001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
005: *
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common Development
009: * and Distribution License("CDDL") (collectively, the "License"). You
010: * may not use this file except in compliance with the License. You can obtain
011: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
012: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
013: * language governing permissions and limitations under the License.
014: *
015: * When distributing the software, include this License Header Notice in each
016: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
017: * Sun designates this particular file as subject to the "Classpath" exception
018: * as provided by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the License
020: * Header, with the fields enclosed by brackets [] replaced by your own
021: * identifying information: "Portions Copyrighted [year]
022: * [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * If you wish your version of this file to be governed by only the CDDL or
027: * only the GPL Version 2, indicate your decision by adding "[Contributor]
028: * elects to include this software in this distribution under the [CDDL or GPL
029: * Version 2] license." If you don't indicate a single choice of license, a
030: * recipient has the option to distribute your version of this file under
031: * either the CDDL, the GPL Version 2 or to extend the choice of license to
032: * its licensees as provided above. However, if you add GPL Version 2 code
033: * and therefore, elected the GPL Version 2 license, then the option applies
034: * only if the new code is made subject to such option by the copyright
035: * holder.
036: */
037:
038: package oracle.toplink.essentials.internal.weaving;
039:
040: import java.io.IOException;
041: import java.io.Writer;
042: import java.lang.instrument.IllegalClassFormatException;
043: import java.net.URISyntaxException;
044: import java.net.URL;
045: import java.util.ArrayList;
046: import java.util.Collection;
047: import java.util.HashMap;
048: import java.util.Iterator;
049: import java.util.List;
050: import java.util.zip.ZipException;
051:
052: import javax.persistence.spi.ClassTransformer;
053: import javax.persistence.spi.PersistenceUnitInfo;
054:
055: import oracle.toplink.essentials.ejb.cmp3.persistence.Archive;
056: import oracle.toplink.essentials.ejb.cmp3.persistence.ArchiveFactoryImpl;
057: import oracle.toplink.essentials.ejb.cmp3.persistence.PersistenceUnitProcessor;
058: import oracle.toplink.essentials.ejb.cmp3.persistence.SEPersistenceUnitInfo;
059: import oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException;
060: import oracle.toplink.essentials.exceptions.StaticWeaveException;
061: import oracle.toplink.essentials.internal.ejb.cmp3.metadata.MetadataProcessor;
062: import oracle.toplink.essentials.internal.helper.EJB30ConversionManager;
063: import oracle.toplink.essentials.logging.DefaultSessionLog;
064: import oracle.toplink.essentials.logging.SessionLog;
065: import oracle.toplink.essentials.sessions.DatabaseLogin;
066: import oracle.toplink.essentials.sessions.Project;
067: import oracle.toplink.essentials.threetier.ServerSession;
068:
069: /**
070: * <p>
071: * <b>Description</b>: This class provides the implementation of class transformer by leveraging on the following existing APIs,
072: * <ul>
073: * <li> PersistenceUnitProcessor.processORMetadata() - get class descriptor.
074: * <li> PersistenceUnitProcessor.buildEntityList() - get entity classes lsit.
075: * <li> TransformerFactory.createTransformerAndModifyProject - get class transformer.
076: * </ul>
077: * <p>
078: * <b>Responsibilities</b>:
079: * <ul>
080: * <li> Create the classtransformer for each persistence unit individually and store them into the list.
081: * <li> Provide class transfom method to perform weaving function.
082: * </ul>
083: *
084: **/
085:
086: public class StaticWeaveClassTransformer {
087: private ArrayList<ClassTransformer> classTransformers;
088: private Writer logWriter;
089: private int logLevel = SessionLog.OFF;
090: private ClassLoader aClassLoader;
091:
092: /**
093: * Constructs an instance of StaticWeaveClassTransformer
094: * @param inputArchiveURL
095: * @param aclassloader
096: * @throws Exception
097: */
098: public StaticWeaveClassTransformer(URL inputArchiveURL,
099: ClassLoader aclassloader) throws Exception {
100: this (inputArchiveURL, aclassloader, null, SessionLog.OFF);
101: }
102:
103: /**
104: * Constructs an instance of StaticWeaveClassTransformer
105: * @param inputArchiveURL
106: * @param aclassloader
107: * @param log
108: * @param loglevel
109: * @throws Exception
110: */
111: public StaticWeaveClassTransformer(URL inputArchiveURL,
112: ClassLoader aclassloader, Writer logWriter, int loglevel)
113: throws URISyntaxException, IOException {
114: this .aClassLoader = aclassloader;
115: this .logWriter = logWriter;
116: this .logLevel = loglevel;
117: buildClassTransformers(inputArchiveURL, aclassloader);
118: }
119:
120: /**
121: * INTERNAL:
122: * The method performs weaving function on the given class.
123: * @param originalClassName
124: * @param originalClass
125: * @param originalClassBytes
126: * @return the converted(woven) class
127: * @throws Exception
128: */
129: public byte[] transform(String originalClassName,
130: Class originalClass, byte[] originalClassBytes)
131: throws IllegalClassFormatException {
132: byte[] newClassBytes = null;
133: for (ClassTransformer transformer : classTransformers) {
134: newClassBytes = transformer.transform(aClassLoader,
135: originalClassName, originalClass, null,
136: originalClassBytes);
137: if (newClassBytes != null) {
138: break;
139: }
140: ;
141: }
142: return newClassBytes;
143: }
144:
145: /**
146: * INTERNAL:
147: * The method creates classtransformer list corresponding to each persistence unit.
148: * @param inputArchiveURL
149: * @param aclassloader
150: * @throws Exception
151: */
152: private void buildClassTransformers(URL inputArchiveURL,
153: ClassLoader aclassloader) throws URISyntaxException,
154: IOException {
155: if (classTransformers != null) {
156: return;
157: } else {
158: classTransformers = new ArrayList<ClassTransformer>();
159: }
160: Archive archive = null;
161: try {
162: archive = (new ArchiveFactoryImpl())
163: .createArchive(inputArchiveURL);
164: } catch (ZipException e) {
165: throw StaticWeaveException.exceptionOpeningArchive(
166: inputArchiveURL, e);
167: }
168:
169: List<SEPersistenceUnitInfo> persistenceUnitsList = PersistenceUnitProcessor
170: .processPersistenceArchive(archive, aclassloader);
171: if (persistenceUnitsList == null) {
172: throw PersistenceUnitLoadingException
173: .couldNotGetUnitInfoFromUrl(inputArchiveURL);
174: }
175: Iterator<SEPersistenceUnitInfo> persistenceUnitsIterator = persistenceUnitsList
176: .iterator();
177: while (persistenceUnitsIterator.hasNext()) {
178: SEPersistenceUnitInfo unitInfo = (SEPersistenceUnitInfo) persistenceUnitsIterator
179: .next();
180: unitInfo.setNewTempClassLoader(aclassloader);
181: //build class transformer.
182: ClassTransformer transformer = buildTransformer(unitInfo,
183: this .logWriter, this .logLevel);
184: classTransformers.add(transformer);
185: }
186: }
187:
188: /**
189: * INTERNAL:
190: * This method builds the classtransformer for the specified perisistence unit.
191: * @param unitInfo
192: * @param logWriter
193: * @param logLevel
194: * @return a ClassTransformer
195: */
196:
197: private ClassTransformer buildTransformer(
198: PersistenceUnitInfo unitInfo, Writer logWriter, int logLevel) {
199: //persistenceUnitInfo = unitInfo;
200: ClassLoader privateClassLoader = unitInfo
201: .getNewTempClassLoader();
202:
203: // create server session (it should be done before initializing ServerPlatform)
204: ServerSession session = new ServerSession(new Project(
205: new DatabaseLogin()));
206: session.setLogLevel(logLevel);
207: if (logWriter != null) {
208: ((DefaultSessionLog) session.getSessionLog())
209: .setWriter(logWriter);
210: }
211:
212: session.getPlatform().setConversionManager(
213: new EJB30ConversionManager());
214:
215: // Create an instance of MetadataProcessor for specified persistence unit info
216: MetadataProcessor processor = new MetadataProcessor(unitInfo,
217: session, privateClassLoader, true);
218: // Process the Object/relational metadata from XML and annotations.
219: PersistenceUnitProcessor.processORMetadata(processor,
220: privateClassLoader, session, false);
221:
222: //Collection entities = buildEntityList(persistenceUnitInfo, privateClassLoader);
223: Collection entities = PersistenceUnitProcessor.buildEntityList(
224: processor, privateClassLoader);
225:
226: // The transformer is capable of altering domain classes to handle a LAZY hint for OneToOne mappings. It will only
227: // be returned if we we are mean to process these mappings
228: return TransformerFactory.createTransformerAndModifyProject(
229: session, entities, privateClassLoader);
230: }
231: }
|