001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.web.project;
043:
044: import java.io.IOException;
045: import java.net.URI;
046: import java.util.Collections;
047: import java.util.logging.Level;
048: import java.util.logging.Logger;
049: import javax.lang.model.element.TypeElement;
050: import javax.lang.model.util.Elements;
051: import org.netbeans.api.java.classpath.ClassPath;
052: import org.netbeans.api.java.project.JavaProjectConstants;
053: import org.netbeans.api.java.project.classpath.ProjectClassPathModifier;
054: import org.netbeans.api.java.source.CancellableTask;
055: import org.netbeans.api.java.source.ClasspathInfo;
056: import org.netbeans.api.java.source.CompilationController;
057: import org.netbeans.api.java.source.JavaSource;
058: import org.netbeans.api.project.FileOwnerQuery;
059: import org.netbeans.api.project.Project;
060: import org.netbeans.api.project.ProjectManager;
061: import org.netbeans.api.project.ant.AntArtifact;
062: import org.netbeans.api.project.ant.AntArtifactQuery;
063: import org.netbeans.modules.j2ee.api.ejbjar.EjbReference;
064: import org.netbeans.modules.j2ee.dd.api.common.VersionNotSupportedException;
065: import org.netbeans.modules.j2ee.dd.api.web.DDProvider;
066: import org.netbeans.modules.j2ee.dd.api.common.EjbLocalRef;
067: import org.netbeans.modules.j2ee.dd.api.common.EjbRef;
068: import org.netbeans.modules.j2ee.dd.api.common.MessageDestinationRef;
069: import org.netbeans.modules.j2ee.dd.api.common.ResourceRef;
070: import org.netbeans.modules.j2ee.dd.api.web.WebApp;
071: import org.netbeans.modules.j2ee.api.ejbjar.EnterpriseReferenceContainer;
072: import org.netbeans.modules.j2ee.api.ejbjar.EnterpriseReferenceSupport;
073: import org.netbeans.modules.j2ee.api.ejbjar.MessageDestinationReference;
074: import org.netbeans.modules.j2ee.api.ejbjar.ResourceReference;
075: import org.netbeans.modules.j2ee.common.queries.api.InjectionTargetQuery;
076: import org.netbeans.modules.j2ee.dd.api.ejb.EjbJarMetadata;
077: import org.netbeans.modules.j2ee.metadata.model.api.MetadataModel;
078: import org.netbeans.modules.j2ee.metadata.model.api.MetadataModelAction;
079: import org.netbeans.modules.web.project.classpath.ClassPathProviderImpl;
080: import org.netbeans.modules.web.spi.webmodule.WebModuleImplementation;
081: import org.netbeans.spi.project.support.ant.AntProjectHelper;
082: import org.netbeans.spi.project.support.ant.EditableProperties;
083: import org.netbeans.spi.project.support.ant.ReferenceHelper;
084: import org.openide.filesystems.FileObject;
085: import org.openide.util.Exceptions;
086:
087: /**
088: *
089: * @author Chris Webster
090: */
091: class WebContainerImpl implements EnterpriseReferenceContainer {
092:
093: private WebProject webProject;
094: private AntProjectHelper antHelper;
095: private static final String SERVICE_LOCATOR_PROPERTY = "project.serviceLocator.class"; //NOI18N
096: private WebApp webApp;
097:
098: public WebContainerImpl(WebProject p, ReferenceHelper helper,
099: AntProjectHelper antHelper) {
100: webProject = p;
101: this .antHelper = antHelper;
102: }
103:
104: public String addEjbLocalReference(EjbReference localRef,
105: String ejbRefName, FileObject referencingFile,
106: String referencingClass) throws IOException {
107: return addReference(localRef, ejbRefName, true,
108: referencingFile, referencingClass);
109: }
110:
111: public String addEjbReference(EjbReference ref, String ejbRefName,
112: FileObject referencingFile, String referencingClass)
113: throws IOException {
114: return addReference(ref, ejbRefName, false, referencingFile,
115: referencingClass);
116: }
117:
118: private String addReference(final EjbReference ejbReference,
119: String ejbRefName, boolean local,
120: FileObject referencingFile, String referencingClass)
121: throws IOException {
122: String refName = null;
123: WebApp webApp = getWebApp();
124:
125: MetadataModel<EjbJarMetadata> ejbReferenceMetadataModel = ejbReference
126: .getEjbModule().getMetadataModel();
127: final String[] ejbName = new String[1];
128: FileObject ejbReferenceEjbClassFO = ejbReferenceMetadataModel
129: .runReadAction(new MetadataModelAction<EjbJarMetadata, FileObject>() {
130: public FileObject run(EjbJarMetadata metadata)
131: throws Exception {
132: ejbName[0] = metadata.findByEjbClass(
133: ejbReference.getEjbClass())
134: .getEjbName();
135: return metadata.findResource(ejbReference
136: .getEjbClass().replace('.', '/')
137: + ".java");
138: }
139: });
140:
141: Project project = FileOwnerQuery
142: .getOwner(ejbReferenceEjbClassFO);
143: AntArtifact[] antArtifacts = AntArtifactQuery
144: .findArtifactsByType(project,
145: JavaProjectConstants.ARTIFACT_TYPE_JAR);
146: boolean hasArtifact = (antArtifacts != null && antArtifacts.length > 0);
147: final AntArtifact moduleJarTarget = hasArtifact ? antArtifacts[0]
148: : null;
149: // only first URI is taken, if more of them are defined, just first one is taken
150: String[] names = new String[] { "" };
151: if (moduleJarTarget != null) {
152: names = moduleJarTarget.getArtifactLocations()[0].getPath()
153: .split("/"); //NOI18N
154: }
155:
156: String jarName = names[names.length - 1] + "#";
157: final String ejbLink = jarName + ejbName[0];
158:
159: if (local) {
160: refName = getUniqueName(getWebApp(), "EjbLocalRef",
161: "EjbRefName", ejbRefName); //NOI18N
162: // EjbLocalRef can come from Ejb project
163: try {
164: EjbLocalRef newRef = (EjbLocalRef) webApp
165: .createBean("EjbLocalRef"); //NOI18N
166: newRef.setEjbLink(ejbLink);
167: newRef.setEjbRefName(refName);
168: newRef.setEjbRefType(ejbReference.getEjbRefType());
169: newRef.setLocal(ejbReference.getLocal());
170: newRef.setLocalHome(ejbReference.getLocalHome());
171: getWebApp().addEjbLocalRef(newRef);
172: } catch (ClassNotFoundException ex) {
173: }
174: } else {
175: refName = getUniqueName(getWebApp(), "EjbRef",
176: "EjbRefName", ejbRefName); //NOI18N
177: // EjbRef can come from Ejb project
178: try {
179: EjbRef newRef = (EjbRef) webApp.createBean("EjbRef"); //NOI18N
180: newRef.setEjbRefName(refName);
181: newRef.setEjbRefType(ejbReference.getEjbRefType());
182: newRef.setHome(ejbReference.getRemoteHome());
183: newRef.setRemote(ejbReference.getRemote());
184: getWebApp().addEjbRef(newRef);
185: } catch (ClassNotFoundException ex) {
186: }
187: }
188:
189: if (moduleJarTarget != null) {
190: try {
191: ProjectClassPathModifier.addAntArtifacts(
192: new AntArtifact[] { moduleJarTarget },
193: new URI[] { moduleJarTarget
194: .getArtifactLocations()[0] },
195: webProject.getSourceRoots().getRoots()[0],
196: ClassPath.COMPILE);
197: } catch (IOException ioe) {
198: Exceptions.printStackTrace(ioe);
199: }
200: }
201:
202: writeDD(referencingFile, referencingClass);
203: return refName;
204: }
205:
206: public String getServiceLocatorName() {
207: EditableProperties ep = antHelper
208: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
209: return ep.getProperty(SERVICE_LOCATOR_PROPERTY);
210: }
211:
212: public void setServiceLocatorName(String serviceLocator)
213: throws IOException {
214: EditableProperties ep = antHelper
215: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
216: ep.setProperty(SERVICE_LOCATOR_PROPERTY, serviceLocator);
217: antHelper.putProperties(
218: AntProjectHelper.PROJECT_PROPERTIES_PATH, ep);
219: ProjectManager.getDefault().saveProject(webProject);
220: }
221:
222: private WebApp getWebApp() throws IOException {
223: if (webApp == null) {
224: WebModuleImplementation jp = (WebModuleImplementation) webProject
225: .getLookup().lookup(WebModuleImplementation.class);
226: FileObject fo = jp.getDeploymentDescriptor();
227: webApp = DDProvider.getDefault().getDDRoot(fo);
228: }
229: return webApp;
230: }
231:
232: private void writeDD(FileObject referencingFile,
233: final String referencingClass) throws IOException {
234: ClassPathProviderImpl cppImpl = webProject
235: .getClassPathProvider();
236: ClasspathInfo classpathInfo = ClasspathInfo.create(cppImpl
237: .getProjectSourcesClassPath(ClassPath.BOOT), cppImpl
238: .getProjectSourcesClassPath(ClassPath.COMPILE), cppImpl
239: .getProjectSourcesClassPath(ClassPath.SOURCE));
240: JavaSource javaSource = JavaSource.create(classpathInfo,
241: Collections.<FileObject> emptyList());
242: WebModuleImplementation jp = (WebModuleImplementation) webProject
243: .getLookup().lookup(WebModuleImplementation.class);
244:
245: // test if referencing class is injection target
246: final boolean[] isInjectionTarget = { false };
247: CancellableTask task = new CancellableTask<CompilationController>() {
248: public void run(CompilationController controller)
249: throws IOException {
250: Elements elements = controller.getElements();
251: TypeElement this Element = elements
252: .getTypeElement(referencingClass);
253: if (this Element != null)
254: isInjectionTarget[0] = InjectionTargetQuery
255: .isInjectionTarget(controller, this Element);
256: }
257:
258: public void cancel() {
259: }
260: };
261: JavaSource refFile = JavaSource.forFileObject(referencingFile);
262: if (refFile != null) {
263: refFile.runUserActionTask(task, true);
264: }
265:
266: boolean shouldWrite = isDescriptorMandatory(jp
267: .getJ2eePlatformVersion())
268: || !isInjectionTarget[0];
269: if (shouldWrite) {
270: FileObject fo = jp.getDeploymentDescriptor();
271: getWebApp().write(fo);
272: }
273: }
274:
275: public String addResourceRef(ResourceReference ref,
276: FileObject referencingFile, String referencingClass)
277: throws IOException {
278: WebApp wa = getWebApp();
279: String resourceRefName = ref.getResRefName();
280: // see if jdbc resource has already been used in the app
281: // this change requested by Ludo
282: if (javax.sql.DataSource.class.getName().equals(
283: ref.getResType())) {
284: ResourceRef[] refs = wa.getResourceRef();
285: for (int i = 0; i < refs.length; i++) {
286: String newDefaultDescription = ref
287: .getDefaultDescription();
288: String existingDefaultDescription = refs[i]
289: .getDefaultDescription();
290: boolean canCompareDefDesc = (newDefaultDescription != null && existingDefaultDescription != null);
291: if (javax.sql.DataSource.class.getName().equals(
292: refs[i].getResType())
293: && (canCompareDefDesc ? newDefaultDescription
294: .equals(existingDefaultDescription)
295: : true)
296: && ref.getResRefName().equals(
297: refs[i].getResRefName())) {
298: return refs[i].getResRefName();
299: }
300: }
301: }
302: if (!isResourceRefUsed(wa, ref)) {
303: resourceRefName = getUniqueName(wa, "ResourceRef",
304: "ResRefName", ref.getResRefName()); //NOI18N
305: ResourceRef resourceRef = createResourceRef();
306: EnterpriseReferenceSupport.populate(ref, resourceRefName,
307: resourceRef);
308: wa.addResourceRef(resourceRef);
309: writeDD(referencingFile, referencingClass);
310: }
311: return resourceRefName;
312: }
313:
314: public String addDestinationRef(MessageDestinationReference ref,
315: FileObject referencingFile, String referencingClass)
316: throws IOException {
317: try {
318: // do not add if there is already an existing destination ref (see #85673)
319: for (MessageDestinationRef mdRef : getWebApp()
320: .getMessageDestinationRef()) {
321: if (mdRef.getMessageDestinationRefName().equals(
322: ref.getMessageDestinationRefName())) {
323: return mdRef.getMessageDestinationRefName();
324: }
325: }
326: } catch (VersionNotSupportedException ex) {
327: Logger.getLogger("global").log(Level.INFO, null, ex);
328: }
329:
330: String refName = getUniqueName(getWebApp(),
331: "MessageDestinationRef", "MessageDestinationRefName", //NOI18N
332: ref.getMessageDestinationRefName());
333:
334: MessageDestinationRef messageDestinationRef = createDestinationRef();
335: EnterpriseReferenceSupport.populate(ref, refName,
336: messageDestinationRef);
337: try {
338: getWebApp().addMessageDestinationRef(messageDestinationRef);
339: writeDD(referencingFile, referencingClass);
340: } catch (VersionNotSupportedException ex) {
341: Logger.getLogger("global").log(Level.INFO, null, ex);
342: }
343: return refName;
344: }
345:
346: public ResourceRef createResourceRef() throws IOException {
347: try {
348: return (ResourceRef) getWebApp().createBean("ResourceRef");
349: } catch (ClassNotFoundException ex) {
350: Exceptions.printStackTrace(ex);
351: }
352: return null;
353: }
354:
355: public MessageDestinationRef createDestinationRef()
356: throws IOException {
357: try {
358: return (org.netbeans.modules.j2ee.dd.api.common.MessageDestinationRef) getWebApp()
359: .createBean("MessageDestinationRef");
360: } catch (ClassNotFoundException ex) {
361: Exceptions.printStackTrace(ex);
362: }
363: return null;
364: }
365:
366: private String getUniqueName(WebApp wa, String beanName,
367: String property, String originalValue) {
368: String proposedValue = originalValue;
369: int index = 1;
370: while (wa.findBeanByName(beanName, property, proposedValue) != null) {
371: proposedValue = originalValue + Integer.toString(index++);
372: }
373: return proposedValue;
374: }
375:
376: private static boolean isDescriptorMandatory(String j2eeVersion) {
377: if ("1.3".equals(j2eeVersion) || "1.4".equals(j2eeVersion)) {
378: return true;
379: }
380: return false;
381: }
382:
383: /**
384: * Searches for given resource reference in given web module.
385: * Two resource references are considered equal if their names and types are equal.
386: *
387: * @param webApp web module where resource reference should be found
388: * @param resRef resource reference to find
389: * @return true id resource reference was found, false otherwise
390: */
391: private static boolean isResourceRefUsed(WebApp webApp,
392: ResourceReference resRef) {
393: String resRefName = resRef.getResRefName();
394: String resRefType = resRef.getResType();
395: for (ResourceRef existingRef : webApp.getResourceRef()) {
396: if (resRefName.equals(existingRef.getResRefName())
397: && resRefType.equals(existingRef.getResType())) {
398: return true;
399: }
400: }
401: return false;
402: }
403:
404: }
|