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 025 import java.util.Iterator; 026 import java.util.LinkedHashSet; 027 import java.util.List; 028 import java.util.Properties; 029 030 import javax.xml.namespace.QName; 031 032 import org.apache.geronimo.deployment.service.EnvironmentBuilder; 033 import org.apache.geronimo.deployment.xbeans.ArtifactType; 034 import org.apache.geronimo.deployment.xbeans.EnvironmentType; 035 import org.apache.geronimo.kernel.repository.Environment; 036 import org.apache.geronimo.kernel.repository.Artifact; 037 import org.apache.geronimo.kernel.repository.ImportType; 038 039 import org.apache.maven.model.Dependency; 040 041 import org.apache.velocity.Template; 042 import org.apache.velocity.VelocityContext; 043 import org.apache.velocity.app.Velocity; 044 import org.apache.velocity.app.VelocityEngine; 045 046 import org.apache.xmlbeans.XmlCursor; 047 import org.apache.xmlbeans.XmlObject; 048 import org.apache.xmlbeans.XmlOptions; 049 050 // 051 // TODO: Rename to PreparePlanMojo 052 // 053 054 /** 055 * Add dependencies to a plan and process with velocity 056 * 057 * @goal prepare-plan 058 * 059 * @version $Rev: 507395 $ $Date: 2007-02-14 00:36:23 -0500 (Wed, 14 Feb 2007) $ 060 */ 061 public class PlanProcessorMojo 062 extends AbstractCarMojo 063 { 064 private static final String ENVIRONMENT_LOCAL_NAME = "environment"; 065 066 private static final QName ENVIRONMENT_QNAME = new QName("http://geronimo.apache.org/xml/ns/deployment-1.2", "environment"); 067 068 /** 069 * @parameter expression="${basedir}/src/plan" 070 * @required 071 */ 072 protected File sourceDir = null; 073 074 /** 075 * @parameter expression="${project.build.directory}/plan" 076 * @required 077 */ 078 protected File targetDir = null; 079 080 /** 081 * @parameter default-value="plan.xml" 082 * @required 083 */ 084 protected String planFileName = null; 085 086 /** 087 * @parameter expression="${project.build.directory}/plan/plan.xml" 088 * @required 089 */ 090 protected File targetFile = null; 091 092 private VelocityContext createContext() { 093 VelocityContext context = new VelocityContext(); 094 095 // Load properties, It inherits them all! 096 Properties props = project.getProperties(); 097 for (Iterator iter = props.keySet().iterator(); iter.hasNext();) { 098 String key = (String) iter.next(); 099 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 // Also velocity does not handle property expansion of expressions like 117 // ${foo.bar} to the value of the "foo.bar" property :-( 118 // 119 // Might be better of just hand rolling something... 120 // 121 122 VelocityContext context = createContext(); 123 124 VelocityEngine velocity = new VelocityEngine(); 125 velocity.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, sourceDir.getAbsolutePath()); 126 127 // Don't spit out any logs 128 velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogSystem"); 129 velocity.init(); 130 131 Template template = velocity.getTemplate(planFileName); 132 StringWriter writer = new StringWriter(); 133 template.merge(context, writer); 134 135 String plan = writer.toString(); 136 137 XmlObject doc = XmlObject.Factory.parse(plan); 138 XmlCursor xmlCursor = doc.newCursor(); 139 LinkedHashSet dependencies = toDependencies(); 140 Artifact configId = new Artifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), "car"); 141 142 try { 143 mergeEnvironment(xmlCursor, configId, dependencies); 144 145 if (targetDir.exists()) { 146 if (!targetDir.isDirectory()) { 147 throw new RuntimeException("TargetDir: " + this.targetDir + " exists and is not a directory"); 148 } 149 } 150 else { 151 targetDir.mkdirs(); 152 } 153 154 XmlOptions xmlOptions = new XmlOptions(); 155 xmlOptions.setSavePrettyPrint(); 156 doc.save(targetFile, xmlOptions); 157 158 log.info("Generated: " + targetFile); 159 } 160 finally { 161 xmlCursor.dispose(); 162 } 163 } 164 165 void mergeEnvironment(final XmlCursor xmlCursor, final Artifact configId, final LinkedHashSet dependencies) { 166 moveToFirstStartElement(xmlCursor); 167 168 boolean atLeastOneChild = xmlCursor.toFirstChild(); 169 if (!atLeastOneChild) { 170 // this is an empty element. Move to EndToken such XmlCursor.beginElement inserts an element inside it. 171 xmlCursor.toEndToken(); 172 } 173 QName childName = xmlCursor.getName(); 174 Environment oldEnvironment; 175 176 if (childName != null && childName.getLocalPart().equals(ENVIRONMENT_LOCAL_NAME)) { 177 convertElement(xmlCursor, ENVIRONMENT_QNAME.getNamespaceURI()); 178 XmlObject xmlObject = xmlCursor.getObject(); 179 EnvironmentType environmentType = (EnvironmentType) xmlObject.copy().changeType(EnvironmentType.type); 180 oldEnvironment = EnvironmentBuilder.buildEnvironment(environmentType); 181 xmlCursor.removeXml(); 182 } else { 183 oldEnvironment = new Environment(); 184 } 185 186 Environment newEnvironment = new Environment(); 187 newEnvironment.setConfigId(configId); 188 newEnvironment.setDependencies(dependencies); 189 190 EnvironmentBuilder.mergeEnvironments(oldEnvironment, newEnvironment); 191 EnvironmentType environmentType = EnvironmentBuilder.buildEnvironmentType(oldEnvironment); 192 193 xmlCursor.beginElement(ENVIRONMENT_QNAME); 194 XmlCursor element = environmentType.newCursor(); 195 196 try { 197 element.copyXmlContents(xmlCursor); 198 } 199 finally { 200 element.dispose(); 201 } 202 } 203 204 private void moveToFirstStartElement(XmlCursor xmlCursor) throws AssertionError { 205 xmlCursor.toStartDoc(); 206 xmlCursor.toFirstChild(); 207 while (!xmlCursor.currentTokenType().isStart()) { 208 if (!xmlCursor.toNextSibling()) { 209 break; 210 } 211 } 212 if (!xmlCursor.currentTokenType().isStart()) { 213 throw new AssertionError("Cannot find first start element"); 214 } 215 } 216 217 private void convertElement(final XmlCursor cursor, final String namespace) { 218 cursor.push(); 219 XmlCursor end = cursor.newCursor(); 220 221 try { 222 end.toCursor(cursor); 223 end.toEndToken(); 224 225 while (cursor.hasNextToken() && cursor.isLeftOf(end)) { 226 if (cursor.isStart()) { 227 if (!namespace.equals(cursor.getName().getNamespaceURI())) { 228 cursor.setName(new QName(namespace, cursor.getName().getLocalPart())); 229 } 230 } 231 232 cursor.toNextToken(); 233 } 234 235 cursor.pop(); 236 } 237 finally { 238 end.dispose(); 239 } 240 } 241 242 private LinkedHashSet toDependencies() { 243 List artifacts = project.getDependencies(); 244 LinkedHashSet dependencies = new LinkedHashSet(); 245 246 Iterator iter = artifacts.iterator(); 247 while (iter.hasNext()) { 248 Dependency dependency = (Dependency) iter.next(); 249 250 // 251 // HACK: Does not appear that we can get the "extention" status of a dependency, 252 // so specifically exclude the ones that we know about, like genesis 253 // 254 255 if (dependency.getGroupId().startsWith("org.apache.geronimo.genesis")) { 256 continue; 257 } 258 259 org.apache.geronimo.kernel.repository.Dependency gdep = toGeronimoDependency(dependency); 260 if (gdep != null) { 261 dependencies.add(gdep); 262 } 263 } 264 265 return dependencies; 266 } 267 268 private static org.apache.geronimo.kernel.repository.Dependency toGeronimoDependency(final Dependency dependency) { 269 Artifact artifact = toGeronimoArtifact(dependency); 270 String type = dependency.getType(); 271 String scope = dependency.getScope(); 272 String groupId = dependency.getGroupId(); 273 274 //!"org.apache.geronimo.specs".equals(groupId) jacc spec needed in plan.xml 275 if ("jar".equalsIgnoreCase(type) && !"junit".equals(groupId) && (scope == null || !scope.equals("provided"))) { 276 if (dependency.getVersion() != null) { 277 artifact = new Artifact( 278 artifact.getGroupId(), 279 artifact.getArtifactId(), 280 dependency.getVersion(), 281 artifact.getType()); 282 } 283 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES); 284 } 285 else if ("car".equalsIgnoreCase(type) && "runtime".equalsIgnoreCase(scope)) { 286 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES); 287 } 288 //doesn't work 289 // else if ("car".equalsIgnoreCase(type) && "provided".equalsIgnoreCase(scope)) { 290 // return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.CLASSES); 291 // } 292 else if ("car".equalsIgnoreCase(type) && (scope == null || "compile".equalsIgnoreCase(scope))) { //parent 293 return new org.apache.geronimo.kernel.repository.Dependency(artifact, ImportType.ALL); 294 } 295 else { 296 // not one of ours 297 return null; 298 } 299 } 300 301 private static Artifact toGeronimoArtifact(final Dependency dependency) { 302 String groupId = dependency.getGroupId(); 303 String artifactId = dependency.getArtifactId(); 304 String version = null; 305 String type = dependency.getType(); 306 307 return new Artifact(groupId, artifactId, version, type); 308 } 309 310 interface Inserter { 311 ArtifactType insert(EnvironmentType environmentType); 312 } 313 }