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