/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.osgi.web.wab.generator.internal.processor; import aQute.bnd.header.Attrs; import aQute.bnd.header.Parameters; import aQute.bnd.osgi.Analyzer; import aQute.bnd.osgi.Builder; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Descriptors.PackageRef; import aQute.bnd.osgi.FileResource; import aQute.bnd.osgi.Jar; import aQute.bnd.osgi.Packages; import aQute.bnd.osgi.Resource; import aQute.bnd.version.Version; import com.liferay.ant.bnd.jsp.JspAnalyzerPlugin; import com.liferay.petra.xml.XMLUtil; import com.liferay.portal.events.GlobalStartupAction; import com.liferay.portal.kernel.deploy.auto.AutoDeployException; import com.liferay.portal.kernel.deploy.auto.AutoDeployListener; import com.liferay.portal.kernel.deploy.auto.context.AutoDeploymentContext; import com.liferay.portal.kernel.deploy.hot.DependencyManagementThreadLocal; import com.liferay.portal.kernel.io.FileFilter; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.plugin.PluginPackage; import com.liferay.portal.kernel.servlet.PortalClassLoaderFilter; import com.liferay.portal.kernel.servlet.PortalClassLoaderServlet; import com.liferay.portal.kernel.util.FastDateFormatFactoryUtil; import com.liferay.portal.kernel.util.FileUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.MapUtil; import com.liferay.portal.kernel.util.Portal; import com.liferay.portal.kernel.util.PropertiesUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.SetUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.xml.Document; import com.liferay.portal.kernel.xml.Element; import com.liferay.portal.kernel.xml.Node; import com.liferay.portal.kernel.xml.SAXReaderUtil; import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil; import com.liferay.portal.kernel.xml.XPath; import com.liferay.portal.util.PropsValues; import com.liferay.whip.util.ReflectionUtil; import java.io.File; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.text.Format; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; /** * @author Raymond Augé * @author Miguel Pastor */ public class WabProcessor { public WabProcessor( ClassLoader classLoader, File file, Map<String, String[]> parameters) { _file = file; _parameters = parameters; } public File getProcessedFile() throws IOException { _pluginDir = autoDeploy(); if ((_pluginDir == null) || !_pluginDir.exists() || !_pluginDir.isDirectory()) { return null; } File outputFile = null; try (Jar jar = new Jar(_pluginDir)) { if (jar.getBsn() == null) { outputFile = transformToOSGiBundle(jar); } } catch (Exception e) { ReflectionUtil.throwException(e); } if (_file.isDirectory()) { return _file; } if (PropsValues.MODULE_FRAMEWORK_WEB_GENERATOR_GENERATED_WABS_STORE) { writeGeneratedWab(outputFile); } return outputFile; } protected void addElement(Element element, String name, String text) { Element childElement = element.addElement(name); childElement.addText(GetterUtil.getString(text)); } protected void appendProperty( Analyzer analyzer, String property, String string) { analyzer.setProperty( property, Analyzer.append(analyzer.getProperty(property), string)); } protected File autoDeploy() { String webContextpath = getWebContextPath(); AutoDeploymentContext autoDeploymentContext = buildAutoDeploymentContext(webContextpath); executeAutoDeployers(autoDeploymentContext); _pluginPackage = autoDeploymentContext.getPluginPackage(); if (_pluginPackage != null) { _context = _pluginPackage.getContext(); } else { _context = autoDeploymentContext.getContext(); } if (_file.isDirectory()) { return _file; } File deployDir = autoDeploymentContext.getDeployDir(); if (!deployDir.exists()) { File parentFile = deployDir.getParentFile(); File[] files = parentFile.listFiles( new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".war"); } }); if ((files == null) || (files.length == 0)) { _log.error("Unable to find any WARs in " + parentFile); return null; } File file = files[0]; deployDir.mkdirs(); if (file.isDirectory()) { FileUtil.move(file, deployDir); } else { try (Jar jar = new Jar(file)) { jar.expand(deployDir); } catch (Exception e) { ReflectionUtil.throwException(e); } } } if (_AUTODEPLOYED_WARS_STORE) { writeAutoDeployedWar(deployDir); } return deployDir; } protected AutoDeploymentContext buildAutoDeploymentContext(String context) { AutoDeploymentContext autoDeploymentContext = new AutoDeploymentContext(); autoDeploymentContext.setContext(context); autoDeploymentContext.setFile(_file); if (_file.isDirectory()) { return autoDeploymentContext; } File file = new File(_file.getParentFile(), "deploy"); file.mkdirs(); autoDeploymentContext.setDestDir(file.getAbsolutePath()); return autoDeploymentContext; } protected void executeAutoDeployers( AutoDeploymentContext autoDeploymentContext) { boolean enabled = DependencyManagementThreadLocal.isEnabled(); try { DependencyManagementThreadLocal.setEnabled(false); List<AutoDeployListener> autoDeployListeners = GlobalStartupAction.getAutoDeployListeners(false); AutoDeployListener autoDeployListener = getAutoDeployListener( autoDeploymentContext, autoDeployListeners); autoDeployListener.deploy(autoDeploymentContext); } catch (AutoDeployException ade) { throw new RuntimeException(ade); } finally { DependencyManagementThreadLocal.setEnabled(enabled); } } protected void formatDocument(File file, Document document) throws IOException { try { FileUtil.write(file, XMLUtil.formatXML(document)); } catch (Exception e) { throw new IOException(e); } } protected AutoDeployListener getAutoDeployListener( AutoDeploymentContext autoDeploymentContext, List<AutoDeployListener> autoDeployListeners) { List<AutoDeployListener> deployableAutoDeployListeners = new ArrayList<>(); for (AutoDeployListener autoDeployListener : autoDeployListeners) { try { if (autoDeployListener.isDeployable(autoDeploymentContext)) { deployableAutoDeployListeners.add(autoDeployListener); } } catch (AutoDeployException ade) { throw new RuntimeException(ade); } } if (deployableAutoDeployListeners.size() > 1) { StringBundler sb = new StringBundler( 3 + (deployableAutoDeployListeners.size() * 2) - 1); sb.append("More than one auto deploy listener is available for "); sb.append(autoDeploymentContext.getFile()); sb.append(": "); for (int i = 0; i < deployableAutoDeployListeners.size(); i++) { AutoDeployListener deployableAutoDeployListener = deployableAutoDeployListeners.get(i); Class<?> clazz = deployableAutoDeployListener.getClass(); if (i != 0) { sb.append(StringPool.COMMA_AND_SPACE); } sb.append(clazz.getName()); } throw new RuntimeException(new AutoDeployException(sb.toString())); } return deployableAutoDeployListeners.get(0); } protected Properties getPluginPackageProperties() { File file = new File( _pluginDir, "WEB-INF/liferay-plugin-package.properties"); if (!file.exists()) { return new Properties(); } try { return PropertiesUtil.load(FileUtil.read(file)); } catch (IOException ioe) { return new Properties(); } } protected String getVersionedServicePackageName(String partialPackageName) { return _servicePackageName + partialPackageName + ";version=" + _bundleVersion; } protected String getWebContextPath() { String webContextpath = MapUtil.getString( _parameters, "Web-ContextPath"); if (!webContextpath.startsWith(StringPool.SLASH)) { webContextpath = StringPool.SLASH.concat(webContextpath); } return webContextpath; } protected void processBundleClasspath( Analyzer analyzer, Properties pluginPackageProperties) throws IOException { appendProperty( analyzer, Constants.BUNDLE_CLASSPATH, "ext/WEB-INF/classes"); // Class path order is critical Map<String, File> classPath = new LinkedHashMap<>(); classPath.put( "WEB-INF/classes", new File(_pluginDir, "WEB-INF/classes")); appendProperty(analyzer, Constants.BUNDLE_CLASSPATH, "WEB-INF/classes"); processFiles(classPath, analyzer); Collection<File> files = classPath.values(); analyzer.setClasspath(files.toArray(new File[classPath.size()])); } protected void processBundleManifestVersion(Analyzer analyzer) { String bundleManifestVersion = MapUtil.getString( _parameters, Constants.BUNDLE_MANIFESTVERSION); if (Validator.isNull(bundleManifestVersion)) { bundleManifestVersion = "2"; } analyzer.setProperty( Constants.BUNDLE_MANIFESTVERSION, bundleManifestVersion); } protected void processBundleSymbolicName(Analyzer analyzer) { String bundleSymbolicName = MapUtil.getString( _parameters, Constants.BUNDLE_SYMBOLICNAME); if (Validator.isNull(bundleSymbolicName)) { bundleSymbolicName = _context.substring(1); } analyzer.setProperty(Constants.BUNDLE_SYMBOLICNAME, bundleSymbolicName); } protected void processBundleVersion(Analyzer analyzer) { _bundleVersion = MapUtil.getString( _parameters, Constants.BUNDLE_VERSION); if (Validator.isNull(_bundleVersion)) { if (_pluginPackage != null) { _bundleVersion = _pluginPackage.getVersion(); } else { _bundleVersion = "1.0.0"; } } if (!Version.isVersion(_bundleVersion)) { // Convert from the Maven format to the OSGi format Matcher matcher = _versionMavenPattern.matcher(_bundleVersion); if (matcher.matches()) { StringBuilder sb = new StringBuilder(); sb.append(matcher.group(1)); sb.append("."); sb.append(matcher.group(3)); sb.append("."); sb.append(matcher.group(5)); sb.append("."); sb.append(matcher.group(7)); _bundleVersion = sb.toString(); } else { _bundleVersion = "0.0.0." + _bundleVersion.replace(".", "_"); } } analyzer.setProperty(Constants.BUNDLE_VERSION, _bundleVersion); } protected void processClass(Analyzer analyzer, String value) { int index = value.lastIndexOf('.'); if (index == -1) { return; } Packages packages = analyzer.getReferred(); String packageName = value.substring(0, index); PackageRef packageRef = analyzer.getPackageRef(packageName); packages.put(packageRef, new Attrs()); } protected void processDeclarativeReferences(Analyzer analyzer) throws IOException { processDefaultServletPackages(); processTLDDependencies(analyzer); Path pluginPath = _pluginDir.toPath(); processXMLDependencies( analyzer, "WEB-INF/liferay-hook.xml", _XPATHS_HOOK); processXMLDependencies( analyzer, "WEB-INF/liferay-portlet.xml", _XPATHS_LIFERAY); processXMLDependencies( analyzer, "WEB-INF/portlet.xml", _XPATHS_PORTLET); processXMLDependencies(analyzer, "WEB-INF/web.xml", _XPATHS_JAVAEE); Path classes = pluginPath.resolve("WEB-INF/classes/"); processPropertiesDependencies( analyzer, classes, ".properties", _KNOWN_PROPERTY_KEYS); processXMLDependencies(analyzer, classes, ".xml", _XPATHS_HBM); processXMLDependencies(analyzer, classes, ".xml", _XPATHS_SPRING); } protected void processDefaultServletPackages() { for (String value : PropsValues. MODULE_FRAMEWORK_WEB_GENERATOR_DEFAULT_SERVLET_PACKAGES) { Parameters defaultPackage = new Parameters(value); for (String packageName : defaultPackage.keySet()) { if (_importPackageParameters.containsKey(packageName)) { continue; } _importPackageParameters.add(packageName, _optionalAttrs); } } } protected void processExportPackageNames(Analyzer analyzer) { analyzer.setProperty( Constants.EXPORT_CONTENTS, _exportPackageParameters.toString()); } protected void processExtraHeaders(Analyzer analyzer) { String bundleSymbolicName = analyzer.getProperty( Constants.BUNDLE_SYMBOLICNAME); Properties properties = PropsUtil.getProperties( PropsKeys.MODULE_FRAMEWORK_WEB_GENERATOR_HEADERS, true); Enumeration<Object> keys = properties.keys(); while (keys.hasMoreElements()) { String key = (String)keys.nextElement(); String value = properties.getProperty(key); String processedKey = key; if (processedKey.endsWith(StringPool.CLOSE_BRACKET)) { String filterString = StringPool.OPEN_BRACKET + bundleSymbolicName + StringPool.CLOSE_BRACKET; if (!processedKey.endsWith(filterString)) { continue; } processedKey = processedKey.substring( 0, processedKey.indexOf(StringPool.OPEN_BRACKET)); } if (Validator.isNotNull(value)) { Parameters parameters = new Parameters(value); if (processedKey.equals(Constants.EXPORT_PACKAGE)) { _exportPackageParameters.mergeWith(parameters, true); } else if (processedKey.equals(Constants.IMPORT_PACKAGE)) { _importPackageParameters.mergeWith(parameters, true); } analyzer.setProperty(processedKey, parameters.toString()); } } } protected void processExtraRequirements() { Attrs attrs = new Attrs(_optionalAttrs); attrs.put("x-liferay-compatibility:", "spring"); _importPackageParameters.add("org.eclipse.core.runtime", attrs); _importPackageParameters.add("!junit.*", new Attrs()); } protected void processFiles(Map<String, File> classPath, Analyzer analyzer) throws IOException { Jar jar = analyzer.getJar(); Map<String, Resource> resources = jar.getResources(); Set<Entry<String, Resource>> entrySet = resources.entrySet(); Iterator<Entry<String, Resource>> iterator = entrySet.iterator(); while (iterator.hasNext()) { Entry<String, Resource> entry = iterator.next(); String path = entry.getKey(); Resource resource = entry.getValue(); if (path.equals("WEB-INF/service.xml")) { processServicePackageName(entry.getValue()); } else if (path.startsWith("WEB-INF/lib/")) { // Remove any other "-service.jar" or ignored jar so that real // imports are used if ((path.endsWith("-service.jar") && !path.endsWith(_context.concat("-service.jar"))) || _ignoredResourcePaths.contains(path)) { iterator.remove(); continue; } if (resource instanceof FileResource) { try (FileResource fileResource = (FileResource)resource) { classPath.put(path, fileResource.getFile()); appendProperty( analyzer, Constants.BUNDLE_CLASSPATH, path); } } } else if (_ignoredResourcePaths.contains(path)) { iterator.remove(); } } } protected void processImportPackageNames(Analyzer analyzer) { String packageName = MapUtil.getString( _parameters, Constants.IMPORT_PACKAGE); if (Validator.isNotNull(packageName)) { analyzer.setProperty(Constants.IMPORT_PACKAGE, packageName); } else { StringBundler sb = new StringBundler( (_importPackageParameters.size() * 4) + 1); for (Entry<String, Attrs> entry : _importPackageParameters.entrySet()) { String importPackageName = entry.getKey(); Attrs attrs = entry.getValue(); boolean containedInClasspath = false; for (Jar jar : analyzer.getClasspath()) { List<String> packages = jar.getPackages(); if (packages.contains(importPackageName)) { containedInClasspath = true; break; } } if (containedInClasspath) { continue; } sb.append(importPackageName); if (!attrs.isEmpty()) { sb.append(";"); sb.append(entry.getValue()); } sb.append(StringPool.COMMA); } sb.append("*;resolution:=\"optional\""); analyzer.setProperty(Constants.IMPORT_PACKAGE, sb.toString()); } } protected void processLiferayPortletXML() throws IOException { File file = new File(_pluginDir, "WEB-INF/liferay-portlet.xml"); if (!file.exists()) { return; } Document document = readDocument(file); Element rootElement = document.getRootElement(); for (Element element : rootElement.elements("portlet")) { Element strutsPathElement = element.element("struts-path"); if (strutsPathElement == null) { continue; } String strutsPath = strutsPathElement.getTextTrim(); if (!strutsPath.startsWith(StringPool.SLASH)) { strutsPath = StringPool.SLASH.concat(strutsPath); } strutsPathElement.setText( Portal.PATH_MODULE.substring(1) + _context + strutsPath); } formatDocument(file, document); } protected void processPackageNames(Analyzer analyzer) { processExportPackageNames(analyzer); processImportPackageNames(analyzer); } protected void processPluginPackagePropertiesExportImportPackages( Properties pluginPackageProperties) { if (pluginPackageProperties == null) { return; } String exportPackage = pluginPackageProperties.getProperty( Constants.EXPORT_PACKAGE); if (Validator.isNotNull(exportPackage)) { Parameters parameters = new Parameters(exportPackage); _exportPackageParameters.mergeWith(parameters, true); pluginPackageProperties.remove(Constants.EXPORT_PACKAGE); } String importPackage = pluginPackageProperties.getProperty( Constants.IMPORT_PACKAGE); if (Validator.isNotNull(importPackage)) { Parameters parameters = new Parameters(importPackage); _importPackageParameters.mergeWith(parameters, true); pluginPackageProperties.remove(Constants.IMPORT_PACKAGE); } } protected void processPropertiesDependencies( Analyzer analyzer, File file, String[] knownPropertyKeys) { if (!file.exists()) { return; } try (InputStream inputStream = new FileInputStream(file)) { Properties properties = new Properties(); properties.load(inputStream); if (properties.isEmpty()) { return; } for (String key : knownPropertyKeys) { String value = properties.getProperty(key); if (value == null) { continue; } value = value.trim(); processClass(analyzer, value); } } catch (Exception e) { // Ignore this case } } protected void processPropertiesDependencies( Analyzer analyzer, Path path, String suffix, String[] knownPropertyKeys) throws IOException { File file = path.toFile(); if (!file.isDirectory()) { return; } Stream<Path> pathStream = Files.walk(path); Stream<File> fileStream = pathStream.map(Path::toFile); fileStream.forEach( entry -> { String pathString = entry.getPath(); if (pathString.endsWith(suffix)) { processPropertiesDependencies( analyzer, entry, knownPropertyKeys); } }); } protected void processRequiredDeploymentContexts(Analyzer analyzer) { if (_pluginPackage == null) { return; } List<String> requiredDeploymentContexts = _pluginPackage.getRequiredDeploymentContexts(); if (ListUtil.isEmpty(requiredDeploymentContexts)) { return; } StringBundler sb = new StringBundler( (6 * requiredDeploymentContexts.size()) - 1); for (int i = 0; i < requiredDeploymentContexts.size(); i++) { String requiredDeploymentContext = requiredDeploymentContexts.get( i); sb.append(requiredDeploymentContext); sb.append(StringPool.SEMICOLON); sb.append(Constants.BUNDLE_VERSION_ATTRIBUTE); sb.append(StringPool.EQUAL); sb.append(_bundleVersion); if ((i + 1) < requiredDeploymentContexts.size()) { sb.append(StringPool.COMMA); } } analyzer.setProperty(Constants.REQUIRE_BUNDLE, sb.toString()); } protected void processServicePackageName(Resource resource) { try (InputStream inputStream = resource.openInputStream()) { Document document = UnsecureSAXReaderUtil.read(inputStream); Element rootElement = document.getRootElement(); _servicePackageName = rootElement.attributeValue("package-path"); String[] partialPackageNames = { "", ".exception", ".model", ".model.impl", ".service", ".service.base", ".service.http", ".service.impl", ".service.persistence", ".service.persistence.impl" }; for (String partialPackageName : partialPackageNames) { Parameters parameters = new Parameters( getVersionedServicePackageName(partialPackageName)); _exportPackageParameters.mergeWith(parameters, false); _importPackageParameters.mergeWith(parameters, false); } _importPackageParameters.add( "com.liferay.portal.osgi.web.wab.generator", _optionalAttrs); } catch (Exception e) { _log.error(e, e); } } protected void processTLDDependencies(Analyzer analyzer) throws IOException { File dir = new File(_pluginDir, "WEB-INF/tld"); if (!dir.exists() || !dir.isDirectory()) { return; } File[] files = dir.listFiles(new FileFilter(".*\\.tld")); for (File file : files) { String content = FileUtil.read(file); Matcher matcher = _tldPackagesPattern.matcher(content); while (matcher.find()) { String value = matcher.group(1); value = value.trim(); processClass(analyzer, value); } } } protected void processWebContextPath(Manifest manifest) { Attributes attributes = manifest.getMainAttributes(); attributes.putValue("Web-ContextPath", getWebContextPath()); } protected void processWebXML( Element element, List<Element> initParamElements, Class<?> clazz) { if (element == null) { return; } String elementText = element.getTextTrim(); if (!elementText.equals(clazz.getName())) { return; } for (Element initParamElement : initParamElements) { Element paramNameElement = initParamElement.element("param-name"); String paramNameValue = paramNameElement.getTextTrim(); if (!paramNameValue.equals(element.getName())) { continue; } Element paramValueElement = initParamElement.element("param-value"); element.setText(paramValueElement.getTextTrim()); initParamElement.detach(); return; } } protected void processWebXML(String path) throws IOException { File file = new File(_pluginDir, path); if (!file.exists()) { return; } Document document = readDocument(file); Element rootElement = document.getRootElement(); for (Element element : rootElement.elements("filter")) { Element filterClassElement = element.element("filter-class"); processWebXML( filterClassElement, element.elements("init-param"), PortalClassLoaderFilter.class); } for (Element element : rootElement.elements("servlet")) { Element servletClassElement = element.element("servlet-class"); processWebXML( servletClassElement, element.elements("init-param"), PortalClassLoaderServlet.class); } formatDocument(file, document); } protected void processXMLDependencies( Analyzer analyzer, File file, String xPathExpression) { if (!file.exists()) { return; } Document document = readDocument(file); if (!document.hasContent()) { return; } Element rootElement = document.getRootElement(); XPath xPath = SAXReaderUtil.createXPath(xPathExpression, _xsds); List<Node> nodes = xPath.selectNodes(rootElement); for (Node node : nodes) { String text = node.getText(); text = text.trim(); processClass(analyzer, text); } } protected void processXMLDependencies( Analyzer analyzer, Path path, String suffix, String xPathExpression) throws IOException { File file = path.toFile(); if (!file.isDirectory()) { return; } Stream<Path> pathStream = Files.walk(path); Stream<File> fileStream = pathStream.map(Path::toFile); fileStream.forEach( entry -> { String pathString = entry.getPath(); if (pathString.endsWith(suffix)) { processXMLDependencies(analyzer, entry, _XPATHS_SPRING); } }); } protected void processXMLDependencies( Analyzer analyzer, String fileName, String xPathExpression) { File file = new File(_pluginDir, fileName); processXMLDependencies(analyzer, file, xPathExpression); } protected Document readDocument(File file) { try { String content = FileUtil.read(file); return UnsecureSAXReaderUtil.read(content); } catch (Exception de) { return SAXReaderUtil.createDocument(); } } protected File transformToOSGiBundle(Jar jar) throws IOException { Builder analyzer = new Builder(); analyzer.setBase(_pluginDir); analyzer.setJar(jar); analyzer.setProperty("-jsp", "*.jsp,*.jspf"); analyzer.setProperty("Web-ContextPath", getWebContextPath()); Set<Object> plugins = analyzer.getPlugins(); plugins.add(new JspAnalyzerPlugin()); Properties pluginPackageProperties = getPluginPackageProperties(); if (pluginPackageProperties.containsKey("portal-dependency-jars") && _log.isWarnEnabled()) { _log.warn( "The property \"portal-dependency-jars\" is deprecated. " + "Specified JARs may not be included in the class path."); } processBundleVersion(analyzer); processBundleClasspath(analyzer, pluginPackageProperties); processBundleSymbolicName(analyzer); processExtraHeaders(analyzer); processPluginPackagePropertiesExportImportPackages( pluginPackageProperties); processBundleManifestVersion(analyzer); processLiferayPortletXML(); processWebXML("WEB-INF/web.xml"); processWebXML("WEB-INF/liferay-web.xml"); processDeclarativeReferences(analyzer); processExtraRequirements(); processPackageNames(analyzer); processRequiredDeploymentContexts(analyzer); _processExcludedJSPs(analyzer); analyzer.setProperties(pluginPackageProperties); try { jar = analyzer.build(); File outputFile = analyzer.getOutputFile(null); jar.write(outputFile); return outputFile; } catch (Exception e) { throw new IOException("Unable to calculate the manifest", e); } finally { analyzer.close(); } } protected void writeAutoDeployedWar(File pluginDir) { File dir = new File( PropsValues. MODULE_FRAMEWORK_WEB_GENERATOR_GENERATED_WABS_STORE_DIR); dir.mkdirs(); StringBundler sb = new StringBundler(5); String name = _file.getName(); sb.append(name.substring(0, name.lastIndexOf(StringPool.PERIOD))); sb.append(StringPool.DASH); Format format = FastDateFormatFactoryUtil.getSimpleDateFormat( PropsValues.INDEX_DATE_FORMAT_PATTERN); sb.append(format.format(new Date())); sb.append(".autodeployed."); sb.append(FileUtil.getExtension(name)); try (Jar jar = new Jar(pluginDir)) { jar.write(new File(dir, sb.toString())); } catch (Exception e) { _log.error("Unable to write JAR file for " + pluginDir, e); } } protected void writeGeneratedWab(File file) throws IOException { File dir = new File( PropsValues. MODULE_FRAMEWORK_WEB_GENERATOR_GENERATED_WABS_STORE_DIR); dir.mkdirs(); StringBundler sb = new StringBundler(5); String name = _file.getName(); sb.append(name.substring(0, name.lastIndexOf(StringPool.PERIOD))); sb.append(StringPool.DASH); Format format = FastDateFormatFactoryUtil.getSimpleDateFormat( PropsValues.INDEX_DATE_FORMAT_PATTERN); sb.append(format.format(new Date())); sb.append(".wab."); sb.append(FileUtil.getExtension(name)); FileUtil.copyFile(file, new File(dir, sb.toString())); } private void _processExcludedJSPs(Analyzer analyzer) { File file = new File(_pluginDir, "/WEB-INF/liferay-hook.xml"); if (!file.exists()) { return; } Document document = readDocument(file); if (!document.hasContent()) { return; } Element rootElement = document.getRootElement(); List<Node> nodes = rootElement.selectNodes("//custom-jsp-dir"); String value = analyzer.getProperty("-jsp"); for (Node node : nodes) { String text = node.getText(); if (text.startsWith("/")) { text = text.substring(1); } value = "!" + text + "/*," + value; } analyzer.setProperty("-jsp", value); } /** * Used diagnostic testing. */ private static final boolean _AUTODEPLOYED_WARS_STORE = GetterUtil.getBoolean( PropsUtil.get( "module.framework.web.generator.autodeployed.wars.store")); private static final String[] _KNOWN_PROPERTY_KEYS = {"jdbc.driverClassName"}; private static final String _XPATHS_HBM = StringUtil.merge( new String[] { "//class/@name", "//id/@access", "//import/@class", "//property/@type" }, "|"); private static final String _XPATHS_HOOK = StringUtil.merge( new String[] { "//indexer-post-processor-impl", "//service-impl", "//servlet-filter-impl", "//struts-action-impl" }, "|"); private static final String _XPATHS_JAVAEE = StringUtil.merge( new String[] { "//j2ee:filter-class", "//j2ee:listener-class", "//j2ee:servlet-class", "//javaee:filter-class", "//javaee:listener-class", "//javaee:servlet-class" }, "|"); private static final String _XPATHS_LIFERAY = StringUtil.merge( new String[] { "//asset-renderer-factory", "//atom-collection-adapter", "//configuration-action-class", "//control-panel-entry-class", "//custom-attributes-display", "//friendly-url-mapper-class", "//indexer-class", "//open-search-class", "//permission-propagator", "//poller-processor-class", "//pop-message-listener-class", "//portlet-data-handler-class", "//portlet-layout-listener-class", "//portlet-url-class", "//social-activity-interpreter-class", "//social-request-interpreter-class", "//url-encoder-class", "//webdav-storage-class", "//workflow-handler", "//xml-rpc-method-class" }, "|"); private static final String _XPATHS_PORTLET = StringUtil.merge( new String[] { "//portlet2:filter-class", "//portlet2:listener-class", "//portlet2:portlet-class", "//portlet2:resource-bundle" }, "|"); private static final String _XPATHS_SPRING = StringUtil.merge( new String[] { "//beans:bean/@class", "//beans:*/@value-type", "//aop:*/@implement-interface", "//aop:*/@default-impl", "//context:load-time-weaver/@weaver-class", "//jee:jndi-lookup/@expected-type", "//jee:jndi-lookup/@proxy-interface", "//jee:remote-slsb/@ejbType", "//jee:*/@business-interface", "//lang:*/@script-interfaces", "//osgi:*/@interface", "//gemini-blueprint:*/@interface", "//blueprint:*/@interface", "//blueprint:*/@class", "//util:list/@list-class", "//util:set/@set-class", "//util:map/@map-class", "//webflow-config:*/@class" }, "|"); private static final Log _log = LogFactoryUtil.getLog(WabProcessor.class); private static final Attrs _optionalAttrs = new Attrs(); private static final Map<String, String> _xsds = new ConcurrentHashMap<>(); static { _optionalAttrs.put("resolution:", "optional"); _xsds.put("aop", "http://www.springframework.org/schema/aop"); _xsds.put("beans", "http://www.springframework.org/schema/beans"); _xsds.put("blueprint", "http://www.osgi.org/xmlns/blueprint/v1.0.0"); _xsds.put("context", "http://www.springframework.org/schema/context"); _xsds.put( "gemini-blueprint", "http://www.eclipse.org/gemini/blueprint/schema/blueprint"); _xsds.put("j2ee", "http://java.sun.com/xml/ns/j2ee"); _xsds.put("javaee", "http://java.sun.com/xml/ns/javaee"); _xsds.put("jee", "http://www.springframework.org/schema/jee"); _xsds.put("jms", "http://www.springframework.org/schema/jms"); _xsds.put("lang", "http://www.springframework.org/schema/lang"); _xsds.put("osgi", "http://www.springframework.org/schema/osgi"); _xsds.put( "osgi-compendium", "http://www.springframework.org/schema/osgi-compendium"); _xsds.put( "portlet2", "http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"); _xsds.put("tool", "http://www.springframework.org/schema/tool"); _xsds.put("tx", "http://www.springframework.org/schema/tx"); _xsds.put("util", "http://www.springframework.org/schema/util"); _xsds.put( "webflow-config", "http://www.springframework.org/schema/webflow-config"); _xsds.put("xsl", "http://www.w3.org/1999/XSL/Transform"); } private String _bundleVersion; private String _context; private final Parameters _exportPackageParameters = new Parameters(); private final File _file; private final Set<String> _ignoredResourcePaths = SetUtil.fromArray( PropsValues.MODULE_FRAMEWORK_WEB_GENERATOR_EXCLUDED_PATHS); private final Parameters _importPackageParameters = new Parameters(); private final Map<String, String[]> _parameters; private File _pluginDir; private PluginPackage _pluginPackage; private String _servicePackageName; private final Pattern _tldPackagesPattern = Pattern.compile( "<[^>]+?-class>\\p{Space}*?(.*?)\\p{Space}*?</[^>]+?-class>"); private final Pattern _versionMavenPattern = Pattern.compile( "(\\d{1,9})(\\.(\\d{1,9})(\\.(\\d{1,9})(-([-_\\da-zA-Z]+))?)?)?"); }