org.hibernate.eclipse.launch.CodeGenXMLFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.eclipse.launch.CodeGenXMLFactory.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributor:
 *     Red Hat, Inc. - initial API and implementation
 ******************************************************************************/
package org.hibernate.eclipse.launch;

import java.io.ByteArrayOutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.datatools.connectivity.IConnectionProfile;
import org.eclipse.datatools.connectivity.ProfileManager;
import org.eclipse.datatools.connectivity.drivers.jdbc.IJDBCDriverDefinitionConstants;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.hibernate.console.ConfigurationFactory;
import org.hibernate.console.ConfigurationXMLFactory;
import org.hibernate.console.ConfigurationXMLStrings;
import org.hibernate.console.ConnectionProfileUtil;
import org.hibernate.console.ConsoleConfiguration;
import org.hibernate.console.KnownConfigurations;
import org.hibernate.console.preferences.ConsoleConfigurationPreferences;
import org.hibernate.console.preferences.PreferencesClassPathUtils;
import org.hibernate.eclipse.console.model.impl.ExporterFactory;
import org.hibernate.eclipse.launch.ExportersXMLAttributeDescription.AttributeDescription;
import org.hibernate.util.xpl.StringHelper;
import org.jboss.tools.hibernate.runtime.spi.IEnvironment;
import org.jboss.tools.hibernate.runtime.spi.IService;
import org.jboss.tools.hibernate.runtime.spi.ServiceLookup;

/**
 * XML document part creation factory,
 * responsible for creation whole Ant code generation script for
 * Hibernate Tools.
 * 
 * @author Vitali Yemialyanchyk
 */
public class CodeGenXMLFactory {

    public static final String varBuildDir = "build.dir"; //$NON-NLS-1$
    public static final String varCurrentDir = "current.dir"; //$NON-NLS-1$
    public static final String varWorkspaceDir = "workspace.dir"; //$NON-NLS-1$

    public static final String NL = System.getProperty("line.separator"); //$NON-NLS-1$
    /**
     * UUID to make a stub for propFileContentPreSave,
     * before formatting
     */
    public static final long versionUID4PropFile = 1841714864553304000L;
    public static final long place2GenerateUID = 3855319363698081943L;
    public static final long workspacePathUID = 2720818065195124531L;
    /**
     */
    public static final String propFileNameSuffix = "hibernate.properties"; //$NON-NLS-1$
    /**
     * presave generated Hibernate Properties file content,
     * this is necessary to proper content formating
     */
    protected String propFileContentPreSave = ""; //$NON-NLS-1$
    /**
     * generate Ant script from this launch configuration
     */
    protected ILaunchConfiguration lc = null;
    /**
     * generate external Hibernate Properties file or
     * put generated properties into Ant script directly
     */
    protected boolean externalPropFile = true;
    /**
     * file name for generated properties file
     */
    protected String externalPropFileName = propFileNameSuffix;
    /**
     * place to generate Ant script file (all paths in script should be
     * relative to this place)
     */
    protected String place2Generate = ""; //$NON-NLS-1$
    /**
     * workspace path
     */
    protected String workspacePath = ""; //$NON-NLS-1$

    public CodeGenXMLFactory(ILaunchConfiguration lc) {
        this.lc = lc;
    }

