001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. 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.tools.ant.taskdefs.optional.ejb;
019:
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileWriter;
023: import java.io.IOException;
024: import java.io.ObjectInputStream;
025: import java.io.PrintWriter;
026: import java.util.Vector;
027: import javax.ejb.deployment.DeploymentDescriptor;
028: import javax.ejb.deployment.EntityDescriptor;
029:
030: /**
031: * A helper class which performs the actual work of the ejbc task.
032: *
033: * This class is run with a classpath which includes the weblogic tools and the home and remote
034: * interface class files referenced in the deployment descriptors being processed.
035: *
036: */
037: public final class EjbcHelper {
038: /**
039: * The root directory of the tree containing the serialised deployment desciptors.
040: */
041: private File descriptorDirectory;
042:
043: /**
044: * The directory where generated files are placed.
045: */
046: private File generatedFilesDirectory;
047:
048: /**
049: * The name of the manifest file generated for the EJB jar.
050: */
051: private File manifestFile;
052:
053: /**
054: * The source directory for the home and remote interfaces. This is used to determine if
055: * the generated deployment classes are out of date.
056: */
057: private File sourceDirectory;
058:
059: // CheckStyle:VisibilityModifier OFF - bc
060: /**
061: * The names of the serialised deployment descriptors
062: */
063: String[] descriptors;
064: // CheckStyle:VisibilityModifier ON
065:
066: private boolean keepGenerated;
067:
068: /**
069: * Command line interface for the ejbc helper task.
070: * @param args command line arguments.
071: * @throws Exception if there is a problem.
072: */
073: public static void main(String[] args) throws Exception {
074: EjbcHelper helper = new EjbcHelper(args);
075: helper.process();
076: }
077:
078: /**
079: * Initialise the EjbcHelper by reading the command arguments.
080: */
081: private EjbcHelper(String[] args) {
082: int index = 0;
083: descriptorDirectory = new File(args[index++]);
084: generatedFilesDirectory = new File(args[index++]);
085: sourceDirectory = new File(args[index++]);
086: manifestFile = new File(args[index++]);
087: keepGenerated = Boolean.valueOf(args[index++]).booleanValue();
088:
089: descriptors = new String[args.length - index];
090: for (int i = 0; index < args.length; ++i) {
091: descriptors[i] = args[index++];
092: }
093: }
094:
095: private String[] getCommandLine(boolean debug, File descriptorFile) {
096: Vector v = new Vector();
097: if (!debug) {
098: v.addElement("-noexit");
099: }
100: if (keepGenerated) {
101: v.addElement("-keepgenerated");
102: }
103: v.addElement("-d");
104: v.addElement(generatedFilesDirectory.getPath());
105: v.addElement(descriptorFile.getPath());
106:
107: String[] args = new String[v.size()];
108: v.copyInto(args);
109: return args;
110: }
111:
112: /**
113: * Determine if the weblogic EJB support classes need to be regenerated
114: * for a given deployment descriptor.
115: *
116: * This process attempts to determine if the support classes need to be
117: * rebuilt. It does this by examining only some of the support classes
118: * which are typically generated. If the ejbc task is interrupted generating
119: * the support classes for a bean, all of the support classes should be removed
120: * to force regeneration of the support classes.
121: *
122: * @param descriptorFile the serialised deployment descriptor
123: *
124: * @return true if the support classes need to be regenerated.
125: *
126: * @throws IOException if the descriptor file cannot be closed.
127: */
128: private boolean isRegenRequired(File descriptorFile)
129: throws IOException {
130: // read in the descriptor. Under weblogic, the descriptor is a weblogic
131: // specific subclass which has references to the implementation classes.
132: // These classes must, therefore, be in the classpath when the deployment
133: // descriptor is loaded from the .ser file
134: FileInputStream fis = null;
135: try {
136: fis = new FileInputStream(descriptorFile);
137: ObjectInputStream ois = new ObjectInputStream(fis);
138: DeploymentDescriptor dd = (DeploymentDescriptor) ois
139: .readObject();
140: fis.close();
141:
142: String homeInterfacePath = dd.getHomeInterfaceClassName()
143: .replace('.', '/')
144: + ".java";
145: String remoteInterfacePath = dd
146: .getRemoteInterfaceClassName().replace('.', '/')
147: + ".java";
148: String primaryKeyClassPath = null;
149: if (dd instanceof EntityDescriptor) {
150: primaryKeyClassPath = ((EntityDescriptor) dd)
151: .getPrimaryKeyClassName();
152: primaryKeyClassPath = primaryKeyClassPath.replace('.',
153: '/')
154: + ".java";
155: }
156:
157: File homeInterfaceSource = new File(sourceDirectory,
158: homeInterfacePath);
159: File remoteInterfaceSource = new File(sourceDirectory,
160: remoteInterfacePath);
161: File primaryKeyClassSource = null;
162: if (primaryKeyClassPath != null) {
163: primaryKeyClassSource = new File(sourceDirectory,
164: remoteInterfacePath);
165: }
166:
167: // are any of the above out of date.
168: // we find the implementation classes and see if they are older than any
169: // of the above or the .ser file itself.
170: String beanClassBase = dd.getEnterpriseBeanClassName()
171: .replace('.', '/');
172: File ejbImplentationClass = new File(
173: generatedFilesDirectory, beanClassBase
174: + "EOImpl.class");
175: File homeImplementationClass = new File(
176: generatedFilesDirectory, beanClassBase
177: + "HomeImpl.class");
178: File beanStubClass = new File(generatedFilesDirectory,
179: beanClassBase + "EOImpl_WLStub.class");
180:
181: // if the implementation classes don;t exist regenerate
182: if (!ejbImplentationClass.exists()
183: || !homeImplementationClass.exists()
184: || !beanStubClass.exists()) {
185: return true;
186: }
187:
188: // Is the ser file or any of the source files newer then the class files.
189: // firstly find the oldest of the two class files.
190: long classModificationTime = ejbImplentationClass
191: .lastModified();
192: if (homeImplementationClass.lastModified() < classModificationTime) {
193: classModificationTime = homeImplementationClass
194: .lastModified();
195: }
196: if (beanStubClass.lastModified() < classModificationTime) {
197: classModificationTime = beanStubClass.lastModified();
198: }
199:
200: if (descriptorFile.lastModified() > classModificationTime
201: || homeInterfaceSource.lastModified() > classModificationTime
202: || remoteInterfaceSource.lastModified() > classModificationTime) {
203: return true;
204: }
205:
206: if (primaryKeyClassSource != null
207: && primaryKeyClassSource.lastModified() > classModificationTime) {
208: return true;
209: }
210: } catch (Throwable descriptorLoadException) {
211: System.out.println("Exception occurred reading "
212: + descriptorFile.getName() + " - continuing");
213: // any problems - just regenerate
214: return true;
215: } finally {
216: if (fis != null) {
217: fis.close();
218: }
219: }
220:
221: return false;
222: }
223:
224: /**
225: * Process the descriptors in turn generating support classes for each and a manifest
226: * file for all of the beans.
227: */
228: private void process() throws Exception {
229: String manifest = "Manifest-Version: 1.0\n\n";
230: for (int i = 0; i < descriptors.length; ++i) {
231: String descriptorName = descriptors[i];
232: File descriptorFile = new File(descriptorDirectory,
233: descriptorName);
234:
235: if (isRegenRequired(descriptorFile)) {
236: System.out.println("Running ejbc for "
237: + descriptorFile.getName());
238: regenerateSupportClasses(descriptorFile);
239: } else {
240: System.out.println(descriptorFile.getName()
241: + " is up to date");
242: }
243: manifest += "Name: " + descriptorName.replace('\\', '/')
244: + "\nEnterprise-Bean: True\n\n";
245: }
246:
247: FileWriter fw = new FileWriter(manifestFile);
248: PrintWriter pw = new PrintWriter(fw);
249: pw.print(manifest);
250: fw.flush();
251: fw.close();
252: }
253:
254: /**
255: * Perform the weblogic.ejbc call to regenerate the support classes.
256: *
257: * Note that this method relies on an undocumented -noexit option to the
258: * ejbc tool to stop the ejbc tool exiting the VM altogether.
259: */
260: private void regenerateSupportClasses(File descriptorFile)
261: throws Exception {
262: // create a Java task to do the rebuild
263:
264: String[] args = getCommandLine(false, descriptorFile);
265:
266: try {
267: weblogic.ejbc.main(args);
268: } catch (Exception e) {
269: // run with no exit for better reporting
270: String[] newArgs = getCommandLine(true, descriptorFile);
271: weblogic.ejbc.main(newArgs);
272: }
273: }
274: }
|