View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.plugin.car;
21  
22  import java.io.File;
23  import java.io.StringWriter;
24  
25  import java.util.Iterator;
26  import java.util.LinkedHashSet;
27  import java.util.List;
28  import java.util.Properties;
29  
30  import javax.xml.namespace.QName;
31  
32  import org.apache.geronimo.deployment.service.EnvironmentBuilder;
33  import org.apache.geronimo.deployment.xbeans.ArtifactType;
34  import org.apache.geronimo.deployment.xbeans.EnvironmentType;
35  import org.apache.geronimo.kernel.repository.Environment;
36  import org.apache.geronimo.kernel.repository.Artifact;
37  import org.apache.geronimo.kernel.repository.ImportType;
38  
39  import org.apache.maven.model.Dependency;
40  
41  import org.apache.velocity.Template;
42  import org.apache.velocity.VelocityContext;
43  import org.apache.velocity.app.VelocityEngine;
44  
45  import org.apache.xmlbeans.XmlCursor;
46  import org.apache.xmlbeans.XmlObject;
47  import org.apache.xmlbeans.XmlOptions;
48  import org.apache.xmlbeans.XmlCursor.TokenType;
49  
50  //
51  // TODO: Rename to PreparePlanMojo
52  //
53  
54  /**
55   * Add dependencies to a plan and process with velocity
56   * 
57   * @goal prepare-plan
58   *
59   * @version $Rev: 451661 $ $Date: 2006-09-30 13:45:53 -0700 (Sat, 30 Sep 2006) $
60   */
61  public class PlanProcessorMojo
62      extends AbstractCarMojo
63  {
64      private static final String ENVIRONMENT_LOCAL_NAME = "environment";
65  
66      private static final QName ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "environment");
67  
68      /**
69       * @parameter expression="${basedir}/src/plan"
70       * @required
71       */
72      protected File sourceDir = null;
73  
74      /**
75       * @parameter expression="${project.build.directory}/plan"
76       * @required
77       */
78      protected File targetDir = null;
79  
80      /**
81       * @parameter default-value="plan.xml"
82       * @required
83       */
84      protected String planFileName = null;
85  
86      /**
87       * @parameter expression="${project.build.directory}/plan/plan.xml"
88       * @required
89       */
90      protected File targetFile = null;
91  
92      private VelocityContext createContext() {
93          VelocityContext context = new VelocityContext();
94  
95          // Load properties, It inherits them all!
96          Properties props = project.getProperties();
97          for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
98              String key = (String) iter.next();
99              String value = props.getProperty(key);
100 
101             log.debug("Setting " + key + "=" + value);
102             context.put(key, value);
103         }
104 
105         context.put("pom", project);
106 
107         return context;
108     }
109 
110     protected void doExecute() throws Exception {
111         //
112         // FIXME: Do not need velocity here, we only need to filter,
113         //        could use resources plugin to do this for us, or
114         //        implement what resources plugin does here
115         //
116         
117         VelocityContext context = createContext();
118 
119         VelocityEngine velocity = new VelocityEngine();
120         velocity.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, sourceDir.getAbsolutePath());
121         velocity.init();
122 
123         Template template = velocity.getTemplate(planFileName);
124         StringWriter writer = new StringWriter();
125         template.merge(context, writer);
126 
127         String plan = writer.toString();
128 
129         XmlObject doc = XmlObject.Factory.parse(plan);
130         XmlCursor xmlCursor = doc.newCursor();
131         LinkedHashSet dependencies = toDependencies();
132         Artifact configId = new Artifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), "car");
133 
134         try {
135             mergeEnvironment(xmlCursor, configId, dependencies);
136             
137             if (targetDir.exists()) {
138                 if (!targetDir.isDirectory()) {
139                     throw new RuntimeException("TargetDir: " + this.targetDir + " exists and is not a directory");
140                 }
141             }
142             else {
143                 targetDir.mkdirs();
144             }
145 
146             XmlOptions xmlOptions = new XmlOptions();
147             xmlOptions.setSavePrettyPrint();
148             doc.save(targetFile, xmlOptions);
149             
150             log.info("Generated: " + targetFile);
151         }
152         finally {
153             xmlCursor.dispose();
154         }
155     }
156 
157     void mergeEnvironment(final XmlCursor xmlCursor, final Artifact configId, final LinkedHashSet dependencies) {
158         moveToFirstStartElement(xmlCursor);
159 
160         boolean atLeastOneChild = xmlCursor.toFirstChild();
161         if (!atLeastOneChild) {
162             // this is an empty element. Move to EndToken such XmlCursor.beginElement inserts an element inside it.
163             xmlCursor.toEndToken();
164         }
165         QName childName = xmlCursor.getName();
166         Environment oldEnvironment;
167         
168         if (childName != null && childName.getLocalPart().equals(ENVIRONMENT_LOCAL_NAME)) {
169             convertElement(xmlCursor, ENVIRONMENT_QNAME.getNamespaceURI());
170             XmlObject xmlObject = xmlCursor.getObject();
171             EnvironmentType environmentType = (EnvironmentType) xmlObject.copy().changeType(EnvironmentType.type);
172             oldEnvironment = EnvironmentBuilder.buildEnvironment(environmentType);
173             xmlCursor.removeXml();
174         } else {
175             oldEnvironment = new Environment();
176         }
177 
178         Environment newEnvironment = new Environment();
179         newEnvironment.setConfigId(configId);
180         newEnvironment.setDependencies(dependencies);
181 
182         EnvironmentBuilder.mergeEnvironments(oldEnvironment, newEnvironment);
183         EnvironmentType environmentType = EnvironmentBuilder.buildEnvironmentType(oldEnvironment);
184 
185         xmlCursor.beginElement(ENVIRONMENT_QNAME);
186         XmlCursor element = environmentType.newCursor();
187 
188         try {
189             element.copyXmlContents(xmlCursor);
190         }
191         finally {
192             element.dispose();
193         }
194     }
195 
196     private void moveToFirstStartElement(XmlCursor xmlCursor) throws AssertionError {
197         xmlCursor.toStartDoc();
198         xmlCursor.toFirstChild();
199         while (!xmlCursor.currentTokenType().isStart()) {            
200             if (!xmlCursor.toNextSibling()) {
201                 break;
202             }
203         } 
204         if (!xmlCursor.currentTokenType().isStart()) {
205             throw new AssertionError("Cannot find first start element");
206         }
207     }
208 
209     private void convertElement(final XmlCursor cursor, final String namespace) {
210         cursor.push();
211         XmlCursor end = cursor.newCursor();
212 
213         try {
214             end.toCursor(cursor);
215             end.toEndToken();
216 
217             while (cursor.hasNextToken() && cursor.isLeftOf(end)) {
218                 if (cursor.isStart()) {
219                     if (!namespace.equals(cursor.getName().getNamespaceURI())) {
220                         cursor.setName(new QName(namespace, cursor.getName().getLocalPart()));
221                     }
222                 }
223 
224                 cursor.toNextToken();
225             }
226 
227             cursor.pop();
228         }
229         finally {
230             end.dispose();
231         }
232     }
233 
234     private LinkedHashSet toDependencies() {
235         List artifacts = project.getDependencies();
236         LinkedHashSet dependencies = new LinkedHashSet();
237 
238         Iterator iter = artifacts.iterator();
239         while (iter.hasNext()) {
240             Dependency dependency = (Dependency) iter.next();
241 
242             //
243             // HACK: Does not appear that we can get the "extention" status of a dependency,
244             //       so specifically exclude the ones that we know about, like genesis
245             //
246 
247             if (dependency.getGroupId().startsWith("org.apache.geronimo.genesis")) {
248                 continue;
249             }
250 
251             org.apache.geronimo.kernel.repository.Dependency gdep = toGeronimoDependency(dependency);
252             if (gdep != null) {
253                 dependencies.add(gdep);
254             }
255         }
256 
257         return dependencies;
258     }
259 
260     private static org.apache.geronimo.kernel.repository.Dependency toGeronimoDependency(final Dependency dependency) {
261         Artifact artifact = toGeronimoArtifact(dependency);
262         String type = dependency.getType();
263         String scope = dependency.getScope();
264         String groupId = dependency.getGroupId();
265 
266         //!"org.apache.geronimo.specs".equals(groupId) jacc spec needed in plan.xml
267         if ("jar".equalsIgnoreCase(type) && !"junit".equals(groupId) && (scope == null || !scope.equals("provided"))) {
268             if (dependency.getVersion() != null) {
269                 artifact = new Artifact(
270                     artifact.getGroupId(),
271                     artifact.getArtifactId(),
272                     dependency.getVersion(),
273                     artifact.getType());
274             }
275             return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES);
276         }
277         else if ("car".equalsIgnoreCase(type) && ("runtime").equalsIgnoreCase(scope)) {
278             return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.SERVICES);
279         }
280         else if ("car".equalsIgnoreCase(type) && ("compile".equalsIgnoreCase(scope))) {
281             return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES);
282         }
283         else if ("car".equalsIgnoreCase(type) && (scope == null)) { //parent
284             return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.ALL);
285         }
286         else {
287             // not one of ours
288             return null;
289         }
290     }
291 
292     private static Artifact toGeronimoArtifact(final Dependency dependency) {
293         String groupId = dependency.getGroupId();
294         String artifactId = dependency.getArtifactId();
295         String version = null;
296         String type = dependency.getType();
297 
298         return new Artifact(groupId, artifactId, version, type);
299     }
300 
301     interface Inserter {
302         ArtifactType insert(EnvironmentType environmentType);
303     }
304 }