001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019
020 package org.apache.geronimo.mavenplugins.car;
021
022 import java.io.File;
023 import java.io.StringWriter;
024 import java.util.Collections;
025 import java.util.LinkedHashSet;
026 import java.util.List;
027 import java.util.Properties;
028
029 import javax.xml.namespace.QName;
030
031 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
032 import org.apache.geronimo.deployment.xbeans.ArtifactType;
033 import org.apache.geronimo.deployment.xbeans.EnvironmentType;
034 import org.apache.geronimo.kernel.repository.Artifact;
035 import org.apache.geronimo.kernel.repository.Environment;
036 import org.apache.geronimo.kernel.repository.ImportType;
037 import org.apache.velocity.Template;
038 import org.apache.velocity.VelocityContext;
039 import org.apache.velocity.app.Velocity;
040 import org.apache.velocity.app.VelocityEngine;
041 import org.apache.xmlbeans.XmlCursor;
042 import org.apache.xmlbeans.XmlObject;
043 import org.apache.xmlbeans.XmlOptions;
044
045 //
046 // TODO: Rename to PreparePlanMojo
047 //
048
049 /**
050 * Add module id and dependencies to a plan and process with velocity
051 *
052 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
053 * @goal prepare-plan
054 */
055 public class PlanProcessorMojo
056 extends AbstractCarMojo {
057 private static final String ENVIRONMENT_LOCAL_NAME = "environment";
058
059 private static final QName ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "environment");
060
061 /**
062 * Location of unproccesed plan, normally missing moduleId and dependencies.
063 *
064 * @parameter expression="${basedir}/src/main/plan"
065 * @required
066 */
067 protected File sourceDir = null;
068
069 /**
070 * Directory to put the processed plan in.
071 *
072 * @parameter expression="${project.build.directory}/resources/META-INF"
073 * @required
074 */
075 protected File targetDir = null;
076
077 /**
078 * Name of the unprocessed source and processed target plan file.
079 *
080 * @parameter default-value="plan.xml"
081 * @required
082 */
083 protected String planFileName = null;
084
085 /**
086 * XXX
087 *
088 * @parameter expression="${project.build.directory}/resources/META-INF/plan.xml"
089 * @required
090 */
091 protected File targetFile = null;
092
093 /**
094 * Dependencies explicitly listed in the car-maven-plugin configuration
095 *
096 * @parameter
097 */
098 private List<Dependency> dependencies = Collections.emptyList();
099
100 /**
101 * Configuration of use of maven dependencies. If missing or if value element is false, use the explicit list in the car-maven-plugin configuration.
102 * If present and true, use the maven dependencies in the current pom file of scope null, runtime, or compile. In addition, the version of the maven
103 * dependency can be included or not depending on the includeVersion element.
104 *
105 * @parameter
106 */
107 private UseMavenDependencies useMavenDependencies;
108
109 private VelocityContext createContext() {
110 VelocityContext context = new VelocityContext();
111
112 // Load properties, It inherits them all!
113 Properties props = project.getProperties();
114 for (Object o : props.keySet()) {
115 String key = (String) o;
116 String value = props.getProperty(key);
117
118 log.debug("Setting " + key + "=" + value);
119 context.put(key, value);
120 }
121
122 context.put("pom", project);
123
124 return context;
125 }
126
127 protected void doExecute() throws Exception {
128 //
129 // FIXME: Do not need velocity here, we only need to filter,
130 // could use resources plugin to do this for us, or
131 // implement what resources plugin does here
132 //
133 // Also velocity does not handle property expansion of expressions like
134 // ${foo.bar} to the value of the "foo.bar" property :-(
135 //
136 // Might be better of just hand rolling something...
137 //
138
139 VelocityContext context = createContext();
140
141 VelocityEngine velocity = new VelocityEngine();
142 velocity.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, sourceDir.getAbsolutePath());
143
144 // Don't spit out any logs
145 velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogSystem");
146 velocity.init();
147
148 Template template = velocity.getTemplate(planFileName);
149 StringWriter writer = new StringWriter();
150 template.merge(context, writer);
151
152 String plan = writer.toString();
153
154 XmlObject doc = XmlObject.Factory.parse(plan);
155 XmlCursor xmlCursor = doc.newCursor();
156 LinkedHashSet<org.apache.geronimo.kernel.repository.Dependency> dependencies = toDependencies();
157 Artifact configId = new Artifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), "car");
158
159 try {
160 mergeEnvironment(xmlCursor, configId, dependencies);
161
162 if (targetDir.exists()) {
163 if (!targetDir.isDirectory()) {
164 throw new RuntimeException("TargetDir: " + this.targetDir + " exists and is not a directory");
165 }
166 } else {
167 targetDir.mkdirs();
168 }
169
170 XmlOptions xmlOptions = new XmlOptions();
171 xmlOptions.setSavePrettyPrint();
172 doc.save(targetFile, xmlOptions);
173
174 log.info("Generated: " + targetFile);
175 }
176 finally {
177 xmlCursor.dispose();
178 }
179 }
180
181 void mergeEnvironment(final XmlCursor xmlCursor, final Artifact configId, final LinkedHashSet<org.apache.geronimo.kernel.repository.Dependency> dependencies) {
182 moveToFirstStartElement(xmlCursor);
183
184 boolean atLeastOneChild = xmlCursor.toFirstChild();
185 if (!atLeastOneChild) {
186 // this is an empty element. Move to EndToken such XmlCursor.beginElement inserts an element inside it.
187 xmlCursor.toEndToken();
188 }
189 QName childName = xmlCursor.getName();
190 Environment oldEnvironment;
191
192 if (childName != null && childName.getLocalPart().equals(ENVIRONMENT_LOCAL_NAME)) {
193 convertElement(xmlCursor, ENVIRONMENT_QNAME.getNamespaceURI());
194 XmlObject xmlObject = xmlCursor.getObject();
195 EnvironmentType environmentType = (EnvironmentType) xmlObject.copy().changeType(EnvironmentType.type);
196 oldEnvironment = EnvironmentBuilder.buildEnvironment(environmentType);
197 xmlCursor.removeXml();
198 } else {
199 oldEnvironment = new Environment();
200 }
201
202 Environment newEnvironment = new Environment();
203 newEnvironment.setConfigId(configId);
204 newEnvironment.setDependencies(dependencies);
205
206 EnvironmentBuilder.mergeEnvironments(oldEnvironment, newEnvironment);
207 EnvironmentType environmentType = EnvironmentBuilder.buildEnvironmentType(oldEnvironment);
208
209 xmlCursor.beginElement(ENVIRONMENT_QNAME);
210 XmlCursor element = environmentType.newCursor();
211
212 try {
213 element.copyXmlContents(xmlCursor);
214 }
215 finally {
216 element.dispose();
217 }
218 }
219
220 private void moveToFirstStartElement(XmlCursor xmlCursor) throws AssertionError {
221 xmlCursor.toStartDoc();
222 xmlCursor.toFirstChild();
223 while (!xmlCursor.currentTokenType().isStart()) {
224 if (!xmlCursor.toNextSibling()) {
225 break;
226 }
227 }
228 if (!xmlCursor.currentTokenType().isStart()) {
229 throw new AssertionError("Cannot find first start element");
230 }
231 }
232
233 private void convertElement(final XmlCursor cursor, final String namespace) {
234 cursor.push();
235 XmlCursor end = cursor.newCursor();
236
237 try {
238 end.toCursor(cursor);
239 end.toEndToken();
240
241 while (cursor.hasNextToken() && cursor.isLeftOf(end)) {
242 if (cursor.isStart()) {
243 if (!namespace.equals(cursor.getName().getNamespaceURI())) {
244 cursor.setName(new QName(namespace, cursor.getName().getLocalPart()));
245 }
246 }
247
248 cursor.toNextToken();
249 }
250
251 cursor.pop();
252 }
253 finally {
254 end.dispose();
255 }
256 }
257
258 private LinkedHashSet<org.apache.geronimo.kernel.repository.Dependency> toDependencies() {
259 LinkedHashSet<org.apache.geronimo.kernel.repository.Dependency> dependencies = new LinkedHashSet<org.apache.geronimo.kernel.repository.Dependency>();
260
261 if (useMavenDependencies == null || !useMavenDependencies.isValue()) {
262 for (Dependency dependency : this.dependencies) {
263 org.apache.geronimo.kernel.repository.Dependency gdep = dependency.toDependency();
264 dependencies.add(gdep);
265 }
266 } else {
267 List<org.apache.maven.model.Dependency> includedDependencies = project.getOriginalModel().getDependencies();
268 List<org.apache.maven.model.Dependency> artifacts = project.getDependencies();
269 for (org.apache.maven.model.Dependency dependency : includedDependencies) {
270 dependency = resolveDependency(dependency, artifacts);
271 if (includeDependency(dependency)) {
272 org.apache.geronimo.kernel.repository.Dependency gdep = toGeronimoDependency(dependency, useMavenDependencies.isIncludeVersion());
273 dependencies.add(gdep);
274 }
275 }
276 }
277
278 return dependencies;
279 }
280
281
282 private static org.apache.geronimo.kernel.repository.Dependency toGeronimoDependency(final org.apache.maven.model.Dependency dependency, boolean includeVersion) {
283 Artifact artifact = toGeronimoArtifact(dependency, includeVersion);
284 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.ALL);
285 }
286
287 private static Artifact toGeronimoArtifact(final org.apache.maven.model.Dependency dependency, boolean includeVersion) {
288 String groupId = dependency.getGroupId();
289 String artifactId = dependency.getArtifactId();
290 String version = includeVersion ? dependency.getVersion() : null;
291 String type = dependency.getType();
292
293 return new Artifact(groupId, artifactId, version, type);
294 }
295
296
297 interface Inserter {
298 ArtifactType insert(EnvironmentType environmentType);
299 }
300 }