    @SuppressWarnings("unchecked")
    protected Element createRoot() {
        ExporterAttributes attributes = null;
        try {
            attributes = new ExporterAttributes(lc);
        } catch (CoreException e) {
            // ignore
        }
        if (attributes == null) {
            return null;
        }
        Properties props = new Properties();
        if (attributes.isReverseEngineer()) {
            props.setProperty(ConfigurationXMLStrings.ISREVENG, Boolean.toString(attributes.isReverseEngineer()));
            props.setProperty(ConfigurationXMLStrings.PACKAGENAME, attributes.getPackageName());
            props.setProperty(ConfigurationXMLStrings.PREFERBASICCOMPOSITEIDS,
                    Boolean.toString(attributes.isPreferBasicCompositeIds()));
            props.setProperty(ConfigurationXMLStrings.DETECTMANYTOMANY,
                    Boolean.toString(attributes.detectManyToMany()));
            props.setProperty(ConfigurationXMLStrings.DETECTONTTOONE,
                    Boolean.toString(attributes.detectOneToOne()));
            props.setProperty(ConfigurationXMLStrings.DETECTOPTIMISTICLOCK,
                    Boolean.toString(attributes.detectOptimisticLock()));
            props.setProperty(ConfigurationXMLStrings.REVERSESTRATEGY, attributes.getRevengStrategy());
            String revEngFile = getResLocation(attributes.getRevengSettings());
            props.setProperty(ConfigurationXMLStrings.REVENGFILE, revEngFile);
        }
        //
        final IPath pathPlace2Generate = isEmpty(place2Generate) ? null : new Path(getResLocation(place2Generate));
        final IPath pathWorkspacePath = isEmpty(workspacePath) ? null : new Path(getResLocation(workspacePath));
        //
        String consoleConfigName = attributes.getConsoleConfigurationName();
        ConsoleConfigurationPreferences consoleConfigPrefs = getConsoleConfigPreferences(consoleConfigName);
        final ConfigurationXMLFactory configurationXMLFactory = new ConfigurationXMLFactory(consoleConfigPrefs,
                props);
        configurationXMLFactory.setPlace2Generate(pathPlace2Generate);
        configurationXMLFactory.setWorkspacePath(pathWorkspacePath);
        Element rootConsoleConfig = configurationXMLFactory.createRoot();
        //
        String defaultTargetName = "hibernateAntCodeGeneration"; //$NON-NLS-1$
        Element el, root = DocumentFactory.getInstance().createElement(CodeGenerationStrings.PROJECT);
        root.addAttribute(CodeGenerationStrings.NAME, "CodeGen"); //$NON-NLS-1$
        root.addAttribute(CodeGenerationStrings.DEFAULT, defaultTargetName);
        //
        if (!isEmpty(place2Generate)) {
            el = root.addElement(CodeGenerationStrings.PROPERTY);
            el.addAttribute(CodeGenerationStrings.NAME, varCurrentDir);
            el.addAttribute(CodeGenerationStrings.LOCATION, getPlace2GenerateUID());
        }
        if (!isEmpty(workspacePath)) {
            el = root.addElement(CodeGenerationStrings.PROPERTY);
            el.addAttribute(CodeGenerationStrings.NAME, varWorkspaceDir);
            el.addAttribute(CodeGenerationStrings.LOCATION, getWorkspacePathUID());
        }
        //
        String location = getResLocation(attributes.getOutputPath());
        location = ConfigurationXMLFactory.makePathRelative(location, pathPlace2Generate, pathWorkspacePath);
        el = root.addElement(CodeGenerationStrings.PROPERTY);
        el.addAttribute(CodeGenerationStrings.NAME, varBuildDir);
        el.addAttribute(CodeGenerationStrings.LOCATION, location);
        //
        String hibernatePropFile = null;
        String generateHibernatePropeties = null;
        String connProfileName = consoleConfigPrefs == null ? null : consoleConfigPrefs.getConnectionProfileName();
        IConnectionProfile profile = getConnectionProfile(connProfileName);
        boolean bPropFile = profile != null;
        // update property with fake tm
        Properties propsTmp = null;
        String hibernateVersion = consoleConfigPrefs == null ? "3.5" : consoleConfigPrefs.getHibernateVersion();
        IService service = ServiceLookup.findService(hibernateVersion);
        IEnvironment environment = service.getEnvironment();
        if (consoleConfigPrefs != null && consoleConfigPrefs.getPropertyFile() != null) {
            propsTmp = consoleConfigPrefs.getProperties();
            String tmStrategy = propsTmp.getProperty(environment.getTransactionManagerStrategy());
            if (tmStrategy != null && StringHelper.isEmpty(tmStrategy)) {
                propsTmp.setProperty(environment.getTransactionManagerStrategy(),
                        ConfigurationFactory.FAKE_TM_LOOKUP);
                bPropFile = true;
            }
        }
        if (bPropFile) {
            Set<String> specialProps = new TreeSet<String>();
            specialProps.add(environment.getDriver());
            specialProps.add(environment.getURL());
            specialProps.add(environment.getUser());
            specialProps.add(environment.getPass());
            specialProps.add(environment.getDialect());
            //
            if (propsTmp == null) {
                propsTmp = new Properties();
            }
            StringBuilder propFileContent = new StringBuilder();
            String driverClass = getDriverClass(connProfileName);
            if (profile != null) {
                final Properties cpProperties = profile.getProperties(profile.getProviderId());
                //
                String url = cpProperties.getProperty(IJDBCDriverDefinitionConstants.URL_PROP_ID);
                //
                String user = cpProperties.getProperty(IJDBCDriverDefinitionConstants.USERNAME_PROP_ID);
                //
                String pass = cpProperties.getProperty(IJDBCDriverDefinitionConstants.PASSWORD_PROP_ID);
                //
                String dialectName = consoleConfigPrefs.getDialectName();
                //
                propsTmp.setProperty(environment.getDriver(), driverClass);
                propsTmp.setProperty(environment.getURL(), url);
                propsTmp.setProperty(environment.getUser(), user);
                propsTmp.setProperty(environment.getPass(), pass);
                if (StringHelper.isNotEmpty(dialectName)) {
                    propsTmp.setProperty(environment.getDialect(), dialectName);
                }
            }
            // output keys in sort order
            Object[] keys = propsTmp.keySet().toArray();
            Arrays.sort(keys);
            //
            if (externalPropFile) {
                for (Object obj : keys) {
                    addIntoPropFileContent(propFileContent, obj.toString(), propsTmp.getProperty(obj.toString()));
                }
            } else {
                for (Object obj : keys) {
                    if (specialProps.contains(obj)) {
                        el = root.addElement(CodeGenerationStrings.PROPERTY);
                        el.addAttribute(CodeGenerationStrings.NAME, obj.toString());
                        el.addAttribute(CodeGenerationStrings.VALUE, propsTmp.getProperty(obj.toString()));
                        addIntoPropFileContent(propFileContent, obj.toString());
                    } else {
                        addIntoPropFileContent(propFileContent, obj.toString(),
                                propsTmp.getProperty(obj.toString()));
                    }
                }
            }
            if (externalPropFile) {
                hibernatePropFile = externalPropFileName;
            } else {
                hibernatePropFile = "hibernatePropFile"; //$NON-NLS-1$
                el = root.addElement(CodeGenerationStrings.PROPERTY);
                el.addAttribute(CodeGenerationStrings.NAME, hibernatePropFile);
                el.addAttribute(CodeGenerationStrings.VALUE,
                        "${java.io.tmpdir}${ant.project.name}-hibernate.properties"); //$NON-NLS-1$
                //
                generateHibernatePropeties = "generateHibernatePropeties"; //$NON-NLS-1$
                Element target = root.addElement(CodeGenerationStrings.TARGET);
                target.addAttribute(CodeGenerationStrings.NAME, generateHibernatePropeties);
                //
                hibernatePropFile = getVar(hibernatePropFile);
                Element echo = target.addElement(CodeGenerationStrings.ECHO);
                echo.addAttribute(CodeGenerationStrings.FILE, hibernatePropFile);
                echo.addText(getPropFileContentStubUID());
            }
            propFileContentPreSave = propFileContent.toString().trim();
        }
        // all jars from libraries should be here
        String toolslibID = "toolslib"; //$NON-NLS-1$
        Element toolslib = root.addElement(CodeGenerationStrings.PATH);
        toolslib.addAttribute(CodeGenerationStrings.ID, toolslibID);
        final URL[] customClassPathURLs = PreferencesClassPathUtils.getCustomClassPathURLs(consoleConfigPrefs);
        for (int i = 0; i < customClassPathURLs.length; i++) {
            if (customClassPathURLs[i] == null) {
                continue;
            }
            // what is right here: CodeGenerationStrings.PATH or CodeGenerationStrings.PATHELEMENT?
            // http://www.redhat.com/docs/en-US/JBoss_Developer_Studio/en/hibernatetools/html/ant.html
            // use CodeGenerationStrings.PATH - so may be error in documentation?
            Element pathItem = toolslib.addElement(CodeGenerationStrings.PATH);
            //Element pathItem = toolslib.addElement(CodeGenerationStrings.PATHELEMENT);
            String strPathItem = customClassPathURLs[i].getPath();
            try {
                strPathItem = (new java.io.File(customClassPathURLs[i].toURI())).getPath();
            } catch (URISyntaxException e) {
                // ignore
            }
            strPathItem = new Path(strPathItem).toString();
            strPathItem = ConfigurationXMLFactory.makePathRelative(strPathItem, pathPlace2Generate,
                    pathWorkspacePath);
            pathItem.addAttribute(CodeGenerationStrings.LOCATION, strPathItem);
        }
        //
        Element target = root.addElement(CodeGenerationStrings.TARGET);
        target.addAttribute(CodeGenerationStrings.NAME, defaultTargetName);
        if (!isEmpty(generateHibernatePropeties)) {
            target.addAttribute(CodeGenerationStrings.DEPENDS, generateHibernatePropeties);
        }
        //
        Element taskdef = target.addElement(CodeGenerationStrings.TASKDEF);
        taskdef.addAttribute(CodeGenerationStrings.NAME, CodeGenerationStrings.HIBERNATETOOL);
        taskdef.addAttribute(CodeGenerationStrings.CLASSNAME, "org.hibernate.tool.ant.HibernateToolTask"); //$NON-NLS-1$
        taskdef.addAttribute(CodeGenerationStrings.CLASSPATHREF, toolslibID);
        //
        Element hibernatetool = target.addElement(CodeGenerationStrings.HIBERNATETOOL);
        hibernatetool.addAttribute(CodeGenerationStrings.DESTDIR, getVar(varBuildDir));
        if (attributes.isUseOwnTemplates()) {
            String templatePath = getResLocation(attributes.getTemplatePath());
            hibernatetool.addAttribute(CodeGenerationStrings.TEMPLATEPATH, templatePath);
        }
        if (rootConsoleConfig != null) {
            if (StringHelper.isNotEmpty(hibernatePropFile)) {
                rootConsoleConfig.addAttribute(ConfigurationXMLStrings.PROPERTYFILE, hibernatePropFile);
            }
            // add hibernate console configuration
            hibernatetool.content().add(rootConsoleConfig);
        }
        //
        // the path there are user classes
        Element classpath = hibernatetool.addElement(CodeGenerationStrings.CLASSPATH);
        Element path = classpath.addElement(CodeGenerationStrings.PATH);
        path.addAttribute(CodeGenerationStrings.LOCATION, getVar(varBuildDir));
        //
        Map<String, Map<String, AttributeDescription>> exportersDescr = ExportersXMLAttributeDescription
                .getExportersDescription();
        Map<String, Set<String>> exportersSetSubTags = ExportersXMLAttributeDescription.getExportersSetSubTags();
        //
        Properties globalProps = new Properties();
        // obligatory global properties
        globalProps.put(CodeGenerationStrings.EJB3, "" + attributes.isEJB3Enabled()); //$NON-NLS-1$
        globalProps.put(CodeGenerationStrings.JDK5, "" + attributes.isJDK5Enabled()); //$NON-NLS-1$
        List<ExporterFactory> exporterFactories = attributes.getExporterFactories();
        for (Iterator<ExporterFactory> iter = exporterFactories.iterator(); iter.hasNext();) {
            ExporterFactory ef = iter.next();
            if (!ef.isEnabled(lc)) {
                continue;
            }
            //Map<String, ExporterProperty> defExpProps = ef.getDefaultExporterProperties();
            //String expId = ef.getId();
            String expDefId = ef.getExporterDefinitionId();
            String expName = ef.getExporterTag();
            // mapping: guiName -> AttributeDescription
            Map<String, AttributeDescription> attributesDescrGui = exportersDescr.get(expName);
            if (attributesDescrGui == null) {
                attributesDescrGui = new TreeMap<String, AttributeDescription>();
            }
            // mapping: guiName -> set of sub tags
            Set<String> setSubTags = exportersSetSubTags.get(expName);
            if (setSubTags == null) {
                setSubTags = new TreeSet<String>();
            }
            // construct new mapping: name -> AttributeDescription
            Map<String, AttributeDescription> attributesDescrAnt = new TreeMap<String, AttributeDescription>();
            for (AttributeDescription ad : attributesDescrGui.values()) {
                attributesDescrAnt.put(ad.name, ad);
            }
            //
            Element exporter = hibernatetool.addElement(expName);
            Properties expProps = new Properties();
            expProps.putAll(globalProps);
            expProps.putAll(ef.getProperties());
            //
            Properties extractGUISpecial = new Properties();
            try {
                ExporterFactory.extractExporterProperties(expDefId, expProps, extractGUISpecial);
            } catch (CoreException e) {
                // ignore
            }
            // convert gui special properties names into Ant names
            for (Map.Entry<Object, Object> propEntry : extractGUISpecial.entrySet()) {
                Object key = propEntry.getKey();
                Object val = propEntry.getValue();
                AttributeDescription ad = attributesDescrGui.get(key);
                if (ad == null) {
                    expProps.put(key, val);
                    continue;
                }
                expProps.put(ad.name, val);
            }
            // to add attributes and properties in alphabetic order
            Map<String, Object> expPropsSorted = new TreeMap<String, Object>();
            for (Map.Entry<Object, Object> propEntry : expProps.entrySet()) {
                Object key = propEntry.getKey();
                Object val = propEntry.getValue();
                expPropsSorted.put(key.toString(), val);
            }
            // list2Remove - list to collect properties which put into attributes,
            // all other properties be ordinal property definition
            List<Object> list2Remove = new ArrayList<Object>();
            for (Map.Entry<String, Object> propEntry : expPropsSorted.entrySet()) {
                Object key = propEntry.getKey();
                Object val = propEntry.getValue();
                AttributeDescription ad = attributesDescrAnt.get(key);
                if (ad == null) {
                    continue;
                }
                list2Remove.add(key);
                if (val == null || 0 == val.toString().compareTo(ad.defaultValue)) {
                    continue;
                }
                String processedVal = processPropertyValue(val);
                if (setSubTags.contains(ad.guiName)) {
                    Element subTag = exporter.addElement(ad.name);
                    subTag.addText(processedVal);
                } else {
                    exporter.addAttribute(ad.name, processedVal);
                }
            }
            for (Object obj : list2Remove) {
                expProps.remove(obj);
                expPropsSorted.remove(obj);
            }
            for (Map.Entry<String, Object> propEntry : expPropsSorted.entrySet()) {
                Object key = propEntry.getKey();
                Object val = propEntry.getValue();
                String processedVal = processPropertyValue(val);
                Element property = exporter.addElement(CodeGenerationStrings.PROPERTY);
                property.addAttribute(CodeGenerationStrings.KEY, key.toString());
                property.addAttribute(CodeGenerationStrings.VALUE, processedVal);
            }
        }
        return root;
    }

