Java tutorial
/* * Copyright 2010 Spolecne s.r.o. (www.spoledge.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.spoledge.audao.generator; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Properties; import javax.xml.transform.TransformerException; import com.spoledge.util.xml.XMLValidator; import com.spoledge.util.xml.XMLValidatorInstance; import com.spoledge.util.xslt.ResourceURIResolver; import com.spoledge.util.xslt.TemplatesCache; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This is the main Generator class. * This class is thread safe. * * <pre> * Generator g = new Generato( Generator.Target.ORACLE ); * g.generate( xml, new FileOutput()); * </pre> */ public class Generator { /** * The global resources located in the JAR. */ public static final String RESOURCES = "/resources"; /** * The global XSD resources located in the JAR. */ public static final String XSD_RESOURCES = RESOURCES + "/xsd"; /** * The global XSL resources located in the JAR. */ public static final String XSL_RESOURCES = RESOURCES + "/xsl"; /** * The global XSL resources located in the JAR. */ public static final String JAVA_RESOURCES = RESOURCES + "/java"; /** * If no specific cache is provided, then all Generators * share the same global cache. */ private static TemplatesCache globalTemplatesCache; /** * Precomputed set of AUDAO Java resource names for each Target. * This structure is lazy. */ private static HashMap<Target, String[]> javaResourceKeys = new HashMap<Target, String[]>(); /** * The AuDAO XML precompiled validator. */ private static XMLValidator xmlValidator; //////////////////////////////////////////////////////////////////////////// // Attributes //////////////////////////////////////////////////////////////////////////// private Target target; private TemplatesCache templatesCache; private ResourceURIResolver resourceURIResolver = new ResourceURIResolver(XSL_RESOURCES); private String[] resourceKeys = new String[10]; private boolean[] resourcesEnabled = new boolean[10]; private boolean isDebugEnabled = false; private Log log = LogFactory.getLog(getClass()); //////////////////////////////////////////////////////////////////////////// // Constructors //////////////////////////////////////////////////////////////////////////// public Generator(Target target) { if (target == null) throw new NullPointerException("Target cannost be null"); this.target = target; } //////////////////////////////////////////////////////////////////////////// // Public //////////////////////////////////////////////////////////////////////////// /** * Returns the target of this generator. */ public final Target getTarget() { return target; } /** * Enables/disables generating type of resource. */ public void setResourceEnabled(ResourceType type, boolean enabled) { resourcesEnabled[type.ordinal()] = enabled; } /** * Enables/disables generating all types of resources. * NOTE: this method does NOT force generating inapplicable resources * for given Target (e.g. DTO_IMPL for "mysql") */ public void setAllResourcesEnabled(boolean enabled) { for (int i = 0; i < resourcesEnabled.length; i++) { resourcesEnabled[i] = enabled; } } /** * Returns true if a debug mode is enabled. */ public boolean getIsDebugEnabled() { return isDebugEnabled; } /** * Sets the debug mode flag. */ public void setIsDebugEnabled(boolean enabled) { this.isDebugEnabled = enabled; ; } /** * Returns the resource key. * It detects whether the implementation file is present * (e.g. "dao/mysql/dto.xsl") and returns that or returns * general version ("dao/dto.xsl"). * * @return the resource key or null if not applicable (e.g. SQL_CREATE for GAE) */ public String getResourceKey(ResourceType type) { int index = type.ordinal(); String ret = resourceKeys[index]; if (ret == null) { ret = getXslName(type, true); if (getClass().getResource(ret) == null) { ret = type.getIsOptional() ? "" : getXslName(type, false); } resourceKeys[index] = ret; } return ret.length() != 0 ? ret : null; } /** * Validates source XML. */ public void validate(String xml) throws Exception { validate(new StringReader(xml)); } /** * Validates source XML. */ public void validate(Reader reader) throws Exception { XMLValidator xv = getXMLValidator(); XMLValidatorInstance xvi = xv.validate(reader); if (xvi.isInvalid()) throw xvi.getParseException(); } /** * Generates the result files. */ public void generate(String pkgName, String xml, Output output) throws IOException, GeneratorException { generate(pkgName, new StringReader(xml), output); } /** * Generates the result files. */ public void generate(String pkgName, Reader reader, Output output) throws IOException, GeneratorException { GeneratorFlow gf = new GeneratorFlow(this, pkgName, reader, output); boolean generated = false; try { for (ResourceType type : ResourceType.values()) { if (resourcesEnabled[type.ordinal()]) { gf.generate(type); generated = true; } } if (gf.hasExceptions()) throw new GeneratorException(gf); } catch (TransformerException e) { if (gf.hasExceptions()) throw new GeneratorException(gf); else throw new GeneratorException(e); } if (gf.hasExceptions()) throw new GeneratorException(gf); if (!generated) { log.warn("generate(): nothing generated since no resource type enabled in the Generator"); } } /** * Sets a templates cache to use. * By default Generator uses default MemoryCache same for all instances. */ public void setTemplatesCache(TemplatesCache tc) { tc.getTransformerFactory().setURIResolver(resourceURIResolver); this.templatesCache = tc; } /** * Returns the cache of XSL templates. */ public synchronized TemplatesCache getTemplatesCache() { if (templatesCache == null) { synchronized (Generator.class) { if (globalTemplatesCache == null) { globalTemplatesCache = new TemplatesCache(); globalTemplatesCache.getTransformerFactory().setURIResolver(resourceURIResolver); } } templatesCache = globalTemplatesCache; } return templatesCache; } /** * Returns the ResourceURIResolver. */ public ResourceURIResolver getResourceURIResolver() { return resourceURIResolver; } /** * Returns the resource keys of the AUDAO Java source files. */ public String[] getJavaResourceKeys() { synchronized (javaResourceKeys) { String[] ret = javaResourceKeys.get(target); if (ret == null) { ret = createJavaResourceKeys(); javaResourceKeys.put(target, ret); } return ret; } } //////////////////////////////////////////////////////////////////////////// // Private //////////////////////////////////////////////////////////////////////////// private String getXslName(ResourceType type, boolean isSpec) { return XSL_RESOURCES + '/' + type.getDir() + '/' + (isSpec ? getTarget().getIdentifier() + '/' : "") + type.getName(); } private String[] createJavaResourceKeys() { ArrayList<String> list = new ArrayList<String>(); Properties props = new Properties(); try { props.load(getClass().getResourceAsStream(JAVA_RESOURCES + "/sources.properties")); } catch (IOException e) { log.error("createJavaResourceKeys()", e); } // NOTE: JDK 1.5 compatibility - we cannot use stringPropertyNames(): // for (String key : props.stringPropertyNames()) { for (Enumeration<?> en = props.propertyNames(); en.hasMoreElements();) { String key = (String) en.nextElement(); String[] vals = props.getProperty(key).split("\\|"); if (vals.length == 1) { list.add(vals[0]); } else { String tname = target.getIdentifier().toLowerCase(); for (int i = 1; i < vals.length; i++) { if (tname.equals(vals[i])) { list.add(vals[0]); break; } } } } String[] ret = new String[list.size()]; return list.toArray(ret); } private static XMLValidator getXMLValidator() { synchronized (Generator.class) { if (xmlValidator == null) { try { xmlValidator = new XMLValidator(Generator.class.getResource(XSD_RESOURCES + "/audao.xsd")); } catch (Exception e) { LogFactory.getLog(Generator.class).error("getXMLValidator(): ", e); } } return xmlValidator; } } }