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-2007 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: * EjbLibReferenceHelper.java
043: *
044: * Created on March 6, 2005, 9:35 PM
045: */
046:
047: package org.netbeans.modules.visualweb.ejb.nodes;
048:
049: import java.io.File;
050: import java.io.IOException;
051: import java.net.URL;
052: import java.util.ArrayList;
053: import java.util.Collection;
054: import java.util.Iterator;
055: import java.util.List;
056: import java.util.jar.JarFile;
057: import java.util.jar.Manifest;
058: import java.util.logging.Level;
059:
060: import java.util.zip.ZipEntry;
061: import org.netbeans.api.java.classpath.ClassPath;
062: import org.netbeans.api.project.FileOwnerQuery;
063: import org.netbeans.api.project.Project;
064: import org.netbeans.modules.j2ee.deployment.common.api.ConfigurationException;
065: import org.netbeans.modules.j2ee.deployment.devmodules.spi.J2eeModuleProvider;
066: import org.netbeans.modules.j2ee.sun.dd.api.DDProvider;
067: import org.netbeans.modules.j2ee.sun.dd.api.RootInterface;
068: import org.netbeans.modules.j2ee.sun.dd.api.common.EjbRef;
069: import org.netbeans.modules.j2ee.sun.dd.api.web.SunWebApp;
070: import org.netbeans.modules.visualweb.api.designerapi.DesignerServiceHack;
071: import org.netbeans.modules.visualweb.api.j2ee.common.RequestedEjbResource;
072: import org.netbeans.modules.visualweb.ejb.EjbDataSourceManager;
073: import org.netbeans.modules.visualweb.ejb.EjbRefMaintainer;
074: import org.netbeans.modules.visualweb.ejb.datamodel.EjbDataModel;
075: import org.netbeans.modules.visualweb.ejb.datamodel.EjbGroup;
076: import org.netbeans.modules.visualweb.ejb.datamodel.EjbInfo;
077: import org.netbeans.modules.visualweb.ejb.util.Util;
078: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectConstants;
079: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
080: import org.openide.ErrorManager;
081: import org.openide.filesystems.FileObject;
082: import org.openide.filesystems.FileSystem;
083: import org.openide.filesystems.FileUtil;
084: import org.openide.util.Lookup;
085:
086: /**
087: *
088: * @author cao
089: */
090: public class EjbLibReferenceHelper {
091:
092: private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; // NOI18N
093: private static final String TIMESTAMP_ATTR = "Generated-time-in-millies"; // NOI18N
094:
095: /**
096: * Class to encapsulate a hack to implement a feature that is not yet implemented by the Sun
097: * AppServer plugin. Remove this hack once it is implemented. Also, remove dependency on the
098: * module. 2007-06-20
099: *
100: * @author Edwin Goei
101: */
102: private static class SunAppServerHack {
103:
104: private FileObject sunWebXml;
105:
106: private SunWebApp sunWebApp;
107:
108: private SunAppServerHack(FileObject sunWebXml)
109: throws IOException {
110: this .sunWebXml = sunWebXml;
111:
112: RootInterface sunDDRoot = DDProvider.getDefault()
113: .getDDRoot(sunWebXml);
114: if (sunDDRoot instanceof SunWebApp) {
115: sunWebApp = (SunWebApp) sunDDRoot;
116: } else {
117: throw new IllegalStateException(
118: "Cannot process sun-web.xml");
119: }
120: }
121:
122: /**
123: * Factory method to create a DD handler for a project.
124: *
125: * @param project
126: * @return
127: * @throws IOException
128: */
129: public static SunAppServerHack getInstance(Project project)
130: throws IOException {
131: FileObject sunWebXml = getSunWebXml(project);
132: if (sunWebXml == null) {
133: return null;
134: } else {
135: return new SunAppServerHack(sunWebXml);
136: }
137: }
138:
139: private static FileObject getSunWebXml(Project project) {
140: Lookup lookup = project.getLookup();
141: J2eeModuleProvider provider = (J2eeModuleProvider) lookup
142: .lookup(J2eeModuleProvider.class);
143: FileObject[] configFiles = provider.getConfigurationFiles();
144: for (FileObject fo : configFiles) {
145: if (fo.getNameExt().equals("sun-web.xml")) {
146: return fo;
147: }
148: }
149: return null;
150: }
151:
152: public SunWebApp getSunWebApp() {
153: return sunWebApp;
154: }
155:
156: public void finish() throws IOException {
157: sunWebApp.write(sunWebXml);
158: }
159: }
160:
161: private static final String EJB_REFS_XML = "ejb-refs.xml";
162:
163: /**
164: * Return the Project that is currently active according to the Designer.
165: *
166: * @return currently active project or null, if none.
167: */
168: public static Project getActiveProject() {
169: FileObject fileObject = DesignerServiceHack.getDefault()
170: .getCurrentFile();
171: if (fileObject == null) {
172: return null;
173: }
174: return FileOwnerQuery.getOwner(fileObject);
175: }
176:
177: /**
178: * Refreshed the EjbGroup jars in all the currently open objects
179: *
180: * @throws IOException
181: */
182: public static void updateEjbGroupForProjects(Project[] projects,
183: EjbGroup ejbGroup) throws IOException,
184: ConfigurationException {
185: // Update the jars in each open visual web project
186: for (int i = 0; i < projects.length; i++) {
187: Project project = projects[i];
188: if (JsfProjectUtils.isJsfProject(project)) {
189: updateEjbGroupForProject(ejbGroup, project);
190: }
191: }
192: }
193:
194: /**
195: * Sync the the EJB related archive refs in the given projects
196: */
197: public static void syncArchiveRefs(Project[] projects) {
198:
199: for (int i = 0; i < projects.length; i++) {
200: if (!JsfProjectUtils.isJsfProject(projects[i])) {
201: // Skip this project unless this is a JSF Project
202: // 107000 unwanted "lib" folder created for every opened/created project
203: continue;
204: }
205:
206: try {
207: FileObject ejbSubDir = projects[i]
208: .getProjectDirectory()
209: .getFileObject(
210: JsfProjectConstants.PATH_LIBRARIES
211: + '/'
212: + EjbDataSourceManager.EJB_DATA_SUB_DIR);
213: if (ejbSubDir == null)
214: // NO ejb in this project. Move on
215: continue;
216:
217: // Get the ejb groups dropped in this project
218: String ejbSubDirPath = FileUtil.toFile(ejbSubDir)
219: .getAbsolutePath();
220: EjbRefMaintainer refMaintainer = new EjbRefMaintainer(
221: ejbSubDirPath + File.separator + EJB_REFS_XML);
222: Collection ejbGroups = refMaintainer
223: .getRefferedEjbGroups();
224:
225: if (ejbGroups == null)
226: return;
227:
228: // Now lets see whehther the ejb groups are still in the data
229: // model
230: for (Iterator iter = ejbGroups.iterator(); iter != null
231: && iter.hasNext();) {
232: EjbGroup ejbGrp = (EjbGroup) iter.next();
233: EjbGroup ejbGrpInModel = EjbDataModel
234: .getInstance()
235: .findEjbGroupForClientWrapperJar(
236: Util.getFileName(ejbGrp
237: .getClientWrapperBeanJar()));
238:
239: if (ejbGrpInModel == null)
240: // This group is gone from the data model
241: continue;
242: else
243: updateEjbGroupForProjects(
244: new Project[] { projects[i] },
245: ejbGrpInModel);
246: }
247: } catch (java.io.IOException ie) {
248: ErrorManager.getDefault().notify(ie);
249: ie.printStackTrace();
250: continue;
251: } catch (ConfigurationException ce) {
252: ErrorManager.getDefault().notify(ce);
253: ce.printStackTrace();
254: continue;
255: }
256: }
257: }
258:
259: private static FileObject getProjectEjbDataDir(Project project)
260: throws IOException {
261: // Obtain the path to the project's library directory
262: FileObject projectLibDir = JsfProjectUtils
263: .getProjectLibraryDirectory(project);
264:
265: FileObject ejbSubDir = projectLibDir
266: .getFileObject(EjbDataSourceManager.EJB_DATA_SUB_DIR);
267: if (ejbSubDir == null)
268: ejbSubDir = projectLibDir
269: .createFolder(EjbDataSourceManager.EJB_DATA_SUB_DIR);
270: return ejbSubDir;
271: }
272:
273: private static void addRefsToProject(Project project, String role,
274: List<FileObject> projectJars, String... jars)
275: throws IOException {
276: ArrayList<URL> copiedArchiveJars = new ArrayList<URL>(
277: jars.length);
278: for (String jar : jars) {
279: FileObject jarFO = findFileObject(projectJars, jar);
280: if (jarFO != null) {
281: copiedArchiveJars.add(new URL(jarFO.getURL()
282: .toExternalForm()
283: + "/"));
284: }
285: }
286:
287: URL[] jarArray = copiedArchiveJars
288: .toArray(new URL[copiedArchiveJars.size()]);
289:
290: // Add archive references to the project
291: if (role != null) {
292: JsfProjectUtils.addRootReferences(project, jarArray, role);
293: } else {
294: JsfProjectUtils.addRootReferences(project, jarArray);
295: }
296: }
297:
298: private static FileObject findFileObject(List<FileObject> files,
299: String filePath) {
300: String fileName = new File(filePath).getName();
301: for (FileObject fo : files) {
302: if (fo.getNameExt().equals(fileName)) {
303: return fo;
304: }
305: }
306:
307: return null;
308: }
309:
310: private static ArrayList<FileObject> addUpdateJarsForProject(
311: Project project, final ArrayList<String> jars)
312: throws IOException {
313: final FileObject ejbSubDir = getProjectEjbDataDir(project);
314: final ArrayList<FileObject> copiedJars = new ArrayList<FileObject>(
315: jars.size());
316:
317: ejbSubDir.getFileSystem().runAtomicAction(
318: new FileSystem.AtomicAction() {
319:
320: public void run() throws IOException {
321: for (String jarFile : jars) {
322: FileObject jarFileObject = FileUtil
323: .toFileObject(FileUtil
324: .normalizeFile(new File(
325: jarFile)));
326: if (jarFileObject != null) {
327: String jarFileName = jarFileObject
328: .getName();
329: String jarFileExt = jarFileObject
330: .getExt();
331: FileObject projectJar = ejbSubDir
332: .getFileObject(jarFileName,
333: jarFileExt);
334:
335: if (projectJar == null) {
336: FileObject copiedJar = FileUtil
337: .copyFile(jarFileObject,
338: ejbSubDir,
339: jarFileName);
340: copiedJars.add(copiedJar);
341: } else if (!isJarUpToDate(projectJar,
342: jarFileObject)) {
343: projectJar.delete();
344:
345: FileObject copiedJar = FileUtil
346: .copyFile(jarFileObject,
347: ejbSubDir,
348: jarFileName);
349: copiedJars.add(copiedJar);
350: } else {
351: copiedJars.add(projectJar);
352: }
353: }
354: }
355: }
356: });
357:
358: return copiedJars;
359: }
360:
361: private static boolean isJarUpToDate(FileObject projectJarFO,
362: FileObject repositoryJarFO) {
363: if (projectJarFO.getSize() != repositoryJarFO.getSize()) {
364: return false;
365: }
366:
367: JarFile projectJar = null;
368: JarFile repositoryJar = null;
369:
370: try {
371: File projectFile = FileUtil.toFile(projectJarFO);
372: File repositoryFile = FileUtil.toFile(repositoryJarFO);
373:
374: projectJar = new JarFile(projectFile, false);
375: repositoryJar = new JarFile(repositoryFile, false);
376:
377: ZipEntry projectManifestEntry = projectJar
378: .getEntry(MANIFEST_PATH);
379: ZipEntry repositoryManifestEntry = repositoryJar
380: .getEntry(MANIFEST_PATH);
381:
382: if (projectManifestEntry == null
383: && repositoryManifestEntry == null) {
384: return true;
385: } else if (projectManifestEntry == null
386: || repositoryManifestEntry == null) {
387: return false;
388: }
389:
390: Manifest projectManifest = new Manifest(projectJar
391: .getInputStream(projectManifestEntry));
392: Manifest repositoryManifest = new Manifest(repositoryJar
393: .getInputStream(repositoryManifestEntry));
394:
395: String projectTS = (String) projectManifest
396: .getMainAttributes().getValue(TIMESTAMP_ATTR);
397: String repositoryTS = (String) repositoryManifest
398: .getMainAttributes().getValue(TIMESTAMP_ATTR);
399:
400: if (projectTS == null && repositoryTS == null) {
401: return true;
402: }
403:
404: return projectTS != null && repositoryTS != null
405: && projectTS.equals(repositoryTS);
406: } catch (Exception ex) {
407: // if there is no manifest, the file sizes and names are at least the same, so
408: // assume that the file is unchanged
409: return true;
410: } finally {
411: if (projectJar != null) {
412: try {
413: projectJar.close();
414: } catch (IOException ex) {
415: Util.getLogger().log(
416: Level.WARNING,
417: "Unable to close jar file: "
418: + projectJar.getName(), ex);
419: }
420: }
421:
422: if (repositoryJar != null) {
423: try {
424: repositoryJar.close();
425: } catch (IOException ex) {
426: Util.getLogger().log(
427: Level.WARNING,
428: "Unable to close jar file: "
429: + repositoryJar.getName(), ex);
430: }
431: }
432: }
433:
434: }
435:
436: /**
437: * Adds the reference information of the ejbs in the give ejb group to the project.
438: *
439: * @param project
440: * The project to be added to
441: * @param ejbGroup
442: */
443: public static void addToEjbRefXmlToProject(Project project,
444: EjbGroup ejbGroup) {
445: try {
446: FileObject projectLibDir = JsfProjectUtils
447: .getProjectLibraryDirectory(project);
448: FileObject ejbSubDir = projectLibDir
449: .getFileObject(EjbDataSourceManager.EJB_DATA_SUB_DIR);
450: if (ejbSubDir == null)
451: ejbSubDir = projectLibDir
452: .createFolder(EjbDataSourceManager.EJB_DATA_SUB_DIR);
453:
454: String ejbSubDirPath = FileUtil.toFile(ejbSubDir)
455: .getAbsolutePath();
456:
457: // Before writing the the ejb group to the xml,
458: // change the client jars and wrapper bean jar locations to the
459: // project/lib/ejb-sources
460: EjbGroup ejbGrpCopy = (EjbGroup) ejbGroup.clone();
461:
462: ArrayList<String> newClientPaths = new ArrayList<String>();
463: for (Iterator iter = ejbGroup.getClientJarFiles()
464: .iterator(); iter.hasNext();) {
465: String jarPath = (String) iter.next();
466: newClientPaths.add(ejbSubDirPath + "/"
467: + (new File(jarPath)).getName());
468: }
469: ejbGrpCopy.setClientJarFiles(newClientPaths);
470:
471: ejbGrpCopy.setClientWrapperBeanJar(ejbSubDirPath
472: + "/"
473: + (new File(ejbGroup.getClientWrapperBeanJar()))
474: .getName());
475: ejbGrpCopy
476: .setDesignInfoJar(ejbSubDirPath
477: + "/"
478: + (new File(ejbGroup.getDesignInfoJar()))
479: .getName());
480:
481: EjbRefMaintainer refMaintainer = new EjbRefMaintainer(
482: ejbSubDirPath + File.separator + EJB_REFS_XML);
483: refMaintainer.addToEjbRefXml(ejbGrpCopy);
484: } catch (java.io.IOException ie) {
485: Util.getLogger().log(Level.WARNING,
486: "Failed to save ejb refs", ie);
487: }
488: }
489:
490: /**
491: * Add all session beans in EjbGroup grp to project. This method is idempotent.
492: *
493: * @param project
494: * @param grp
495: * @throws IOException
496: * @throws ConfigurationException
497: */
498: private static void addToDeploymentDescriptors(Project project,
499: EjbGroup grp) throws IOException, ConfigurationException {
500: SunAppServerHack sunAppServerHack = SunAppServerHack
501: .getInstance(project);
502:
503: // Add all the EJBs in this group as EJB resources to the project
504: // Note: we purposely decided to add all the EJBs vs just the used
505: // ones
506: for (Iterator ejbIter = grp.getSessionBeans().iterator(); ejbIter
507: .hasNext();) {
508: EjbInfo ejbInfo = (EjbInfo) ejbIter.next();
509:
510: String refName = ejbInfo.getWebEjbRef();
511: String refType = ejbInfo.getBeanTypeName();
512: String home = ejbInfo.getHomeInterfaceName();
513:
514: // The global JNDI name for this EJB
515: // - corbaname:iiop:<hostname>:<port>#<jndiname> for Sun
516: // Application server, weblogic
517: // -
518: // corbaname:iiop:<hostname>:<port>/NameServiceServerRoot#<jndiname>
519: // for websphere 5.1
520: String jndiName = "corbaname:iiop:" + grp.getServerHost()
521: + ":" + grp.getIIOPPort() + "#"
522: + ejbInfo.getJNDIName();
523: if (grp.isWebsphereAppServer())
524: jndiName = "corbaname:iiop:" + grp.getServerHost()
525: + ":" + grp.getIIOPPort()
526: + "/NameServiceServerRoot#"
527: + ejbInfo.getJNDIName();
528:
529: String remote = ejbInfo.getCompInterfaceName();
530:
531: RequestedEjbResource resource = new RequestedEjbResource(
532: refName, jndiName, refType, home, remote);
533: JsfProjectUtils.setEjbReference(project, resource);
534:
535: if (sunAppServerHack != null) {
536: /*
537: * TODO This hack should be removed once the app server plugin implements the
538: * bindEjbReference API.
539: */
540: SunWebApp sunWebApp = sunAppServerHack.getSunWebApp();
541: EjbRef ref = findEjbRefByName(sunWebApp, refName);
542: if (ref != null) {
543: ref.setJndiName(jndiName);
544: } else {
545: ref = sunWebApp.newEjbRef();
546: ref.setEjbRefName(refName);
547: ref.setJndiName(jndiName);
548: sunWebApp.addEjbRef(ref);
549: }
550: } else {
551: // Bind the EJB Reference
552: J2eeModuleProvider j2eeModuleProvider = project
553: .getLookup().lookup(J2eeModuleProvider.class);
554: j2eeModuleProvider.getConfigSupport().bindEjbReference(
555: refName, jndiName);
556: }
557: }
558:
559: if (sunAppServerHack != null) {
560: sunAppServerHack.finish();
561: }
562: }
563:
564: /**
565: * Adds the EjbGroup to the currently active project. This method is idempotent.
566: *
567: * @throws IOException
568: * @throws ConfigurationException
569: */
570: public static void addEjbGroupToActiveProject(EjbGroup ejbGroup)
571: throws IOException, ConfigurationException {
572: Project project = getActiveProject();
573:
574: addEjbGroupJarsToProject(ejbGroup, project);
575:
576: // Add/update this ejb group to the ejb ref xml in the project
577: addToEjbRefXmlToProject(project, ejbGroup);
578:
579: // Add an ejb-ref to the standard and vendor webapp DD
580: addToDeploymentDescriptors(project, ejbGroup);
581: }
582:
583: private static void addEjbGroupJarsToProject(EjbGroup ejbGroup,
584: Project project) throws IOException {
585: // Add EJB client wrapper archive to the project
586: String wrapperJar = ejbGroup.getClientWrapperBeanJar();
587: String dtJar = ejbGroup.getDesignInfoJar();
588: ArrayList<String> clientJarFiles = ejbGroup.getClientJarFiles();
589:
590: ArrayList<String> allJars = new ArrayList<String>(
591: clientJarFiles.size() + 2);
592: allJars.add(wrapperJar);
593: allJars.add(dtJar);
594: allJars.addAll(clientJarFiles);
595:
596: // copy all jars to the project
597: List<FileObject> projectJars = addUpdateJarsForProject(project,
598: allJars);
599:
600: // add EJB client wrapper archive to the project
601: addRefsToProject(project, null, projectJars, wrapperJar);
602:
603: // Add EJB design-time archive to the project
604: addRefsToProject(project, ClassPath.COMPILE, projectJars, dtJar);
605:
606: // Add the client stub jars to the project
607: if (clientJarFiles.size() > 0) {
608: addRefsToProject(project, null, projectJars, clientJarFiles
609: .toArray(new String[clientJarFiles.size()]));
610: }
611: }
612:
613: private static void updateEjbGroupForProject(EjbGroup ejbGroup,
614: Project project) throws IOException, ConfigurationException {
615: // Update EJB client wrapper archive
616: String wrapperJar = ejbGroup.getClientWrapperBeanJar();
617: String dtJar = ejbGroup.getDesignInfoJar();
618: ArrayList<String> clientJarFiles = ejbGroup.getClientJarFiles();
619:
620: ArrayList<String> allJars = new ArrayList<String>(
621: clientJarFiles.size() + 2);
622: allJars.add(wrapperJar);
623: allJars.add(dtJar);
624: allJars.addAll(clientJarFiles);
625:
626: addUpdateJarsForProject(project, allJars);
627:
628: // Partial fix for 119881
629: addToDeploymentDescriptors(project, ejbGroup);
630: }
631:
632: private static EjbRef findEjbRefByName(SunWebApp sunWebApp,
633: String ejbRefName) {
634: EjbRef[] ejbRefs = sunWebApp.getEjbRef();
635: for (EjbRef ref : ejbRefs) {
636: if (ref.getEjbRefName().equals(ejbRefName)) {
637: return ref;
638: }
639: }
640: return null;
641: }
642: }
|