1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portal.tools.deploy;
21  
22  import com.liferay.portal.deploy.DeployUtil;
23  import com.liferay.portal.kernel.deploy.auto.AutoDeployException;
24  import com.liferay.portal.kernel.log.Log;
25  import com.liferay.portal.kernel.log.LogFactoryUtil;
26  import com.liferay.portal.kernel.plugin.PluginPackage;
27  import com.liferay.portal.kernel.util.FileUtil;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.HttpUtil;
30  import com.liferay.portal.kernel.util.PropertiesUtil;
31  import com.liferay.portal.kernel.util.ServerDetector;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.util.StringUtil;
34  import com.liferay.portal.kernel.util.Time;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.kernel.xml.Document;
37  import com.liferay.portal.kernel.xml.Element;
38  import com.liferay.portal.kernel.xml.SAXReaderUtil;
39  import com.liferay.portal.plugin.PluginPackageUtil;
40  import com.liferay.portal.tools.WebXMLBuilder;
41  import com.liferay.portal.util.InitUtil;
42  import com.liferay.portal.util.PortalUtil;
43  import com.liferay.portal.util.PrefsPropsUtil;
44  import com.liferay.portal.util.PropsKeys;
45  import com.liferay.portal.util.PropsUtil;
46  import com.liferay.portal.util.PropsValues;
47  import com.liferay.util.License;
48  import com.liferay.util.SystemProperties;
49  import com.liferay.util.ant.CopyTask;
50  import com.liferay.util.ant.DeleteTask;
51  import com.liferay.util.ant.ExpandTask;
52  import com.liferay.util.ant.UpToDateTask;
53  import com.liferay.util.ant.WarTask;
54  import com.liferay.util.xml.XMLFormatter;
55  
56  import com.sun.portal.portletcontainer.warupdater.PortletWarUpdater;
57  
58  import java.io.File;
59  import java.io.FileInputStream;
60  import java.io.IOException;
61  import java.io.InputStream;
62  
63  import java.util.ArrayList;
64  import java.util.List;
65  import java.util.Map;
66  import java.util.Properties;
67  import java.util.zip.ZipEntry;
68  import java.util.zip.ZipFile;
69  
70  import org.apache.oro.io.GlobFilenameFilter;
71  
72  /**
73   * <a href="BaseDeployer.java.html"><b><i>View Source</i></b></a>
74   *
75   * @author Brian Wing Shun Chan
76   * @author Sandeep Soni
77   *
78   */
79  public class BaseDeployer {
80  
81      public static final String DEPLOY_TO_PREFIX = "DEPLOY_TO__";
82  
83      public static void main(String[] args) {
84          InitUtil.initWithSpring();
85  
86          List<String> wars = new ArrayList<String>();
87          List<String> jars = new ArrayList<String>();
88  
89          for (String arg : args) {
90              String fileName = arg.toLowerCase();
91  
92              if (fileName.endsWith(".war")) {
93                  wars.add(arg);
94              }
95              else if (fileName.endsWith(".jar")) {
96                  jars.add(arg);
97              }
98          }
99  
100         new BaseDeployer(wars, jars);
101     }
102 
103     protected BaseDeployer() {
104     }
105 
106     protected BaseDeployer(List<String> wars, List<String> jars) {
107         baseDir = System.getProperty("deployer.base.dir");
108         destDir = System.getProperty("deployer.dest.dir");
109         appServerType = System.getProperty("deployer.app.server.type");
110         portletTaglibDTD = System.getProperty("deployer.portlet.taglib.dtd");
111         portletExtTaglibDTD = System.getProperty(
112             "deployer.portlet.ext.taglib.dtd");
113         securityTaglibDTD = System.getProperty("deployer.security.taglib.dtd");
114         themeTaglibDTD = System.getProperty("deployer.theme.taglib.dtd");
115         uiTaglibDTD = System.getProperty("deployer.ui.taglib.dtd");
116         utilTaglibDTD = System.getProperty("deployer.util.taglib.dtd");
117         unpackWar = GetterUtil.getBoolean(
118             System.getProperty("deployer.unpack.war"), true);
119         filePattern = System.getProperty("deployer.file.pattern");
120         jbossPrefix = GetterUtil.getString(
121             System.getProperty("deployer.jboss.prefix"));
122         tomcatLibDir = System.getProperty("deployer.tomcat.lib.dir");
123         this.wars = wars;
124         this.jars = jars;
125 
126         checkArguments();
127 
128         try {
129             deploy();
130         }
131         catch (Exception e) {
132             e.printStackTrace();
133         }
134     }
135 
136     protected void checkArguments() {
137         if (Validator.isNull(baseDir)) {
138             throw new IllegalArgumentException(
139                 "The system property deployer.base.dir is not set");
140         }
141 
142         if (Validator.isNull(destDir)) {
143             throw new IllegalArgumentException(
144                 "The system property deployer.dest.dir is not set");
145         }
146 
147         if (Validator.isNull(appServerType)) {
148             throw new IllegalArgumentException(
149                 "The system property deployer.app.server.type is not set");
150         }
151 
152         if (!appServerType.startsWith(ServerDetector.GERONIMO_ID) &&
153             !appServerType.startsWith(ServerDetector.GLASSFISH_ID) &&
154             !appServerType.startsWith(ServerDetector.JBOSS_ID) &&
155             !appServerType.startsWith(ServerDetector.JONAS_ID) &&
156             !appServerType.equals(ServerDetector.JETTY_ID) &&
157             !appServerType.equals(ServerDetector.OC4J_ID) &&
158             !appServerType.equals(ServerDetector.RESIN_ID) &&
159             !appServerType.equals(ServerDetector.TOMCAT_ID) &&
160             !appServerType.equals(ServerDetector.WEBLOGIC_ID) &&
161             !appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
162 
163             throw new IllegalArgumentException(
164                 appServerType + " is not a valid application server type");
165         }
166 
167         if (appServerType.startsWith(ServerDetector.GLASSFISH_ID) ||
168             appServerType.equals(ServerDetector.WEBLOGIC_ID)) {
169 
170             unpackWar = false;
171         }
172 
173         if (Validator.isNotNull(jbossPrefix) &&
174             !Validator.isNumber(jbossPrefix)) {
175 
176             jbossPrefix = "1";
177         }
178     }
179 
180     protected void copyDependencyXml(String fileName, String targetDir)
181         throws Exception {
182 
183         copyDependencyXml(fileName, targetDir, null);
184     }
185 
186     protected void copyDependencyXml(
187             String fileName, String targetDir, Map<String, String> filterMap)
188         throws Exception {
189 
190         copyDependencyXml(fileName, targetDir, filterMap, false);
191     }
192 
193     protected void copyDependencyXml(
194             String fileName, String targetDir, Map<String, String> filterMap,
195             boolean overwrite)
196         throws Exception {
197 
198         File file = new File(DeployUtil.getResourcePath(fileName));
199         File targetFile = new File(targetDir + "/" + fileName);
200 
201         if (!targetFile.exists()) {
202             CopyTask.copyFile(
203                 file, new File(targetDir), filterMap, overwrite, true);
204         }
205     }
206 
207     protected void copyJars(File srcFile, PluginPackage pluginPackage)
208         throws Exception {
209 
210         for (int i = 0; i < jars.size(); i++) {
211             String jarFullName = jars.get(i);
212             String jarName = jarFullName.substring(
213                 jarFullName.lastIndexOf("/") + 1, jarFullName.length());
214 
215             if ((!appServerType.equals(ServerDetector.TOMCAT_ID)) ||
216                 (appServerType.equals(ServerDetector.TOMCAT_ID) &&
217                     !jarFullName.equals("util-java.jar"))) {
218 
219                 FileUtil.copyFile(
220                     jarFullName, srcFile + "/WEB-INF/lib/" + jarName, true);
221             }
222         }
223 
224         FileUtil.delete(srcFile + "/WEB-INF/lib/util-jsf.jar");
225     }
226 
227     protected void copyPortalDependencies(File srcFile) throws Exception {
228         Properties properties = getPluginPackageProperties(srcFile);
229 
230         if (properties == null) {
231             return;
232         }
233 
234         // jars
235 
236         String[] portalJars = StringUtil.split(
237             properties.getProperty(
238                 "portal-dependency-jars",
239                 properties.getProperty("portal.dependency.jars")));
240 
241         for (int i = 0; i < portalJars.length; i++) {
242             String portalJar = portalJars[i].trim();
243 
244             if (_log.isDebugEnabled()) {
245                 _log.debug("Copy portal JAR " + portalJar);
246             }
247 
248             try {
249                 String portalJarPath = PortalUtil.getPortalLibDir() + portalJar;
250 
251                 FileUtil.copyFile(
252                     portalJarPath, srcFile + "/WEB-INF/lib/" + portalJar, true);
253             }
254             catch (Exception e) {
255                 _log.error("Unable to copy portal JAR " + portalJar, e);
256             }
257         }
258 
259         // tlds
260 
261         String[] portalTlds = StringUtil.split(
262             properties.getProperty(
263                 "portal-dependency-tlds",
264                 properties.getProperty("portal.dependency.tlds")));
265 
266         for (int i = 0; i < portalTlds.length; i++) {
267             String portalTld = portalTlds[i].trim();
268 
269             if (_log.isDebugEnabled()) {
270                 _log.debug("Copy portal TLD " + portalTld);
271             }
272 
273             try {
274                 String portalTldPath = DeployUtil.getResourcePath(portalTld);
275 
276                 FileUtil.copyFile(
277                     portalTldPath, srcFile + "/WEB-INF/tld/" + portalTld, true);
278             }
279             catch (Exception e) {
280                 _log.error("Unable to copy portal TLD " + portalTld, e);
281             }
282         }
283 
284         // commons-logging*.jar
285 
286         File pluginLibDir = new File(srcFile + "/WEB-INF/lib/");
287 
288         String[] commonsLoggingJars = pluginLibDir.list(
289             new GlobFilenameFilter("commons-logging*.jar"));
290 
291         if ((commonsLoggingJars == null) || (commonsLoggingJars.length == 0)) {
292             String portalJarPath =
293                 PortalUtil.getPortalLibDir() + "commons-logging.jar";
294 
295             FileUtil.copyFile(
296                 portalJarPath, srcFile + "/WEB-INF/lib/commons-logging.jar",
297                 true);
298         }
299 
300         // log4j*.jar
301 
302         String[] log4jJars = pluginLibDir.list(
303             new GlobFilenameFilter("log4j*.jar"));
304 
305         if ((log4jJars == null) || (log4jJars.length == 0)) {
306             String portalJarPath = PortalUtil.getPortalLibDir() + "log4j.jar";
307 
308             FileUtil.copyFile(
309                 portalJarPath, srcFile + "/WEB-INF/lib/log4j.jar", true);
310         }
311     }
312 
313     protected void copyProperties(File srcFile, PluginPackage pluginPackage)
314         throws Exception {
315 
316         copyDependencyXml("log4j.properties", srcFile + "/WEB-INF/classes");
317         copyDependencyXml("logging.properties", srcFile + "/WEB-INF/classes");
318     }
319 
320     protected void copyTlds(File srcFile, PluginPackage pluginPackage)
321         throws Exception {
322 
323         if (Validator.isNotNull(portletTaglibDTD)) {
324             FileUtil.copyFile(
325                 portletTaglibDTD, srcFile + "/WEB-INF/tld/liferay-portlet.tld",
326                 true);
327         }
328 
329         if (Validator.isNotNull(portletExtTaglibDTD)) {
330             FileUtil.copyFile(
331                 portletExtTaglibDTD,
332                 srcFile + "/WEB-INF/tld/liferay-portlet-ext.tld", true);
333         }
334 
335         if (Validator.isNotNull(securityTaglibDTD)) {
336             FileUtil.copyFile(
337                 securityTaglibDTD,
338                 srcFile + "/WEB-INF/tld/liferay-security.tld", true);
339         }
340 
341         if (Validator.isNotNull(themeTaglibDTD)) {
342             FileUtil.copyFile(
343                 themeTaglibDTD, srcFile + "/WEB-INF/tld/liferay-theme.tld",
344                 true);
345         }
346 
347         if (Validator.isNotNull(uiTaglibDTD)) {
348             FileUtil.copyFile(
349                 uiTaglibDTD, srcFile + "/WEB-INF/tld/liferay-ui.tld", true);
350         }
351 
352         if (Validator.isNotNull(utilTaglibDTD)) {
353             FileUtil.copyFile(
354                 utilTaglibDTD, srcFile + "/WEB-INF/tld/liferay-util.tld", true);
355         }
356     }
357 
358     protected void copyXmls(
359             File srcFile, String displayName, PluginPackage pluginPackage)
360         throws Exception {
361 
362         if (appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
363             copyDependencyXml("geronimo-web.xml", srcFile + "/WEB-INF");
364         }
365         else if (appServerType.equals(ServerDetector.WEBLOGIC_ID)) {
366             copyDependencyXml("weblogic.xml", srcFile + "/WEB-INF");
367         }
368 
369         copyDependencyXml("web.xml", srcFile + "/WEB-INF");
370     }
371 
372     protected void deploy() throws Exception {
373         try {
374             File baseDirFile = new File(baseDir);
375 
376             File[] files = baseDirFile.listFiles();
377 
378             if (files == null) {
379                 return;
380             }
381 
382             files = FileUtil.sortFiles(files);
383 
384             for (int i = 0; i < files.length; i++) {
385                 File srcFile = files[i];
386 
387                 String fileName = srcFile.getName().toLowerCase();
388 
389                 boolean deploy = false;
390 
391                 if (fileName.endsWith(".war") || fileName.endsWith(".zip")) {
392                     deploy = true;
393 
394                     if (wars.size() > 0) {
395                         if (!wars.contains(srcFile.getName())) {
396                             deploy = false;
397                         }
398                     }
399                     else if (Validator.isNotNull(filePattern)) {
400                         if (!StringUtil.matches(fileName, filePattern)) {
401                             deploy = false;
402                         }
403                     }
404                 }
405 
406                 if (deploy) {
407                     deployFile(srcFile);
408                 }
409             }
410         }
411         catch (Exception e) {
412             e.printStackTrace();
413         }
414     }
415 
416     protected void deployDirectory(
417             File srcFile, String displayName, boolean override,
418             PluginPackage pluginPackage)
419         throws Exception {
420 
421         deployDirectory(
422             srcFile, null, null, displayName, override, pluginPackage);
423     }
424 
425     protected void deployDirectory(
426             File srcFile, File mergeDir, File deployDir, String displayName,
427             boolean overwrite, PluginPackage pluginPackage)
428         throws Exception {
429 
430         if ((PropsValues.PORTLET_CONTAINER_IMPL_SUN) &&
431             (this instanceof PortletDeployer)) {
432 
433             Properties properties = new Properties();
434 
435             properties.setProperty(PortletWarUpdater.ADD_WEB_XML, "true");
436 
437             PortletWarUpdater portletWarUpdater = new PortletWarUpdater(
438                 properties);
439 
440             portletWarUpdater.preparePortlet(displayName, srcFile);
441         }
442 
443         rewriteFiles(srcFile);
444 
445         mergeDirectory(mergeDir, srcFile);
446 
447         processPluginPackageProperties(srcFile, displayName, pluginPackage);
448 
449         copyJars(srcFile, pluginPackage);
450         copyProperties(srcFile, pluginPackage);
451         copyTlds(srcFile, pluginPackage);
452         copyXmls(srcFile, displayName, pluginPackage);
453         copyPortalDependencies(srcFile);
454 
455         updateGeronimoWebXml(srcFile, displayName, pluginPackage);
456 
457         File webXml = new File(srcFile + "/WEB-INF/web.xml");
458 
459         updateWebXml(webXml, srcFile, displayName, pluginPackage);
460 
461         if ((deployDir == null) || baseDir.equals(destDir)) {
462             return;
463         }
464 
465         updateDeployDirectory(srcFile);
466 
467         String excludes = StringPool.BLANK;
468 
469         if (appServerType.startsWith("jboss")) {
470             excludes += "**/WEB-INF/lib/log4j.jar,";
471         }
472         else if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
473             String[] libs = FileUtil.listFiles(tomcatLibDir);
474 
475             for (int i = 0; i < libs.length; i++) {
476                 excludes += "**/WEB-INF/lib/" + libs[i] + ",";
477             }
478 
479             File contextXml = new File(srcFile + "/META-INF/context.xml");
480 
481             if (contextXml.exists()) {
482                 String content = FileUtil.read(contextXml);
483 
484                 if (content.indexOf(_PORTAL_CLASS_LOADER) != -1) {
485                     excludes += "**/WEB-INF/lib/util-bridges.jar,";
486                     excludes += "**/WEB-INF/lib/util-java.jar,";
487                     excludes += "**/WEB-INF/lib/util-taglib.jar,";
488                 }
489             }
490 
491             try {
492 
493                 // LEP-2990
494 
495                 Class.forName("javax.el.ELContext");
496 
497                 excludes += "**/WEB-INF/lib/el-api.jar,";
498             }
499             catch (ClassNotFoundException cnfe) {
500             }
501         }
502 
503         if (!unpackWar || appServerType.equals("websphere")) {
504             File tempDir = new File(
505                 SystemProperties.get(SystemProperties.TMP_DIR) +
506                     File.separator + Time.getTimestamp());
507 
508             WarTask.war(srcFile, tempDir, "WEB-INF/web.xml", webXml);
509 
510             if (isJEEDeploymentEnabled()) {
511                 File tempWarDir = new File(
512                     tempDir.getParent(), deployDir.getName());
513 
514                 if (tempWarDir.exists()) {
515                     tempWarDir.delete();
516                 }
517 
518                 if (!tempDir.renameTo(tempWarDir)) {
519                     tempWarDir = tempDir;
520                 }
521 
522                 DeploymentHandler deploymentHandler = getDeploymentHandler();
523 
524                 deploymentHandler.deploy(tempWarDir, displayName);
525 
526                 deploymentHandler.releaseDeploymentManager();
527 
528                 DeleteTask.deleteDirectory(tempWarDir);
529             }
530             else {
531                 if (!tempDir.renameTo(deployDir)) {
532                     WarTask.war(srcFile, deployDir, "WEB-INF/web.xml", webXml);
533                 }
534 
535                 DeleteTask.deleteDirectory(tempDir);
536             }
537         }
538         else {
539 
540             // The deployer might only copy files that have been modified.
541             // However, the deployer always copies and overwrites web.xml after
542             // the other files have been copied because application servers
543             // usually detect that a WAR has been modified based on the web.xml
544             // timestamp.
545 
546             excludes += "**/WEB-INF/web.xml";
547 
548             CopyTask.copyDirectory(
549                 srcFile, deployDir, StringPool.BLANK, excludes, overwrite,
550                 true);
551 
552             CopyTask.copyDirectory(
553                 srcFile, deployDir, "**/WEB-INF/web.xml", StringPool.BLANK,
554                 true, false);
555 
556             if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
557 
558                 // See org.apache.catalina.startup.HostConfig to see how Tomcat
559                 // checks to make sure that web.xml was modified 5 seconds after
560                 // WEB-INF
561 
562                 File deployWebXml = new File(deployDir + "/WEB-INF/web.xml");
563 
564                 deployWebXml.setLastModified(
565                     System.currentTimeMillis() + (Time.SECOND * 6));
566             }
567         }
568     }
569 
570     protected void deployFile(File srcFile) throws Exception {
571         PluginPackage pluginPackage = readPluginPackage(srcFile);
572 
573         if (_log.isInfoEnabled()) {
574             _log.info("Deploying " + srcFile.getName());
575         }
576 
577         String deployDir = null;
578         String displayName = null;
579         boolean overwrite = false;
580         String preliminaryContext = null;
581 
582         // File names starting with DEPLOY_TO_PREFIX should use the filename
583         // after the prefix as the deployment context
584 
585         if (srcFile.getName().startsWith(DEPLOY_TO_PREFIX)) {
586             displayName = srcFile.getName().substring(
587                 DEPLOY_TO_PREFIX.length(), srcFile.getName().length() - 4);
588 
589             overwrite = true;
590             preliminaryContext = displayName;
591         }
592 
593         if (preliminaryContext == null) {
594             preliminaryContext = getDisplayName(srcFile);
595         }
596 
597         if (pluginPackage != null) {
598             if (!PluginPackageUtil.isCurrentVersionSupported(
599                     pluginPackage.getLiferayVersions())) {
600 
601                 throw new AutoDeployException(
602                     srcFile.getName() +
603                         " does not support this version of Liferay");
604             }
605 
606             if (displayName == null) {
607                 displayName = pluginPackage.getRecommendedDeploymentContext();
608             }
609 
610             if (Validator.isNull(displayName)) {
611                 displayName = getDisplayName(srcFile);
612             }
613 
614             pluginPackage.setContext(displayName);
615 
616             PluginPackageUtil.updateInstallingPluginPackage(
617                 preliminaryContext, pluginPackage);
618         }
619 
620         if (Validator.isNotNull(displayName)) {
621             deployDir = displayName + ".war";
622         }
623         else {
624             deployDir = srcFile.getName();
625             displayName = getDisplayName(srcFile);
626         }
627 
628         if (appServerType.startsWith(ServerDetector.JBOSS_ID)) {
629             deployDir = jbossPrefix + deployDir;
630         }
631         else if (appServerType.equals(ServerDetector.JETTY_ID) ||
632                  appServerType.equals(ServerDetector.OC4J_ID) ||
633                  appServerType.equals(ServerDetector.RESIN_ID) ||
634                  appServerType.equals(ServerDetector.TOMCAT_ID)) {
635 
636             if (unpackWar) {
637                 deployDir = deployDir.substring(0, deployDir.length() - 4);
638             }
639         }
640 
641         deployDir = destDir + "/" + deployDir;
642 
643         File deployDirFile = new File(deployDir);
644 
645         try {
646             PluginPackage previousPluginPackage =
647                 readPluginPackage(deployDirFile);
648 
649             if ((pluginPackage != null) && (previousPluginPackage != null)) {
650                 if (_log.isInfoEnabled()) {
651                     String name = pluginPackage.getName();
652                     String previousVersion = previousPluginPackage.getVersion();
653                     String version = pluginPackage.getVersion();
654 
655                     _log.info(
656                         "Updating " + name + " from version " +
657                             previousVersion + " to version " + version);
658                 }
659 
660                 if (pluginPackage.isLaterVersionThan(
661                     previousPluginPackage)) {
662 
663                     overwrite = true;
664                 }
665             }
666 
667             File mergeDirFile = new File(
668                 srcFile.getParent() + "/merge/" + srcFile.getName());
669 
670             if (srcFile.isDirectory()) {
671                 deployDirectory(
672                     srcFile, mergeDirFile, deployDirFile, displayName,
673                     overwrite, pluginPackage);
674             }
675             else {
676                 boolean deployed = deployFile(
677                     srcFile, mergeDirFile, deployDirFile, displayName,
678                     overwrite, pluginPackage);
679 
680                 if (!deployed) {
681                     String context = preliminaryContext;
682 
683                     if (pluginPackage != null) {
684                         context = pluginPackage.getContext();
685                     }
686 
687                     PluginPackageUtil.endPluginPackageInstallation(context);
688                 }
689             }
690         }
691         catch (Exception e) {
692             if (pluginPackage != null) {
693                 PluginPackageUtil.endPluginPackageInstallation(
694                     pluginPackage.getContext());
695             }
696 
697             throw e;
698         }
699     }
700 
701     protected boolean deployFile(
702             File srcFile, File mergeDir, File deployDir, String displayName,
703             boolean overwrite, PluginPackage pluginPackage)
704         throws Exception {
705 
706         boolean undeployOnRedeploy = false;
707 
708         try {
709             undeployOnRedeploy = PrefsPropsUtil.getBoolean(
710                 PropsKeys.HOT_UNDEPLOY_ON_REDEPLOY,
711                 PropsValues.HOT_UNDEPLOY_ON_REDEPLOY);
712         }
713         catch (Exception e) {
714 
715             // This will only happen when running the deploy tool in Ant in the
716             // classical way where the WAR file is actually massaged and
717             // packaged.
718 
719         }
720 
721         if (undeployOnRedeploy) {
722             DeployUtil.undeploy(appServerType, deployDir);
723         }
724 
725         if (!overwrite && UpToDateTask.isUpToDate(srcFile, deployDir)) {
726             if (_log.isInfoEnabled()) {
727                 _log.info(deployDir + " is already up to date");
728             }
729 
730             return false;
731         }
732 
733         File tempDir = new File(
734             SystemProperties.get(SystemProperties.TMP_DIR) + File.separator +
735                 Time.getTimestamp());
736 
737         ExpandTask.expand(srcFile, tempDir);
738 
739         deployDirectory(
740             tempDir, mergeDir, deployDir, displayName, overwrite,
741             pluginPackage);
742 
743         DeleteTask.deleteDirectory(tempDir);
744 
745         return true;
746     }
747 
748     protected String downloadJar(String jar) throws Exception {
749         String tmpDir = SystemProperties.get(SystemProperties.TMP_DIR);
750 
751         File file = new File(
752             tmpDir + "/liferay/com/liferay/portal/deploy/dependencies/" +
753                 jar);
754 
755         if (!file.exists()) {
756             synchronized (this) {
757                 String url = PropsUtil.get(
758                     PropsKeys.LIBRARY_DOWNLOAD_URL + jar);
759 
760                 if (_log.isInfoEnabled()) {
761                     _log.info("Downloading library from " + url);
762                 }
763 
764                 byte[] bytes = HttpUtil.URLtoByteArray(url);
765 
766                 FileUtil.write(file, bytes);
767             }
768         }
769 
770         return FileUtil.getAbsolutePath(file);
771     }
772 
773     protected String getDisplayName(File srcFile) {
774         String displayName = srcFile.getName();
775 
776         if (StringUtil.endsWith(displayName, ".war") ||
777             StringUtil.endsWith(displayName, ".xml")) {
778 
779             displayName = displayName.substring(0, displayName.length() - 4);
780         }
781 
782         if (appServerType.startsWith("jboss") &&
783             Validator.isNotNull(jbossPrefix) &&
784             displayName.startsWith(jbossPrefix)) {
785 
786             displayName = displayName.substring(1, displayName.length());
787         }
788 
789         return displayName;
790     }
791 
792     protected DeploymentHandler getDeploymentHandler() {
793         String prefix = "auto.deploy." + ServerDetector.getServerId() + ".jee.";
794 
795         String dmId = PropsUtil.get(prefix + "dm.id");
796         String dmUser =  PropsUtil.get(prefix + "dm.user");
797         String dmPassword =  PropsUtil.get(prefix + "dm.passwd");
798         String dfClassName = PropsUtil.get(prefix + "df.classname");
799 
800         return new DeploymentHandler(dmId, dmUser, dmPassword, dfClassName);
801     }
802 
803     protected String getExtraContent(
804             double webXmlVersion, File srcFile, String displayName)
805         throws Exception {
806 
807         StringBuilder sb = new StringBuilder();
808 
809         sb.append("<display-name>");
810         sb.append(displayName);
811         sb.append("</display-name>");
812 
813         File serviceXml = new File(srcFile + "/WEB-INF/service.xml");
814 
815         if (serviceXml.exists()) {
816             sb.append("<listener>");
817             sb.append("<listener-class>");
818             sb.append("com.liferay.portal.kernel.spring.context.");
819             sb.append("PortletContextLoaderListener");
820             sb.append("</listener-class>");
821             sb.append("</listener>");
822         }
823 
824         boolean hasTaglib = false;
825 
826         if (Validator.isNotNull(portletTaglibDTD) ||
827             Validator.isNotNull(portletExtTaglibDTD) ||
828             Validator.isNotNull(securityTaglibDTD) ||
829             Validator.isNotNull(themeTaglibDTD) ||
830             Validator.isNotNull(uiTaglibDTD) ||
831             Validator.isNotNull(utilTaglibDTD)) {
832 
833             hasTaglib = true;
834         }
835 
836         if (hasTaglib && (webXmlVersion > 2.3)) {
837             sb.append("<jsp-config>");
838         }
839 
840         if (Validator.isNotNull(portletTaglibDTD)) {
841             sb.append("<taglib>");
842             sb.append(
843                 "<taglib-uri>http://java.sun.com/portlet_2_0</taglib-uri>");
844             sb.append("<taglib-location>");
845             sb.append("/WEB-INF/tld/liferay-portlet.tld");
846             sb.append("</taglib-location>");
847             sb.append("</taglib>");
848         }
849 
850         if (Validator.isNotNull(portletExtTaglibDTD)) {
851             sb.append("<taglib>");
852             sb.append("<taglib-uri>");
853             sb.append("http://liferay.com/tld/portlet");
854             sb.append("</taglib-uri>");
855             sb.append("<taglib-location>");
856             sb.append("/WEB-INF/tld/liferay-portlet-ext.tld");
857             sb.append("</taglib-location>");
858             sb.append("</taglib>");
859         }
860 
861         if (Validator.isNotNull(securityTaglibDTD)) {
862             sb.append("<taglib>");
863             sb.append("<taglib-uri>");
864             sb.append("http://liferay.com/tld/security");
865             sb.append("</taglib-uri>");
866             sb.append("<taglib-location>");
867             sb.append("/WEB-INF/tld/liferay-security.tld");
868             sb.append("</taglib-location>");
869             sb.append("</taglib>");
870         }
871 
872         if (Validator.isNotNull(themeTaglibDTD)) {
873             sb.append("<taglib>");
874             sb.append("<taglib-uri>http://liferay.com/tld/theme</taglib-uri>");
875             sb.append("<taglib-location>");
876             sb.append("/WEB-INF/tld/liferay-theme.tld");
877             sb.append("</taglib-location>");
878             sb.append("</taglib>");
879         }
880 
881         if (Validator.isNotNull(uiTaglibDTD)) {
882             sb.append("<taglib>");
883             sb.append("<taglib-uri>http://liferay.com/tld/ui</taglib-uri>");
884             sb.append("<taglib-location>");
885             sb.append("/WEB-INF/tld/liferay-ui.tld");
886             sb.append("</taglib-location>");
887             sb.append("</taglib>");
888         }
889 
890         if (Validator.isNotNull(utilTaglibDTD)) {
891             sb.append("<taglib>");
892             sb.append("<taglib-uri>http://liferay.com/tld/util</taglib-uri>");
893             sb.append("<taglib-location>");
894             sb.append("/WEB-INF/tld/liferay-util.tld");
895             sb.append("</taglib-location>");
896             sb.append("</taglib>");
897         }
898 
899         if (hasTaglib && (webXmlVersion > 2.3)) {
900             sb.append("</jsp-config>");
901         }
902 
903         return sb.toString();
904     }
905 
906     protected String getPluginPackageLicensesXml(List<License> licenses) {
907         StringBuilder sb = new StringBuilder();
908 
909         for (int i = 0; i < licenses.size(); i++) {
910             License license = licenses.get(i);
911 
912             if (i == 0) {
913                 sb.append("\r\n");
914             }
915 
916             sb.append("\t\t<license osi-approved=\"");
917             sb.append(license.isOsiApproved());
918             sb.append("\">");
919             sb.append(license.getName());
920             sb.append("</license>\r\n");
921 
922             if ((i + 1) == licenses.size()) {
923                 sb.append("\t");
924             }
925         }
926 
927         return sb.toString();
928     }
929 
930     protected String getPluginPackageLiferayVersionsXml(
931         List<String> liferayVersions) {
932 
933         StringBuilder sb = new StringBuilder();
934 
935         for (int i = 0; i < liferayVersions.size(); i++) {
936             String liferayVersion = liferayVersions.get(i);
937 
938             if (i == 0) {
939                 sb.append("\r\n");
940             }
941 
942             sb.append("\t\t<liferay-version>");
943             sb.append(liferayVersion);
944             sb.append("</liferay-version>\r\n");
945 
946             if ((i + 1) == liferayVersions.size()) {
947                 sb.append("\t");
948             }
949         }
950 
951         return sb.toString();
952     }
953 
954     protected Properties getPluginPackageProperties(File srcFile)
955         throws Exception {
956 
957         File propertiesFile = new File(
958             srcFile + "/WEB-INF/liferay-plugin-package.properties");
959 
960         if (!propertiesFile.exists()) {
961             return null;
962         }
963 
964         String propertiesString = FileUtil.read(propertiesFile);
965 
966         return PropertiesUtil.load(propertiesString);
967     }
968 
969     protected String getPluginPackageTagsXml(List<String> tags) {
970         StringBuilder sb = new StringBuilder();
971 
972         for (int i = 0; i < tags.size(); i++) {
973             String tag = tags.get(i);
974 
975             if (i == 0) {
976                 sb.append("\r\n");
977             }
978 
979             sb.append("\t\t<tag>");
980             sb.append(tag);
981             sb.append("</tag>\r\n");
982 
983             if ((i + 1) == tags.size()) {
984                 sb.append("\t");
985             }
986         }
987 
988         return sb.toString();
989     }
990 
991     protected String getSpeedFiltersContent(File srcFile) throws Exception {
992         boolean speedFiltersEnabled = true;
993 
994         Properties properties = getPluginPackageProperties(srcFile);
995 
996         if (properties != null) {
997             speedFiltersEnabled = GetterUtil.getBoolean(
998                 properties.getProperty("speed-filters-enabled"), true);
999         }
1000
1001        if (speedFiltersEnabled) {
1002            String speedFiltersContent = FileUtil.read(
1003                DeployUtil.getResourcePath("speed_filters.xml"));
1004
1005            return speedFiltersContent;
1006        }
1007        else {
1008            return StringPool.BLANK;
1009        }
1010    }
1011
1012    protected boolean isJEEDeploymentEnabled() {
1013        return GetterUtil.getBoolean(PropsUtil.get(
1014            "auto.deploy." + ServerDetector.getServerId() +
1015                ".jee.deployment.enabled"));
1016    }
1017
1018    protected void mergeDirectory(File mergeDir, File targetDir) {
1019        if ((mergeDir == null) || (!mergeDir.exists())) {
1020            return;
1021        }
1022
1023        CopyTask.copyDirectory(mergeDir, targetDir, null, null, true, false);
1024    }
1025
1026    protected void processPluginPackageProperties(
1027            File srcFile, String displayName, PluginPackage pluginPackage)
1028        throws Exception {
1029    }
1030
1031    protected PluginPackage readPluginPackage(File file) {
1032        if (!file.exists()) {
1033            return null;
1034        }
1035
1036        InputStream is = null;
1037        ZipFile zipFile = null;
1038
1039        try {
1040            boolean parseProps = false;
1041
1042            if (file.isDirectory()) {
1043                String path = file.getPath();
1044
1045                File pluginPackageXmlFile = new File(
1046                    file.getParent() + "/merge/" + file.getName() +
1047                        "/WEB-INF/liferay-plugin-package.xml");
1048
1049                if (pluginPackageXmlFile.exists()) {
1050                    is = new FileInputStream(pluginPackageXmlFile);
1051                }
1052                else {
1053                    pluginPackageXmlFile = new File(
1054                        path + "/WEB-INF/liferay-plugin-package.xml");
1055
1056                    if (pluginPackageXmlFile.exists()) {
1057                        is = new FileInputStream(pluginPackageXmlFile);
1058                    }
1059                }
1060
1061                File pluginPackagePropsFile = new File(
1062                    file.getParent() + "/merge/" + file.getName() +
1063                        "/WEB-INF/liferay-plugin-package.properties");
1064
1065                if ((is == null) && pluginPackagePropsFile.exists()) {
1066                    is = new FileInputStream(pluginPackagePropsFile);
1067
1068                    parseProps = true;
1069                }
1070                else {
1071                    pluginPackagePropsFile = new File(
1072                        path + "/WEB-INF/liferay-plugin-package.properties");
1073
1074                    if ((is == null) && pluginPackagePropsFile.exists()) {
1075                        is = new FileInputStream(pluginPackagePropsFile);
1076
1077                        parseProps = true;
1078                    }
1079                }
1080            }
1081            else {
1082                zipFile = new ZipFile(file);
1083
1084                File pluginPackageXmlFile = new File(
1085                    file.getParent() + "/merge/" + file.getName() +
1086                        "/WEB-INF/liferay-plugin-package.xml");
1087
1088                if (pluginPackageXmlFile.exists()) {
1089                    is = new FileInputStream(pluginPackageXmlFile);
1090                }
1091                else {
1092                    ZipEntry zipEntry = zipFile.getEntry(
1093                        "WEB-INF/liferay-plugin-package.xml");
1094
1095                    if (zipEntry != null) {
1096                        is = zipFile.getInputStream(zipEntry);
1097                    }
1098                }
1099
1100                File pluginPackagePropsFile = new File(
1101                    file.getParent() + "/merge/" + file.getName() +
1102                        "/WEB-INF/liferay-plugin-package.properties");
1103
1104                if ((is == null) && pluginPackagePropsFile.exists()) {
1105                    is = new FileInputStream(pluginPackagePropsFile);
1106
1107                    parseProps = true;
1108                }
1109                else {
1110                    ZipEntry zipEntry = zipFile.getEntry(
1111                        "WEB-INF/liferay-plugin-package.properties");
1112
1113                    if ((is == null) && (zipEntry != null)) {
1114                        is = zipFile.getInputStream(zipEntry);
1115
1116                        parseProps = true;
1117                    }
1118                }
1119            }
1120
1121            if (is == null) {
1122                if (_log.isInfoEnabled()) {
1123                    _log.info(
1124                        file.getPath() + " does not have a " +
1125                            "WEB-INF/liferay-plugin-package.xml or " +
1126                                "WEB-INF/liferay-plugin-package.properties");
1127                }
1128
1129                return null;
1130            }
1131
1132            if (parseProps) {
1133                String displayName = getDisplayName(file);
1134
1135                String propertiesString = StringUtil.read(is);
1136
1137                Properties properties = PropertiesUtil.load(propertiesString);
1138
1139                return PluginPackageUtil.readPluginPackageProperties(
1140                    displayName, properties);
1141            }
1142            else {
1143                String xml = StringUtil.read(is);
1144
1145                xml = XMLFormatter.fixProlog(xml);
1146
1147                return PluginPackageUtil.readPluginPackageXml(xml);
1148            }
1149        }
1150        catch (Exception e) {
1151            _log.error(file.getPath() + ": " + e.toString());
1152        }
1153        finally {
1154            if (is != null) {
1155                try {
1156                    is.close();
1157                }
1158                catch (IOException ioe) {
1159                }
1160            }
1161
1162            if (zipFile != null) {
1163                try {
1164                    zipFile.close();
1165                }
1166                catch (IOException ioe) {
1167                }
1168            }
1169        }
1170
1171        return null;
1172    }
1173
1174    protected void rewriteFiles(File srcDir) throws Exception {
1175        String[] files = FileUtil.listFiles(srcDir + "/WEB-INF/");
1176
1177        for (int i = 0; i < files.length; i++) {
1178            String fileName = GetterUtil.getString(
1179                FileUtil.getShortFileName(files[i]));
1180
1181            // LEP-6415
1182
1183            if (fileName.equalsIgnoreCase("mule-config.xml")) {
1184                continue;
1185            }
1186
1187            String ext = GetterUtil.getString(FileUtil.getExtension(files[i]));
1188
1189            if (!ext.equalsIgnoreCase("xml")) {
1190                continue;
1191            }
1192
1193            // Make sure to rewrite any XML files to include external entities
1194            // into same file. See LEP-3142.
1195
1196            File file = new File(srcDir + "/WEB-INF/" + files[i]);
1197
1198            try {
1199                Document doc = SAXReaderUtil.read(file);
1200
1201                String content = doc.formattedString(StringPool.TAB, true);
1202
1203                FileUtil.write(file, content);
1204            }
1205            catch (Exception e) {
1206                if (_log.isWarnEnabled()) {
1207                    _log.warn(
1208                        "Unable to format " + file + ": " + e.getMessage());
1209                }
1210            }
1211        }
1212    }
1213
1214    protected void updateDeployDirectory(File srcFile) throws Exception {
1215    }
1216
1217    protected void updateGeronimoWebXml(
1218            File srcFile, String displayName, PluginPackage pluginPackage)
1219        throws Exception {
1220
1221        if (!appServerType.startsWith(ServerDetector.GERONIMO_ID)) {
1222            return;
1223        }
1224
1225        File geronimoWebXml = new File(srcFile + "/WEB-INF/geronimo-web.xml");
1226
1227        Document doc = SAXReaderUtil.read(geronimoWebXml);
1228
1229        Element root = doc.getRootElement();
1230
1231        Element environmentEl = root.element("environment");
1232
1233        Element moduleIdEl = environmentEl.element("moduleId");
1234
1235        Element artifactIdEl = moduleIdEl.element("artifactId");
1236
1237        String artifactIdText = GetterUtil.getString(artifactIdEl.getText());
1238
1239        if (!artifactIdText.equals(displayName)) {
1240            artifactIdEl.setText(displayName);
1241
1242            String content = doc.formattedString();
1243
1244            FileUtil.write(geronimoWebXml, content);
1245
1246            if (_log.isInfoEnabled()) {
1247                _log.info("Modifying Geronimo " + geronimoWebXml);
1248            }
1249        }
1250    }
1251
1252    protected void updateWebXml(
1253            File webXml, File srcFile, String displayName,
1254            PluginPackage pluginPackage)
1255        throws Exception {
1256
1257        String content = FileUtil.read(webXml);
1258
1259        int x = content.indexOf("<display-name>");
1260
1261        if (x != -1) {
1262            int y = content.indexOf("</display-name>", x);
1263
1264            y = content.indexOf(">", y) + 1;
1265
1266            content = content.substring(0, x) + content.substring(y);
1267        }
1268
1269        double webXmlVersion = 2.3;
1270
1271        Document webXmlDoc = SAXReaderUtil.read(content);
1272
1273        Element webXmlRoot = webXmlDoc.getRootElement();
1274
1275        webXmlVersion = GetterUtil.getDouble(
1276            webXmlRoot.attributeValue("version"), webXmlVersion);
1277
1278        // Merge extra content
1279
1280        String extraContent = getExtraContent(
1281            webXmlVersion, srcFile, displayName);
1282
1283        int pos = content.indexOf("</web-app>");
1284
1285        String newContent =
1286            content.substring(0, pos) + extraContent +
1287            content.substring(pos, content.length());
1288
1289        // Replace old package names
1290
1291        newContent = StringUtil.replace(
1292            newContent, "com.liferay.portal.shared.",
1293            "com.liferay.portal.kernel.");
1294
1295        newContent = WebXMLBuilder.organizeWebXML(newContent);
1296
1297        FileUtil.write(webXml, newContent, true);
1298
1299        if (_log.isInfoEnabled()) {
1300            _log.info("Modifying Servlet " + webXmlVersion + " " + webXml);
1301        }
1302    }
1303
1304    protected String baseDir;
1305    protected String destDir;
1306    protected String appServerType;
1307    protected String portletTaglibDTD;
1308    protected String portletExtTaglibDTD;
1309    protected String securityTaglibDTD;
1310    protected String themeTaglibDTD;
1311    protected String uiTaglibDTD;
1312    protected String utilTaglibDTD;
1313    protected boolean unpackWar;
1314    protected String filePattern;
1315    protected String jbossPrefix;
1316    protected String tomcatLibDir;
1317    protected List<String> wars;
1318    protected List<String> jars;
1319
1320    private static final String _PORTAL_CLASS_LOADER =
1321        "com.liferay.support.tomcat.loader.PortalClassLoader";
1322
1323    private static Log _log = LogFactoryUtil.getLog(BaseDeployer.class);
1324
1325}