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