/******************************************************************************* * 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; } }