    public IConnectionProfile getConnectionProfile(String connProfileName) {
        IConnectionProfile profile = null;
        if (!isEmpty(connProfileName)) {
            profile = ProfileManager.getInstance().getProfileByName(connProfileName);
        }
        return profile;
    }

    public String getDriverClass(String connProfileName) {
        return ConnectionProfileUtil.getDriverClass(connProfileName);
    }

    public String getVar(String str) {
        return "${" + str + "}"; //$NON-NLS-1$ //$NON-NLS-2$
    }

    public void addIntoPropFileContent(StringBuilder pfc, String str) {
        pfc.append(NL + str + "=" + getVar(str)); //$NON-NLS-1$
    }

    public void addIntoPropFileContent(StringBuilder pfc, String name, String value) {
        pfc.append(NL + name + "=" + value); //$NON-NLS-1$
    }

    public ConsoleConfigurationPreferences getConsoleConfigPreferences(String consoleConfigName) {
        ConsoleConfiguration consoleConfig = KnownConfigurations.getInstance().find(consoleConfigName);
        if (consoleConfig == null) {
            return null;
        }
        return consoleConfig.getPreferences();
    }

    /**
     * Check is the value a path in current file system,
     * if true - update result value (workspace related path is 
     * converted to absolute path).
     * 
     * @param val
     * @return
     */
    public String processPropertyValue(Object val) {
        if (val == null) {
            return ""; //$NON-NLS-1$
        }
        String res = val.toString();
        String processedVal = getResLocation(res);
        if ((new java.io.File(processedVal)).exists()) {
            res = processedVal;
        }
        return res;
    }

