001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * 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, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.assembler.classic;
018:
019: import java.io.File;
020: import java.io.FileOutputStream;
021: import java.io.IOException;
022: import java.util.Set;
023: import java.util.StringTokenizer;
024: import java.util.TreeSet;
025: import java.util.jar.JarEntry;
026: import java.util.jar.JarOutputStream;
027:
028: import org.apache.openejb.core.cmp.cmp2.Cmp2Generator;
029: import org.apache.openejb.core.cmp.cmp2.CmrField;
030: import org.apache.openejb.core.cmp.cmp2.Cmp1Generator;
031: import org.apache.openejb.core.cmp.CmpUtil;
032: import org.apache.openejb.ClassLoaderUtil;
033: import org.apache.openejb.util.UrlCache;
034:
035: /**
036: * Creates a jar file which contains the CMP implementation classes and the cmp entity mappings xml file.
037: */
038: public class CmpJarBuilder {
039: private final ClassLoader tempClassLoader;
040:
041: private File jarFile;
042: private final Set<String> entries = new TreeSet<String>();
043: private final AppInfo appInfo;
044:
045: public CmpJarBuilder(AppInfo appInfo, ClassLoader classLoader) {
046: this .appInfo = appInfo;
047: tempClassLoader = ClassLoaderUtil
048: .createTempClassLoader(classLoader);
049: }
050:
051: public File getJarFile() throws IOException {
052: if (jarFile == null) {
053: generate();
054: }
055: return jarFile;
056: }
057:
058: private void generate() throws IOException {
059: // Don't generate an empty jar
060: if (!hasCmpBeans())
061: return;
062:
063: boolean threwException = false;
064: JarOutputStream jarOutputStream = openJarFile();
065: try {
066: // Generate CMP implementation classes
067: for (EjbJarInfo ejbJar : appInfo.ejbJars) {
068: for (EnterpriseBeanInfo beanInfo : ejbJar.enterpriseBeans) {
069: if (beanInfo instanceof EntityBeanInfo) {
070: EntityBeanInfo entityBeanInfo = (EntityBeanInfo) beanInfo;
071: if ("CONTAINER"
072: .equalsIgnoreCase(entityBeanInfo.persistenceType)) {
073: generateClass(jarOutputStream,
074: entityBeanInfo);
075: }
076: }
077: }
078: }
079: if (appInfo.cmpMappingsXml != null) {
080: // System.out.println(appInfo.cmpMappingsXml);
081: addJarEntry(jarOutputStream,
082: "META-INF/openejb-cmp-generated-orm.xml",
083: appInfo.cmpMappingsXml.getBytes());
084: }
085: } catch (IOException e) {
086: threwException = true;
087: throw e;
088: } finally {
089: close(jarOutputStream);
090: if (threwException) {
091: jarFile.delete();
092: jarFile = null;
093: }
094: }
095: }
096:
097: private boolean hasCmpBeans() {
098: for (EjbJarInfo ejbJar : appInfo.ejbJars) {
099: for (EnterpriseBeanInfo beanInfo : ejbJar.enterpriseBeans) {
100: if (beanInfo instanceof EntityBeanInfo) {
101: EntityBeanInfo entityBeanInfo = (EntityBeanInfo) beanInfo;
102: if ("CONTAINER"
103: .equalsIgnoreCase(entityBeanInfo.persistenceType)) {
104: return true;
105: }
106: }
107: }
108: }
109: return false;
110: }
111:
112: private void generateClass(JarOutputStream jarOutputStream,
113: EntityBeanInfo entityBeanInfo) throws IOException {
114: // don't generate if there is aleady an implementation class
115: String cmpImplClass = CmpUtil.getCmpImplClassName(
116: entityBeanInfo.abstractSchemaName,
117: entityBeanInfo.ejbClass);
118: String entryName = cmpImplClass.replace(".", "/") + ".class";
119: if (entries.contains(entryName)
120: || tempClassLoader.getResource(entryName) != null) {
121: return;
122: }
123:
124: // load the bean class, which is used by the generator
125: Class<?> beanClass = null;
126: try {
127: beanClass = tempClassLoader
128: .loadClass(entityBeanInfo.ejbClass);
129: } catch (ClassNotFoundException e) {
130: throw (IOException) new IOException(
131: "Could not find entity bean class " + beanClass)
132: .initCause(e);
133: }
134:
135: Class<?> primKeyClass = null;
136: if (entityBeanInfo.primKeyClass != null) {
137: try {
138: primKeyClass = tempClassLoader
139: .loadClass(entityBeanInfo.primKeyClass);
140: } catch (ClassNotFoundException e) {
141: throw (IOException) new IOException(
142: "Could not find entity primary key class "
143: + entityBeanInfo.primKeyClass)
144: .initCause(e);
145: }
146: }
147:
148: byte[] bytes;
149: if (entityBeanInfo.cmpVersion != 2) {
150: Cmp1Generator cmp1Generator = new Cmp1Generator(
151: cmpImplClass, beanClass);
152: if ("java.lang.Object".equals(entityBeanInfo.primKeyClass)) {
153: cmp1Generator.setUnknownPk(true);
154: }
155: bytes = cmp1Generator.generate();
156: } else {
157:
158: // generte the implementation class
159: Cmp2Generator cmp2Generator = new Cmp2Generator(
160: cmpImplClass,
161: beanClass,
162: entityBeanInfo.primKeyField,
163: primKeyClass,
164: entityBeanInfo.cmpFieldNames
165: .toArray(new String[entityBeanInfo.cmpFieldNames
166: .size()]));
167:
168: for (CmrFieldInfo cmrFieldInfo : entityBeanInfo.cmrFields) {
169: EntityBeanInfo roleSource = cmrFieldInfo.mappedBy.roleSource;
170: CmrField cmrField = new CmrField(
171: cmrFieldInfo.fieldName, cmrFieldInfo.fieldType,
172: CmpUtil.getCmpImplClassName(
173: roleSource.abstractSchemaName,
174: roleSource.ejbClass), roleSource.local,
175: cmrFieldInfo.mappedBy.fieldName,
176: cmrFieldInfo.synthetic);
177: cmp2Generator.addCmrField(cmrField);
178: }
179: bytes = cmp2Generator.generate();
180: }
181:
182: // add the generated class to the jar
183: addJarEntry(jarOutputStream, entryName, bytes);
184: }
185:
186: private void addJarEntry(JarOutputStream jarOutputStream,
187: String fileName, byte[] bytes) throws IOException {
188: // add all missing directory entried
189: String path = "";
190: for (StringTokenizer tokenizer = new StringTokenizer(fileName,
191: "/"); tokenizer.hasMoreTokens();) {
192: String part = tokenizer.nextToken();
193: if (tokenizer.hasMoreTokens()) {
194: path += part + "/";
195: if (!entries.contains(path)) {
196: jarOutputStream.putNextEntry(new JarEntry(path));
197: jarOutputStream.closeEntry();
198: entries.add(path);
199: }
200: }
201: }
202:
203: // write the bytes
204: jarOutputStream.putNextEntry(new JarEntry(fileName));
205: try {
206: jarOutputStream.write(bytes);
207: } finally {
208: jarOutputStream.closeEntry();
209: entries.add(fileName);
210: }
211: }
212:
213: private JarOutputStream openJarFile() throws IOException {
214: if (jarFile != null) {
215: throw new IllegalStateException("Jar file is closed");
216: }
217:
218: // if url caching is enabled, generate the file directly in the cache dir, so it doesn't have to be recoppied
219: if (UrlCache.cacheDir != null) {
220: jarFile = File.createTempFile("OpenEJB_Generated_", ".jar",
221: UrlCache.cacheDir);
222: } else {
223: jarFile = File.createTempFile("OpenEJB_Generated_", ".jar");
224: }
225:
226: jarFile.deleteOnExit();
227: JarOutputStream jarOutputStream = new JarOutputStream(
228: new FileOutputStream(jarFile));
229: return jarOutputStream;
230: }
231:
232: private void close(JarOutputStream jarOutputStream) {
233: if (jarOutputStream != null) {
234: try {
235: jarOutputStream.close();
236: } catch (IOException ignored) {
237: }
238: }
239: }
240: }
|