001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.tools;
016    
017    import com.liferay.portal.kernel.util.ListUtil;
018    import com.liferay.portal.kernel.util.StringBundler;
019    import com.liferay.portal.kernel.util.StringPool;
020    import com.liferay.portal.kernel.util.StringUtil;
021    import com.liferay.portal.kernel.util.UniqueList;
022    import com.liferay.portal.kernel.util.Validator;
023    import com.liferay.portal.util.FileImpl;
024    import com.liferay.portal.util.PropsValues;
025    
026    import java.io.File;
027    import java.io.FileInputStream;
028    import java.io.FilenameFilter;
029    
030    import java.util.ArrayList;
031    import java.util.Arrays;
032    import java.util.Collections;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Map;
036    import java.util.Properties;
037    import java.util.Set;
038    import java.util.TreeSet;
039    
040    import org.apache.oro.io.GlobFilenameFilter;
041    import org.apache.tools.ant.DirectoryScanner;
042    
043    /**
044     * @author Alexander Chow
045     * @author Brian Wing Shun Chan
046     */
047    public class PluginsEnvironmentBuilder {
048    
049            public static void main(String[] args) throws Exception {
050                    try {
051                            File dir = new File(System.getProperty("plugins.env.dir"));
052    
053                            new PluginsEnvironmentBuilder(dir);
054                    }
055                    catch (Exception e) {
056                            e.printStackTrace();
057                    }
058            }
059    
060            public PluginsEnvironmentBuilder(File dir) throws Exception {
061                    DirectoryScanner directoryScanner = new DirectoryScanner();
062    
063                    directoryScanner.setBasedir(dir);
064                    directoryScanner.setIncludes(
065                            new String[] {"**\\liferay-plugin-package.properties"});
066    
067                    directoryScanner.scan();
068    
069                    String dirName = dir.getCanonicalPath();
070    
071                    for (String fileName : directoryScanner.getIncludedFiles()) {
072                            setupWarProject(dirName, fileName);
073                    }
074    
075                    directoryScanner = new DirectoryScanner();
076    
077                    directoryScanner.setBasedir(dir);
078                    directoryScanner.setIncludes(new String[] {"**\\build.xml"});
079    
080                    directoryScanner.scan();
081    
082                    for (String fileName : directoryScanner.getIncludedFiles()) {
083                            String content = _fileUtil.read(dirName + "/" + fileName);
084    
085                            boolean osgiProject = false;
086    
087                            if (content.contains("../build-common-osgi-plugin.xml\" />") ||
088                                    content.contains(
089                                            "../tools/sdk/build-common-osgi-plugin.xml\" />")) {
090    
091                                    osgiProject = true;
092                            }
093    
094                            boolean sharedProject = false;
095    
096                            if (content.contains(
097                                            "<import file=\"../build-common-shared.xml\" />") ||
098                                    content.contains(
099                                            "../tools/sdk/build-common-shared.xml\" />")) {
100    
101                                    sharedProject = true;
102                            }
103    
104                            List<String> dependencyJars = Collections.emptyList();
105    
106                            if (osgiProject) {
107                                    int x = content.indexOf("osgi.plugin.portal.lib.jars");
108    
109                                    if (x != -1) {
110                                            x = content.indexOf("value=\"", x);
111                                            x = content.indexOf("\"", x);
112    
113                                            int y = content.indexOf("\"", x + 1);
114    
115                                            dependencyJars = Arrays.asList(
116                                                    StringUtil.split(content.substring(x + 1, y)));
117                                    }
118                            }
119    
120                            if (osgiProject || sharedProject) {
121                                    setupJarProject(
122                                            dirName, fileName, dependencyJars, sharedProject);
123                            }
124                    }
125            }
126    
127            protected void addClasspathEntry(StringBundler sb, String jar) {
128                    addClasspathEntry(sb, jar, null);
129            }
130    
131            protected void addClasspathEntry(
132                    StringBundler sb, String jar, Map<String, String> attributes) {
133    
134                    sb.append("\t<classpathentry kind=\"lib\" path=\"");
135                    sb.append(jar);
136    
137                    if ((attributes == null) || attributes.isEmpty()) {
138                            sb.append("\" />\n");
139    
140                            return;
141                    }
142    
143                    sb.append("\">\n\t\t<attributes>\n");
144    
145                    for (Map.Entry<String, String> entry : attributes.entrySet()) {
146                            sb.append("\t\t\t<attribute name=\"");
147                            sb.append(entry.getKey());
148                            sb.append("\" value=\"");
149                            sb.append(entry.getValue());
150                            sb.append("\" />\n");
151                    }
152    
153                    sb.append("\t\t</attributes>\n\t</classpathentry>\n");
154            }
155    
156            protected List<String> getCommonJars() {
157                    List<String> jars = new ArrayList<String>();
158    
159                    jars.add("commons-logging.jar");
160                    jars.add("log4j.jar");
161                    jars.add("util-bridges.jar");
162                    jars.add("util-java.jar");
163                    jars.add("util-taglib.jar");
164    
165                    return jars;
166            }
167    
168            protected List<String> getImportSharedJars(File projectDir)
169                    throws Exception {
170    
171                    File buildXmlFile = new File(projectDir, "build.xml");
172    
173                    String content = _fileUtil.read(buildXmlFile);
174    
175                    int x = content.indexOf("import.shared");
176    
177                    if (x == -1) {
178                            return new ArrayList<String>();
179                    }
180    
181                    x = content.indexOf("value=\"", x);
182                    x = content.indexOf("\"", x);
183    
184                    int y = content.indexOf("\" />", x);
185    
186                    if ((x == -1) || (y == -1)) {
187                            return new ArrayList<String>();
188                    }
189    
190                    String[] importShared = StringUtil.split(content.substring(x + 1, y));
191    
192                    if (importShared.length == 0) {
193                            return new ArrayList<String>();
194                    }
195    
196                    List<String> jars = new ArrayList<String>();
197    
198                    for (String currentImportShared : importShared) {
199                            jars.add(currentImportShared + ".jar");
200    
201                            File currentImportSharedLibDir = new File(
202                                    projectDir, "/../../shared/" + currentImportShared + "/lib");
203    
204                            if (!currentImportSharedLibDir.exists()) {
205                                    continue;
206                            }
207    
208                            for (File file : currentImportSharedLibDir.listFiles()) {
209                                    jars.add(file.getName());
210                            }
211                    }
212    
213                    return jars;
214            }
215    
216            protected List<String> getPortalDependencyJars(Properties properties) {
217                    String[] dependencyJars = StringUtil.split(
218                            properties.getProperty(
219                                    "portal-dependency-jars",
220                                    properties.getProperty("portal.dependency.jars")));
221    
222                    return ListUtil.toList(dependencyJars);
223            }
224    
225            protected List<String> getRequiredDeploymentContextsJars(
226                            File libDir, Properties properties)
227                    throws Exception {
228    
229                    List<String> jars = new ArrayList<String>();
230    
231                    String[] requiredDeploymentContexts = StringUtil.split(
232                            properties.getProperty("required-deployment-contexts"));
233    
234                    for (String requiredDeploymentContext : requiredDeploymentContexts) {
235                            if (_fileUtil.exists(
236                                            libDir.getCanonicalPath() + "/" +
237                                                    requiredDeploymentContext + "-service.jar")) {
238    
239                                    jars.add(requiredDeploymentContext + "-service.jar");
240                            }
241                    }
242    
243                    return jars;
244            }
245    
246            protected void setupJarProject(
247                            String dirName, String fileName, List<String> dependencyJars,
248                            boolean sharedProject)
249                    throws Exception {
250    
251                    File buildFile = new File(dirName + "/" + fileName);
252    
253                    File projectDir = new File(buildFile.getParent());
254    
255                    File libDir = new File(projectDir, "lib");
256    
257                    writeEclipseFiles(libDir, projectDir, dependencyJars);
258    
259                    List<String> importSharedJars = getImportSharedJars(projectDir);
260    
261                    if (sharedProject) {
262                            if (!importSharedJars.contains("portal-compat-shared.jar")) {
263                                    importSharedJars.add("portal-compat-shared.jar");
264                            }
265                    }
266    
267                    File gitignoreFile = new File(
268                            projectDir.getCanonicalPath() + "/.gitignore");
269    
270                    String[] gitIgnores = importSharedJars.toArray(
271                            new String[importSharedJars.size()]);
272    
273                    for (int i = 0; i < gitIgnores.length; i++) {
274                            String gitIgnore = gitIgnores[i];
275    
276                            gitIgnore = "/lib/" + gitIgnore;
277    
278                            gitIgnores[i] = gitIgnore;
279                    }
280    
281                    if (gitIgnores.length > 0) {
282                            System.out.println("Updating " + gitignoreFile);
283    
284                            _fileUtil.write(gitignoreFile, StringUtil.merge(gitIgnores, "\n"));
285                    }
286            }
287    
288            protected void setupWarProject(String dirName, String fileName)
289                    throws Exception {
290    
291                    File propertiesFile = new File(dirName + "/" + fileName);
292    
293                    Properties properties = new Properties();
294    
295                    properties.load(new FileInputStream(propertiesFile));
296    
297                    Set<String> jars = new TreeSet<String>();
298    
299                    jars.addAll(getCommonJars());
300    
301                    List<String> dependencyJars = getPortalDependencyJars(properties);
302    
303                    jars.addAll(dependencyJars);
304    
305                    File projectDir = new File(propertiesFile.getParent() + "/../..");
306    
307                    jars.addAll(getImportSharedJars(projectDir));
308    
309                    File libDir = new File(propertiesFile.getParent() + "/lib");
310    
311                    jars.addAll(getRequiredDeploymentContextsJars(libDir, properties));
312    
313                    writeEclipseFiles(libDir, projectDir, dependencyJars);
314    
315                    String libDirPath = StringUtil.replace(
316                            libDir.getPath(), StringPool.BACK_SLASH, StringPool.SLASH);
317    
318                    List<String> ignores = ListUtil.fromFile(
319                            libDir.getCanonicalPath() + "/../.gitignore");
320    
321                    if (libDirPath.contains("/ext/") || ignores.contains("/lib")) {
322                            return;
323                    }
324    
325                    File gitignoreFile = new File(
326                            libDir.getCanonicalPath() + "/.gitignore");
327    
328                    System.out.println("Updating " + gitignoreFile);
329    
330                    String[] gitIgnores = jars.toArray(new String[jars.size()]);
331    
332                    for (int i = 0; i < gitIgnores.length; i++) {
333                            String gitIgnore = gitIgnores[i];
334    
335                            if (Validator.isNotNull(gitIgnore) && !gitIgnore.startsWith("/")) {
336                                    gitIgnores[i] = "/" + gitIgnore;
337                            }
338                    }
339    
340                    _fileUtil.write(gitignoreFile, StringUtil.merge(gitIgnores, "\n"));
341            }
342    
343            protected void writeClasspathFile(
344                            File libDir, List<String> dependencyJars, String projectDirName,
345                            String projectName, boolean javaProject)
346                    throws Exception {
347    
348                    File classpathFile = new File(projectDirName + "/.classpath");
349    
350                    if (!javaProject) {
351                            classpathFile.delete();
352    
353                            return;
354                    }
355    
356                    List<String> globalJars = new UniqueList<String>();
357                    List<String> portalJars = new UniqueList<String>();
358    
359                    List<String> extGlobalJars = new UniqueList<String>();
360                    List<String> extPortalJars = new UniqueList<String>();
361    
362                    String libDirPath = StringUtil.replace(
363                            libDir.getPath(), StringPool.BACK_SLASH, StringPool.SLASH);
364    
365                    if (libDirPath.contains("/ext/")) {
366                            FilenameFilter filenameFilter = new GlobFilenameFilter("*.jar");
367    
368                            for (String dirName : new String[] {"global", "portal"}) {
369                                    File file = new File(libDirPath + "/../ext-lib/" + dirName);
370    
371                                    List<String> jars = ListUtil.toList(file.list(filenameFilter));
372    
373                                    if (dirName.equals("global")) {
374                                            extGlobalJars.addAll(ListUtil.sort(jars));
375    
376                                            File dir = new File(PropsValues.LIFERAY_LIB_GLOBAL_DIR);
377    
378                                            String[] fileNames = dir.list(filenameFilter);
379    
380                                            globalJars.addAll(
381                                                    ListUtil.sort(ListUtil.toList(fileNames)));
382                                            globalJars.removeAll(extGlobalJars);
383                                    }
384                                    else if (dirName.equals("portal")) {
385                                            extPortalJars.addAll(ListUtil.sort(jars));
386    
387                                            File dir = new File(PropsValues.LIFERAY_LIB_PORTAL_DIR);
388    
389                                            String[] fileNames = dir.list(filenameFilter);
390    
391                                            portalJars.addAll(
392                                                    ListUtil.sort(ListUtil.toList(fileNames)));
393                                            portalJars.removeAll(extPortalJars);
394                                    }
395                            }
396                    }
397                    else {
398                            globalJars.add("portlet.jar");
399    
400                            portalJars.addAll(dependencyJars);
401                            portalJars.add("commons-logging.jar");
402                            portalJars.add("log4j.jar");
403    
404                            Collections.sort(portalJars);
405                    }
406    
407                    String[] customJarsArray = libDir.list(new GlobFilenameFilter("*.jar"));
408    
409                    List<String> customJars = null;
410    
411                    if (customJarsArray != null) {
412                            customJars = ListUtil.toList(customJarsArray);
413    
414                            for (String jar : portalJars) {
415                                    customJars.remove(jar);
416                            }
417    
418                            customJars.remove(projectName + "-service.jar");
419                            customJars.remove("util-bridges.jar");
420                            customJars.remove("util-java.jar");
421                            customJars.remove("util-taglib.jar");
422    
423                            Collections.sort(customJars);
424                    }
425                    else {
426                            customJars = new ArrayList<String>();
427                    }
428    
429                    StringBundler sb = new StringBundler();
430    
431                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
432                    sb.append("<classpath>\n");
433    
434                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
435                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
436                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
437                                    sb.append("kind=\"src\" path=\"");
438                                    sb.append(sourceDirName);
439                                    sb.append("\" />\n");
440                            }
441                    }
442    
443                    sb.append("\t<classpathentry kind=\"src\" path=\"/portal\" />\n");
444                    sb.append("\t<classpathentry kind=\"con\" ");
445                    sb.append("path=\"org.eclipse.jdt.launching.JRE_CONTAINER\" />\n");
446    
447                    boolean addJunitJars = false;
448    
449                    for (String testType : _TEST_TYPES) {
450                            String testFolder = "test/" + testType;
451    
452                            if (_fileUtil.exists(projectDirName + "/" + testFolder)) {
453                                    addJunitJars = true;
454    
455                                    sb.append("\t<classpathentry excluding=\"**/.svn/**|.svn/\" ");
456                                    sb.append("kind=\"src\" path=\"");
457                                    sb.append(testFolder);
458                                    sb.append("\" />\n");
459                            }
460                    }
461    
462                    if (addJunitJars) {
463                            addClasspathEntry(sb, "/portal/lib/development/junit.jar");
464                            addClasspathEntry(sb, "/portal/lib/development/mockito.jar");
465                            addClasspathEntry(
466                                    sb, "/portal/lib/development/powermock-mockito.jar");
467                            addClasspathEntry(sb, "/portal/lib/development/spring-test.jar");
468    
469                            portalJars.add("commons-io.jar");
470                            portalJars.add("commons-lang.jar");
471                    }
472    
473                    addClasspathEntry(sb, "/portal/lib/development/activation.jar");
474                    addClasspathEntry(sb, "/portal/lib/development/annotations.jar");
475                    addClasspathEntry(sb, "/portal/lib/development/jsp-api.jar");
476                    addClasspathEntry(sb, "/portal/lib/development/mail.jar");
477                    addClasspathEntry(sb, "/portal/lib/development/servlet-api.jar");
478    
479                    Map<String, String> attributes = new HashMap<String, String>();
480    
481                    if (libDirPath.contains("/ext/")) {
482                            attributes.put("optional", "true");
483                    }
484    
485                    for (String jar : globalJars) {
486                            addClasspathEntry(sb, "/portal/lib/global/" + jar, attributes);
487                    }
488    
489                    Collections.sort(portalJars);
490    
491                    for (String jar : portalJars) {
492                            if (!jar.equals("util-slf4j.jar")) {
493                                    addClasspathEntry(sb, "/portal/lib/portal/" + jar, attributes);
494                            }
495                    }
496    
497                    addClasspathEntry(sb, "/portal/portal-service/portal-service.jar");
498                    addClasspathEntry(sb, "/portal/util-bridges/util-bridges.jar");
499                    addClasspathEntry(sb, "/portal/util-java/util-java.jar");
500    
501                    if (portalJars.contains("util-slf4j.jar")) {
502                            addClasspathEntry(sb, "/portal/util-slf4j/util-slf4j.jar");
503                    }
504    
505                    addClasspathEntry(sb, "/portal/util-taglib/util-taglib.jar");
506    
507                    for (String jar : extGlobalJars) {
508                            addClasspathEntry(sb, "docroot/WEB-INF/ext-lib/global/" + jar);
509                    }
510    
511                    for (String jar : extPortalJars) {
512                            addClasspathEntry(sb, "docroot/WEB-INF/ext-lib/portal/" + jar);
513                    }
514    
515                    for (String jar : customJars) {
516                            if (libDirPath.contains("/tmp/WEB-INF/lib")) {
517                                    addClasspathEntry(sb, "tmp/WEB-INF/lib/" + jar);
518                            }
519                            else if (libDirPath.contains("/docroot/WEB-INF/lib")) {
520                                    addClasspathEntry(sb, "docroot/WEB-INF/lib/" + jar);
521                            }
522                            else {
523                                    addClasspathEntry(sb, "lib/" + jar);
524                            }
525                    }
526    
527                    sb.append("\t<classpathentry kind=\"output\" path=\"bin\" />\n");
528                    sb.append("</classpath>");
529    
530                    System.out.println("Updating " + classpathFile);
531    
532                    String content = StringUtil.replace(
533                            sb.toString(), "\"/portal", "\"/portal-" + _BRANCH);
534    
535                    _fileUtil.write(classpathFile, content);
536            }
537    
538            protected void writeEclipseFiles(
539                            File libDir, File projectDir, List<String> dependencyJars)
540                    throws Exception {
541    
542                    String projectDirName = projectDir.getCanonicalPath();
543    
544                    String projectName = StringUtil.extractLast(
545                            projectDirName, File.separatorChar);
546    
547                    boolean javaProject = false;
548    
549                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
550                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
551                                    javaProject = true;
552    
553                                    break;
554                            }
555                    }
556    
557                    if (!javaProject) {
558                            System.out.println(
559                                    "Eclipse Java project will not be used because a source " +
560                                            "folder does not exist");
561                    }
562    
563                    writeProjectFile(projectDirName, projectName, javaProject);
564    
565                    writeClasspathFile(
566                            libDir, dependencyJars, projectDirName, projectName, javaProject);
567    
568                    for (String sourceDirName : _SOURCE_DIR_NAMES) {
569                            if (_fileUtil.exists(projectDirName + "/" + sourceDirName)) {
570                                    List<String> gitIgnores = new ArrayList<String>();
571    
572                                    if (sourceDirName.endsWith("ext-impl/src")) {
573                                            gitIgnores.add("/classes");
574                                            gitIgnores.add("/ext-impl.jar");
575                                    }
576                                    else if (sourceDirName.endsWith("ext-service/src")) {
577                                            gitIgnores.add("/classes");
578                                            gitIgnores.add("/ext-service.jar");
579                                    }
580                                    else if (sourceDirName.endsWith("ext-util-bridges/src")) {
581                                            gitIgnores.add("/classes");
582                                            gitIgnores.add("/ext-util-bridges.jar");
583                                    }
584                                    else if (sourceDirName.endsWith("ext-util-java/src")) {
585                                            gitIgnores.add("/classes");
586                                            gitIgnores.add("/ext-util-java.jar");
587                                    }
588                                    else if (sourceDirName.endsWith("ext-util-taglib/src")) {
589                                            gitIgnores.add("/classes");
590                                            gitIgnores.add("/ext-util-taglib.jar");
591                                    }
592                                    else {
593                                            continue;
594                                    }
595    
596                                    String dirName = projectDirName + "/" + sourceDirName + "/../";
597    
598                                    if (gitIgnores.isEmpty()) {
599                                            _fileUtil.delete(dirName + ".gitignore");
600                                    }
601                                    else {
602                                            String gitIgnoresString = StringUtil.merge(
603                                                    gitIgnores, "\n");
604    
605                                            _fileUtil.write(dirName + ".gitignore", gitIgnoresString);
606                                    }
607                            }
608                    }
609    
610                    if (_fileUtil.exists(projectDirName + "/test")) {
611                            _fileUtil.write(
612                                    projectDirName + "/.gitignore", "/test-classes\n/test-results");
613                    }
614                    else {
615                            _fileUtil.delete(projectDirName + "/.gitignore");
616                    }
617            }
618    
619            protected void writeProjectFile(
620                            String projectDirName, String projectName, boolean javaProject)
621                    throws Exception {
622    
623                    StringBundler sb = new StringBundler(17);
624    
625                    sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n");
626                    sb.append("<projectDescription>\n");
627                    sb.append("\t<name>");
628                    sb.append(projectName);
629                    sb.append("-");
630                    sb.append(_BRANCH);
631                    sb.append("</name>\n");
632                    sb.append("\t<comment></comment>\n");
633                    sb.append("\t<projects></projects>\n");
634                    sb.append("\t<buildSpec>\n");
635    
636                    if (javaProject) {
637                            sb.append("\t\t<buildCommand>\n");
638                            sb.append("\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>\n");
639                            sb.append("\t\t\t<arguments></arguments>\n");
640                            sb.append("\t\t</buildCommand>\n");
641                    }
642    
643                    sb.append("\t</buildSpec>\n");
644                    sb.append("\t<natures>\n");
645    
646                    if (javaProject) {
647                            sb.append("\t\t<nature>org.eclipse.jdt.core.javanature</nature>\n");
648                    }
649    
650                    sb.append("\t</natures>\n");
651                    sb.append("</projectDescription>");
652    
653                    File projectFile = new File(projectDirName + "/.project");
654    
655                    System.out.println("Updating " + projectFile);
656    
657                    _fileUtil.write(projectFile, sb.toString());
658            }
659    
660            private static final String _BRANCH = "master";
661    
662            private static final String[] _SOURCE_DIR_NAMES = new String[] {
663                    "docroot/WEB-INF/ext-impl/src", "docroot/WEB-INF/ext-service/src",
664                    "docroot/WEB-INF/ext-util-bridges/src",
665                    "docroot/WEB-INF/ext-util-java/src",
666                    "docroot/WEB-INF/ext-util-taglib/src", "docroot/WEB-INF/service",
667                    "docroot/WEB-INF/src", "src"
668            };
669    
670            private static final String[] _TEST_TYPES = {"integration", "unit"};
671    
672            private static FileImpl _fileUtil = FileImpl.getInstance();
673    
674    }