001    /**
002     *
003     * Copyright 2005 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.plugin.car;
019    
020    import java.io.File;
021    import java.io.StringWriter;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.LinkedHashSet;
025    import java.util.List;
026    import java.util.Map;
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.Environment;
035    import org.apache.geronimo.kernel.repository.Artifact;
036    import org.apache.geronimo.kernel.repository.ImportType;
037    
038    import org.apache.maven.model.Dependency;
039    
040    import org.apache.velocity.Template;
041    import org.apache.velocity.VelocityContext;
042    import org.apache.velocity.app.VelocityEngine;
043    
044    import org.apache.xmlbeans.XmlCursor;
045    import org.apache.xmlbeans.XmlObject;
046    import org.apache.xmlbeans.XmlOptions;
047    
048    //
049    // TODO: Rename to PreparePlanMojo
050    //
051    
052    /**
053     * Add dependencies to a plan and process with velocity
054     * 
055     * @goal prepare-plan
056     *
057     * @version $Rev: 434144 $ $Date: 2006-08-23 21:56:43 +0200 (mer., 23 août 2006) $
058     */
059    public class PlanProcessorMojo
060        extends AbstractCarMojo
061    {
062        private static final String ENVIRONMENT_LOCAL_NAME = "environment";
063    
064        private static final QName ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.1", ENVIRONMENT_LOCAL_NAME);
065    
066        /**
067         * @parameter expression="${basedir}/src/plan"
068         * @required
069         */
070        private File sourceDir;
071    
072        /**
073         * @parameter expression="${project.build.directory}/plan"
074         * @required
075         */
076        private File targetDir;
077    
078        /**
079         * @parameter default-value="plan.xml"
080         * @required
081         */
082        private String planFileName;
083    
084        /**
085         * @parameter expression="${project.build.directory}/plan/plan.xml"
086         * @required
087         */
088        private File targetFile;
089        
090        /**
091         * @parameter expression="1.2"
092         * @required     
093         */    
094        private String geronimoVersion;
095        
096        private VelocityContext createContext() {
097            VelocityContext context = new VelocityContext();
098    
099            // Load properties, It inherits them all!
100            Properties props = project.getProperties();
101            for (Iterator iter = props.keySet().iterator(); iter.hasNext();) {
102                String key = (String) iter.next();
103                String value = props.getProperty(key);
104    
105                log.debug("Setting " + key + "=" + value);
106                context.put(key, value);
107            }
108    
109            context.put("pom", project);
110    
111            return context;
112        }
113    
114        protected void doExecute() throws Exception {
115            //
116            // FIXME: Do not need velocity here, we only need to filter,
117            //        could use resources plugin to do this for us, or
118            //        implement what resources plugin does here
119            //
120            
121            VelocityContext context = createContext();
122    
123            VelocityEngine velocity = new VelocityEngine();
124            velocity.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, sourceDir.getAbsolutePath());
125            velocity.init();
126    
127            Template template = velocity.getTemplate(planFileName);
128            StringWriter writer = new StringWriter();
129            template.merge(context, writer);
130    
131            String plan = writer.toString();
132    
133            XmlObject doc = XmlObject.Factory.parse(plan);
134            XmlCursor xmlCursor = doc.newCursor();
135            LinkedHashSet dependencies = toDependencies();
136            Artifact configId = new Artifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), "car");
137    
138            try {
139                mergeEnvironment(xmlCursor, configId, dependencies);
140                
141                if (targetDir.exists()) {
142                    if (!targetDir.isDirectory()) {
143                        throw new RuntimeException("TargetDir: " + this.targetDir + " exists and is not a directory");
144                    }
145                }
146                else {
147                    targetDir.mkdirs();
148                }
149    
150                XmlOptions xmlOptions = new XmlOptions();
151                xmlOptions.setSavePrettyPrint();
152                doc.save(targetFile, xmlOptions);
153                
154                log.info("Generated: " + targetFile);
155            }
156            finally {
157                xmlCursor.dispose();
158            }
159        }
160    
161        void mergeEnvironment(final XmlCursor xmlCursor, final Artifact configId, final LinkedHashSet dependencies) {
162            xmlCursor.toFirstContentToken();
163            xmlCursor.toFirstChild();
164            QName childName = xmlCursor.getName();
165            Environment oldEnvironment;
166            
167            if (childName != null && childName.getLocalPart().equals(ENVIRONMENT_LOCAL_NAME)) {
168                convertElement(xmlCursor, ENVIRONMENT_QNAME.getNamespaceURI());
169                XmlObject xmlObject = xmlCursor.getObject();
170                EnvironmentType environmentType = (EnvironmentType) xmlObject.copy().changeType(EnvironmentType.type);
171                oldEnvironment = EnvironmentBuilder.buildEnvironment(environmentType);
172                xmlCursor.removeXml();
173            }
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 convertElement(final XmlCursor cursor, final String namespace) {
197            cursor.push();
198            XmlCursor end = cursor.newCursor();
199    
200            try {
201                end.toCursor(cursor);
202                end.toEndToken();
203    
204                while (cursor.hasNextToken() && cursor.isLeftOf(end)) {
205                    if (cursor.isStart()) {
206                        if (!namespace.equals(cursor.getName().getNamespaceURI())) {
207                            cursor.setName(new QName(namespace, cursor.getName().getLocalPart()));
208                        }
209                    }
210    
211                    cursor.toNextToken();
212                }
213    
214                cursor.pop();
215            }
216            finally {
217                end.dispose();
218            }
219        }
220    
221        private LinkedHashSet toDependencies() {
222            List artifacts = project.getDependencies();
223            LinkedHashSet dependencies = new LinkedHashSet();
224    
225            Iterator iter = artifacts.iterator();
226            while (iter.hasNext()) {
227                Dependency dependency = (Dependency) iter.next();
228    
229                //
230                // HACK: Does not appear that we can get the "extention" status of a dependency,
231                //       so specifically exclude the ones that we know about, like genesis
232                //
233    
234                if (dependency.getGroupId().startsWith("org.apache.geronimo.genesis")) {
235                    continue;
236                }
237    
238                org.apache.geronimo.kernel.repository.Dependency gdep = toGeronimoDependency(dependency);
239                if (gdep != null) {
240                    dependencies.add(gdep);
241                }
242            }
243    
244            return dependencies;
245        }
246    
247        private static org.apache.geronimo.kernel.repository.Dependency toGeronimoDependency(final Dependency dependency) {
248            Artifact artifact = toGeronimoArtifact(dependency);
249            String type = dependency.getType();
250            String scope = dependency.getScope();
251            String groupId = dependency.getGroupId();
252    
253            //!"org.apache.geronimo.specs".equals(groupId) jacc spec needed in plan.xml
254            if ("jar".equalsIgnoreCase(type) && !"junit".equals(groupId) && (scope == null || !scope.equals("provided"))) {
255                if (dependency.getVersion() != null) {
256                    artifact = new Artifact(
257                        artifact.getGroupId(),
258                        artifact.getArtifactId(),
259                        dependency.getVersion(),
260                        artifact.getType());
261                }
262                return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES);
263            }
264            else if ("car".equalsIgnoreCase(type) && ("runtime").equalsIgnoreCase(scope)) {
265                return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.SERVICES);
266            }
267            else if ("car".equalsIgnoreCase(type) && ("compile".equalsIgnoreCase(scope))) {
268                return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES);
269            }
270            else if ("car".equalsIgnoreCase(type) && (scope == null)) { //parent
271                return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.ALL);
272            }
273            else {
274                // not one of ours
275                return null;
276            }
277        }
278    
279        private static Artifact toGeronimoArtifact(final Dependency dependency) {
280            String groupId = dependency.getGroupId();
281            String artifactId = dependency.getArtifactId();
282            String version = null;
283            String type = dependency.getType();
284    
285            return new Artifact(groupId, artifactId, version, type);
286        }
287    
288        interface Inserter {
289            ArtifactType insert(EnvironmentType environmentType);
290        }
291    }