    public IResource findResource(String path) {
        final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
        final IResource res = PathHelper.findMember(wsRoot, path);
        return res;
    }

    public String getResLocation(String path) {
        final IResource outputPathRes = findResource(path);
        String location = path == null ? "" : path; //$NON-NLS-1$
        if (outputPathRes != null) {
            location = outputPathRes.getLocation().toString();
        } else {
            location = new Path(location).toString();
        }
        return location;
    }

    public static boolean isEmpty(String str) {
        return (str == null || str.length() == 0);
    }

    public static String getPropFileContentStubUID() {
        return Long.toHexString(versionUID4PropFile);
    }

    public static String getPlace2GenerateUID() {
        return Long.toHexString(place2GenerateUID);
    }

    public static String getWorkspacePathUID() {
        return Long.toHexString(workspacePathUID);
    }

    public String getPropFileContentPreSave() {
        return propFileContentPreSave == null ? "" : propFileContentPreSave; //$NON-NLS-1$
    }

    public String createCodeGenXML() {
        Element rootBuildXml = createRoot();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ConfigurationXMLFactory.dump(baos, rootBuildXml);
        String res = baos.toString().trim();
        //place2Generate, workspacePath
        if (!isEmpty(place2Generate)) {
            String location = getResLocation(place2Generate);
            res = res.replace(location, getVar(varCurrentDir));
            res = res.replace(getPlace2GenerateUID(), location);
        }
        if (!isEmpty(workspacePath)) {
            String location = getResLocation(workspacePath);
            res = res.replace(getWorkspacePathUID(), location);
        }
        res = res.replace(getPropFileContentStubUID(), getPropFileContentPreSave());
        return res;
    }

    public void setExternalPropFile(boolean externalPropFile) {
        this.externalPropFile = externalPropFile;
    }

    public void setExternalPropFileName(String externalPropFileName) {
        this.externalPropFileName = externalPropFileName;
    }

    public String getExternalPropFileName() {
        return externalPropFileName;
    }

    public void setPlace2Generate(String place2Generate) {
        this.place2Generate = place2Generate;
    }

    public String getPlace2Generate() {
        return place2Generate;
    }

    public void setWorkspacePath(String workspacePath) {
        this.workspacePath = workspacePath;
    }

    public String getWorkspacePath() {
        return workspacePath;
    }

    public static String getExternalPropFileNameStandard(String fileName) {
        String externalPropFileName = CodeGenXMLFactory.propFileNameSuffix;
        externalPropFileName = fileName + "." + externalPropFileName; //$NON-NLS-1$
        return externalPropFileName;
    }
}