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 }