/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * 08/10/2009-2.0 Guy Pelletier * - 267391: JPA 2.0 implement/extend/use an APT tooling library for MetaModel API canonical classes * 11/20/2009-2.0 Guy Pelletier/Mitesh Meswani * - 295376: Improve usability of MetaModel generator * 04/29/2010-2.0.3 Guy Pelletier * - 311020: Canonical model generator should not throw an exception when no persistence.xml is found * 06/01/2010-2.1 Guy Pelletier * - 315195: Add new property to avoid reading XML during the canonical model generation * 03/06/2013-2.5 Guy Pelletier * - 267391: JPA 2.1 Functionality for Java EE 7 (JSR-338) ******************************************************************************/ package org.eclipse.persistence.internal.jpa.modelgen.objects; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.HashSet; import java.util.StringTokenizer; import javax.annotation.processing.ProcessingEnvironment; import javax.tools.FileObject; import javax.tools.StandardLocation; import javax.tools.Diagnostic.Kind; import org.eclipse.persistence.config.PersistenceUnitProperties; import org.eclipse.persistence.exceptions.ValidationException; import org.eclipse.persistence.internal.jpa.deployment.SEPersistenceUnitInfo; import org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProperties; import org.eclipse.persistence.internal.jpa.modelgen.MetadataMirrorFactory; import org.eclipse.persistence.internal.jpa.modelgen.objects.PersistenceUnit; import org.eclipse.persistence.internal.jpa.modelgen.objects.PersistenceXML; import org.eclipse.persistence.internal.jpa.modelgen.objects.PersistenceXMLMappings; import static org.eclipse.persistence.config.PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML; import static org.eclipse.persistence.config.PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML_DEFAULT; import static org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProperties.CANONICAL_MODEL_LOAD_XML; import static org.eclipse.persistence.internal.jpa.modelgen.CanonicalModelProperties.CANONICAL_MODEL_LOAD_XML_DEFAULT; /** * Used to read persistence units through the java annotation processing API. * * @author Guy Pelletier, Peter Krogh * @since EclipseLink 1.2 */ public class PersistenceUnitReader { protected MetadataMirrorFactory factory; protected ProcessingEnvironment processingEnv; /** * INTERNAL: */ public PersistenceUnitReader(MetadataMirrorFactory factory) throws IOException { this.factory = factory; processingEnv = factory.getProcessingEnvironment(); // As a performance enhancement to avoid reloading and merging XML // metadata for every compile round, the user may choose to turn off // the XML loading by setting the load XML flag to false. if (Boolean.valueOf(CanonicalModelProperties.getOption(CANONICAL_MODEL_LOAD_XML, CANONICAL_MODEL_LOAD_XML_DEFAULT, processingEnv.getOptions()))) { // after initializing our member variables, initialize the pu's. initPersistenceUnits(); } } /** * INTERAL: * Close the given input stream. */ protected void closeInputStream(InputStream inputStream) { if (inputStream != null) { try { inputStream.close(); } catch (IOException exception) { throw ValidationException.fileError(exception); } } } /** * INTERNAL: */ protected FileObject getFileObject(String filename, ProcessingEnvironment processingEnv) throws IOException { return processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", filename); } /** * INTERNAL: * Return an input stream for the given filename. */ protected InputStream getInputStream(String filename, boolean loadingPersistenceXML) { InputStream inputStream = null; try { FileObject fileObject = getFileObject(filename, processingEnv); inputStream = fileObject.openInputStream(); } catch (Exception ioe) { // If we can't find the persistence.xml from the class output // we'll try from the current directory using regular IO. try { inputStream = new FileInputStream(filename); } catch (IOException e) { if (loadingPersistenceXML) { // If loading the persistence.xml, log a BIG warning message. processingEnv.getMessager().printMessage(Kind.NOTE, "The persistence xml file ["+filename+"] was not found. NO GENERATION will occur!! Please ensure a persistence xml file is available either from the CLASS_OUTPUT directory [META-INF/persistence.xml] or using the eclipselink.persistencexml property to specify its location. "); } else { // For any other mapping file log a message. processingEnv.getMessager().printMessage(Kind.NOTE, "Optional file was not found: " + filename + " continuing with generation."); } } } return inputStream; } /** * INTERNAL: * This method will look for an process the -A eclipselink.persistenceunits * option. This list is treated as an include/filter list and if it is not * specified all persistence units are processed. */ protected HashSet<String> getPersistenceUnitList(ProcessingEnvironment processingEnv ) { String persistenceUnits = processingEnv.getOptions().get(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_UNITS); HashSet<String> persistenceUnitList = null; if (persistenceUnits != null) { persistenceUnitList = new HashSet<String>(); StringTokenizer st = new StringTokenizer(persistenceUnits, ","); while (st.hasMoreTokens()) { persistenceUnitList.add(((String) st.nextToken()).trim()); } } return persistenceUnitList; } /** * INTERNAL: */ public Collection<PersistenceUnit> getPersistenceUnits() { return factory.getPersistenceUnits(); } /** * INTERNAL: */ protected void initPersistenceUnits() { for (String optionKey : processingEnv.getOptions().keySet()) { processingEnv.getMessager().printMessage(Kind.OTHER, "Found Option : " + optionKey + ", with value: " + processingEnv.getOptions().get(optionKey)); } String filename = CanonicalModelProperties.getOption(ECLIPSELINK_PERSISTENCE_XML, ECLIPSELINK_PERSISTENCE_XML_DEFAULT, processingEnv.getOptions()); HashSet<String> persistenceUnitList = getPersistenceUnitList(processingEnv); InputStream inStream1 = null; InputStream inStream2 = null; try { inStream1 = getInputStream(filename, true); // If the persistence.xml was not found, then there is nothing to do. if (inStream1 != null) { PersistenceXML persistenceXML; try { // Try a 2.1 context first. persistenceXML = (PersistenceXML) PersistenceXMLMappings.createXML2_1Context().createUnmarshaller().unmarshal(inStream1); } catch (Exception e) { // Catch all exceptions and try a 2.0 context second with a new input stream. inStream2 = getInputStream(filename, true); persistenceXML = (PersistenceXML) PersistenceXMLMappings.createXML2_0Context().createUnmarshaller().unmarshal(inStream2); } for (SEPersistenceUnitInfo puInfo : persistenceXML.getPersistenceUnitInfos()) { // If no persistence unit list has been specified or one // has been specified and this persistence unit info's name // appears in that list then add it. if (persistenceUnitList == null || persistenceUnitList.contains(puInfo.getPersistenceUnitName())) { factory.addPersistenceUnit(puInfo, new PersistenceUnit(puInfo, factory, this)); } } } } finally { closeInputStream(inStream1); closeInputStream(inStream2); } } }