1
22
23 package com.liferay.portal.plugin;
24
25 import com.liferay.portal.PortalException;
26 import com.liferay.portal.SystemException;
27 import com.liferay.portal.kernel.plugin.PluginPackage;
28 import com.liferay.portal.kernel.plugin.RemotePluginPackageRepository;
29 import com.liferay.portal.kernel.search.Hits;
30 import com.liferay.portal.kernel.util.ArrayUtil;
31 import com.liferay.portal.kernel.util.GetterUtil;
32 import com.liferay.portal.kernel.util.StringMaker;
33 import com.liferay.portal.kernel.util.StringPool;
34 import com.liferay.portal.kernel.util.StringUtil;
35 import com.liferay.portal.kernel.util.Validator;
36 import com.liferay.portal.lucene.LuceneFields;
37 import com.liferay.portal.lucene.LuceneUtil;
38 import com.liferay.portal.model.impl.CompanyImpl;
39 import com.liferay.portal.util.PortalUtil;
40 import com.liferay.portal.util.PrefsPropsUtil;
41 import com.liferay.portal.util.PropsUtil;
42 import com.liferay.portal.util.ReleaseInfo;
43 import com.liferay.util.Html;
44 import com.liferay.util.Http;
45 import com.liferay.util.License;
46 import com.liferay.util.Screenshot;
47 import com.liferay.util.Time;
48 import com.liferay.util.Version;
49 import com.liferay.util.XSSUtil;
50 import com.liferay.util.lucene.HitsImpl;
51
52 import java.io.IOException;
53
54 import java.net.MalformedURLException;
55
56 import java.text.DateFormat;
57 import java.text.SimpleDateFormat;
58
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Collection;
62 import java.util.Date;
63 import java.util.HashMap;
64 import java.util.Iterator;
65 import java.util.List;
66 import java.util.Locale;
67 import java.util.Map;
68 import java.util.Properties;
69 import java.util.Set;
70 import java.util.TreeSet;
71
72 import org.apache.commons.httpclient.HostConfiguration;
73 import org.apache.commons.httpclient.HttpClient;
74 import org.apache.commons.httpclient.methods.GetMethod;
75 import org.apache.commons.lang.time.StopWatch;
76 import org.apache.commons.logging.Log;
77 import org.apache.commons.logging.LogFactory;
78 import org.apache.lucene.index.IndexWriter;
79 import org.apache.lucene.index.Term;
80 import org.apache.lucene.search.BooleanClause;
81 import org.apache.lucene.search.BooleanQuery;
82 import org.apache.lucene.search.Query;
83 import org.apache.lucene.search.Searcher;
84 import org.apache.lucene.search.TermQuery;
85
86 import org.dom4j.Attribute;
87 import org.dom4j.Document;
88 import org.dom4j.DocumentException;
89 import org.dom4j.Element;
90
91
98 public class PluginPackageUtil {
99
100 public static final String REPOSITORY_XML_FILENAME_PREFIX =
101 "liferay-plugin-repository";
102
103 public static final String REPOSITORY_XML_FILENAME_EXTENSION =
104 "xml";
105
106 public static void endPluginPackageInstallation(String preliminaryContext) {
107 _installedPluginPackages.unregisterPluginPackageInstallation(
108 preliminaryContext);
109 }
110
111 public static List getAllAvailablePluginPackages()
112 throws PluginPackageException {
113
114 List plugins = new ArrayList();
115
116 String[] repositoryURLs = getRepositoryURLs();
117
118 for (int i = 0; i < repositoryURLs.length; i++) {
119 try {
120 RemotePluginPackageRepository repository =
121 getRepository(repositoryURLs[i]);
122
123 plugins.addAll(repository.getPluginPackages());
124 }
125 catch(PluginPackageException ppe) {
126 String message = ppe.getMessage();
127
128 if (message.startsWith("Unable to communicate")) {
129 if (_log.isWarnEnabled()) {
130 _log.warn(message);
131 }
132 }
133 else {
134 _log.error(message);
135 }
136 }
137 }
138
139 return plugins;
140 }
141
142 public static Collection getAvailableTags() {
143 return _availableTagsCache;
144 }
145
146 public static List getInstalledPluginPackages() {
147 return _installedPluginPackages.getSortedPluginPackages();
148 }
149
150 public static PluginPackage getLatestAvailablePluginPackage(
151 String groupId, String artifactId)
152 throws SystemException {
153
154 List pluginPackages = new ArrayList();
155
156 String[] repositoryURLs = getRepositoryURLs();
157
158 for (int i = 0; i < repositoryURLs.length; i++) {
159 RemotePluginPackageRepository repository =
160 getRepository(repositoryURLs[i]);
161
162 List curPluginPackages =
163 repository.findPluginsByGroupIdAndArtifactId(
164 groupId, artifactId);
165
166 if (curPluginPackages != null) {
167 pluginPackages.addAll(curPluginPackages);
168 }
169 }
170
171 return _findLatestVersion(pluginPackages);
172 }
173
174 public static PluginPackage getLatestInstalledPluginPackage(
175 String groupId, String artifactId) {
176
177 return _installedPluginPackages.getLatestPluginPackage(
178 groupId, artifactId);
179 }
180
181 public static Date getLastUpdateDate() {
182 return _lastUpdateDate;
183 }
184
185 public static PluginPackage getPluginPackageByModuleId(
186 String moduleId, String repositoryURL)
187 throws DocumentException, IOException, PluginPackageException {
188
189 RemotePluginPackageRepository repository = getRepository(repositoryURL);
190
191 return repository.findPluginPackageByModuleId(moduleId);
192 }
193
194 public static PluginPackage getPluginPackageByURL(String url)
195 throws PluginPackageException {
196
197 String[] repositoryURLs = getRepositoryURLs();
198
199 for (int i = 0; i < repositoryURLs.length; i++) {
200 String repositoryURL = repositoryURLs[i];
201
202 try {
203 RemotePluginPackageRepository repository =
204 getRepository(repositoryURL);
205
206 return repository.findPluginByArtifactURL(url);
207 }
208 catch (PluginPackageException pe) {
209 _log.error("Unable to load repository " + repositoryURL, pe);
210 }
211 }
212
213 return null;
214 }
215
216 public static RemotePluginPackageRepository getRepository(
217 String repositoryURL)
218 throws PluginPackageException {
219
220 RemotePluginPackageRepository repository =
221 (RemotePluginPackageRepository)_repositoryCache.get(repositoryURL);
222
223 if (repository != null) {
224 return repository;
225 }
226
227 return _loadRepository(repositoryURL);
228 }
229
230 public static String[] getRepositoryURLs() throws PluginPackageException {
231 try {
232 String[] trusted = PrefsPropsUtil.getStringArray(
233 PropsUtil.PLUGIN_REPOSITORIES_TRUSTED);
234 String[] untrusted = PrefsPropsUtil.getStringArray(
235 PropsUtil.PLUGIN_REPOSITORIES_UNTRUSTED);
236
237 return ArrayUtil.append(trusted, untrusted);
238 }
239 catch (Exception e) {
240 throw new PluginPackageException(
241 "Unable to read repository list", e);
242 }
243 }
244
245 public static String[] getSupportedTypes() {
246 return PropsUtil.getArray(PropsUtil.PLUGIN_TYPES);
247 }
248
249 public static boolean isCurrentVersionSupported(List versions) {
250 Version currentVersion = Version.getInstance(ReleaseInfo.getVersion());
251
252 for (int i = 0; i < versions.size(); i++) {
253 Version supportedVersion = Version.getInstance(
254 (String)versions.get(i));
255
256 if (supportedVersion.includes(currentVersion)) {
257 return true;
258 }
259 }
260
261 return false;
262 }
263
264 public static boolean isIgnored(PluginPackage pluginPackage)
265 throws PortalException, SystemException {
266
267 String packageId = pluginPackage.getPackageId();
268
269 String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
270 PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
271
272 for (int i = 0; i < pluginPackagesIgnored.length; i++) {
273 String curPluginPackagesIgnored = pluginPackagesIgnored[i];
274
275 if (curPluginPackagesIgnored.endsWith(StringPool.STAR)) {
276 String prefix = curPluginPackagesIgnored.substring(
277 0, curPluginPackagesIgnored.length() - 2);
278
279 if (packageId.startsWith(prefix)) {
280 return true;
281 }
282 }
283 else {
284 if (packageId.equals(curPluginPackagesIgnored)) {
285 return true;
286 }
287 }
288 }
289
290 return false;
291 }
292
293 public static boolean isInstallationInProcess(String context) {
294 if (_installedPluginPackages.getInstallingPluginPackage(
295 context) != null) {
296
297 return true;
298 }
299 else {
300 return false;
301 }
302 }
303
304 public static boolean isTrusted(String repositoryURL)
305 throws PluginPackageException {
306
307 try {
308 String[] trusted = PrefsPropsUtil.getStringArray(
309 PropsUtil.PLUGIN_REPOSITORIES_TRUSTED);
310
311 if (ArrayUtil.contains(trusted, repositoryURL)) {
312 return true;
313 }
314 else {
315 return false;
316 }
317 }
318 catch (Exception e) {
319 throw new PluginPackageException(
320 "Unable to read repository list", e);
321 }
322 }
323
324 public static boolean isUpdateAvailable()
325 throws PortalException, SystemException {
326
327 return _instance._isUpdateAvailable();
328 }
329
330 public static PluginPackage readPluginPackageProps(
331 String displayName, Properties props) {
332
333 int pos = displayName.indexOf("-portlet-");
334
335 String pluginType = "portlet";
336 String pluginTypeName = "Portlet";
337
338 if (pos == -1) {
339 pos = displayName.indexOf("-theme-");
340
341 pluginType = "theme";
342 pluginTypeName = "Theme";
343 }
344
345 if (pos == -1) {
346 return null;
347 }
348
349 String displayPrefix = displayName.substring(0, pos);
350
351 String moduleGroupId = GetterUtil.getString(
352 props.getProperty("module-group-id"));
353 String moduleArtifactId = displayPrefix + "-" + pluginType;
354 String moduleVersion = displayName.substring(
355 pos + pluginType.length() + 2);
356 String moduleId =
357 moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
358 "/war";
359
360 String pluginName = GetterUtil.getString(props.getProperty("name"));
361
362 String deploymentContext = GetterUtil.getString(props.getProperty(
363 "recommended-deployment-context"), moduleArtifactId);
364
365 String author = GetterUtil.getString(props.getProperty("author"));
366
367 List types = new ArrayList();
368
369 types.add(pluginType);
370
371 List licenses = new ArrayList();
372
373 String[] licensesArray = StringUtil.split(
374 props.getProperty("licenses"));
375
376 for (int i = 0; i < licensesArray.length; i++) {
377 License license = new License();
378
379 license.setName(licensesArray[i].trim());
380 license.setOsiApproved(true);
381
382 licenses.add(license);
383 }
384
385 List liferayVersions = new ArrayList();
386
387 String[] liferayVersionsArray = StringUtil.split(
388 props.getProperty("liferay-versions"));
389
390 for (int i = 0; i < liferayVersionsArray.length; i++) {
391 liferayVersions.add(liferayVersionsArray[i].trim());
392 }
393
394 if (liferayVersions.size() == 0) {
395 liferayVersions.add(ReleaseInfo.getVersion() + "+");
396 }
397
398 List tags = new ArrayList();
399
400 String[] tagsArray = StringUtil.split(props.getProperty("tags"));
401
402 for (int i = 0; i < tagsArray.length; i++) {
403 tags.add(tagsArray[i].trim());
404 }
405
406 String shortDescription = GetterUtil.getString(
407 props.getProperty("short-description"));
408 String longDescription = GetterUtil.getString(
409 props.getProperty("long-description"));
410 String changeLog = GetterUtil.getString(
411 props.getProperty("change-log"));
412 String pageURL = GetterUtil.getString(props.getProperty("page-url"));
413 String downloadURL = GetterUtil.getString(
414 props.getProperty("download-url"));
415
416 PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
417
418 pluginPackage.setName(pluginName);
419 pluginPackage.setRecommendedDeploymentContext(deploymentContext);
420 pluginPackage.setAuthor(author);
422 pluginPackage.setTypes(types);
423 pluginPackage.setLicenses(licenses);
424 pluginPackage.setLiferayVersions(liferayVersions);
425 pluginPackage.setTags(tags);
426 pluginPackage.setShortDescription(shortDescription);
427 pluginPackage.setLongDescription(longDescription);
428 pluginPackage.setChangeLog(changeLog);
429 pluginPackage.setPageURL(pageURL);
431 pluginPackage.setDownloadURL(downloadURL);
432
434 return pluginPackage;
435 }
436
437 public static PluginPackage readPluginPackageXml(String xml)
438 throws DocumentException {
439
440 Document doc = PortalUtil.readDocumentFromXML(xml);
441
442 Element root = doc.getRootElement();
443
444 return readPluginPackageXml(root);
445 }
446
447 public static PluginPackage readPluginPackageXml(Element pluginPackageEl) {
448 String name = pluginPackageEl.elementText("name");
449
450 if (_log.isDebugEnabled()) {
451 _log.debug("Reading pluginPackage definition " + name);
452 }
453
454 PluginPackage pluginPackage = new PluginPackageImpl(
455 GetterUtil.getString(pluginPackageEl.elementText("module-id")));
456
457 List liferayVersions = _readList(
458 pluginPackageEl.element("liferay-versions"), "liferay-version");
459
460 List types = _readList(pluginPackageEl.element("types"), "type");
461
462 pluginPackage.setName(_readText(name));
463 pluginPackage.setRecommendedDeploymentContext(
464 _readText(
465 pluginPackageEl.elementText("recommended-deployment-context")));
466 pluginPackage.setModifiedDate(
467 _readDate(pluginPackageEl.elementText("modified-date")));
468 pluginPackage.setAuthor(
469 _readText(pluginPackageEl.elementText("author")));
470 pluginPackage.setTypes(types);
471 pluginPackage.setLicenses(
472 _readLicenseList(
473 pluginPackageEl.element("licenses"), "license"));
474 pluginPackage.setLiferayVersions(liferayVersions);
475 pluginPackage.setTags(
476 _readList(pluginPackageEl.element("tags"), "tag"));
477 pluginPackage.setShortDescription(
478 _readText(pluginPackageEl.elementText("short-description")));
479 pluginPackage.setLongDescription(
480 _readHtml(pluginPackageEl.elementText("long-description")));
481 pluginPackage.setChangeLog(
482 _readHtml(pluginPackageEl.elementText("change-log")));
483 pluginPackage.setScreenshots(
484 _readScreenshots(pluginPackageEl.element("screenshots")));
485 pluginPackage.setPageURL(
486 _readText(pluginPackageEl.elementText("page-url")));
487 pluginPackage.setDownloadURL(
488 _readText(pluginPackageEl.elementText("download-url")));
489 pluginPackage.setDeploymentSettings(
490 _readProperties(
491 pluginPackageEl.element("deployment-settings"), "setting"));
492
493 return pluginPackage;
494 }
495
496 public static void refreshUpdatesAvailableCache() {
497 _updateAvailable = null;
498 }
499
500 public static void reIndex() throws SystemException {
501 IndexWriter writer = null;
502
503 try {
504 PluginPackageIndexer.cleanIndex();
505
506 writer = LuceneUtil.getWriter(CompanyImpl.SYSTEM);
507
508 Iterator itr = getAllAvailablePluginPackages().iterator();
509
510 while (itr.hasNext()) {
511 PluginPackage pluginPackage = (PluginPackage)itr.next();
512
513 String[] statusAndInstalledVersion =
514 _getStatusAndInstalledVersion(pluginPackage);
515
516 String status = statusAndInstalledVersion[0];
517 String installedVersion = statusAndInstalledVersion[1];
518
519 org.apache.lucene.document.Document doc =
520 PluginPackageIndexer.getAddPluginPackageDocument(
521 pluginPackage.getModuleId(), pluginPackage.getName(),
522 pluginPackage.getVersion(),
523 pluginPackage.getModifiedDate(),
524 pluginPackage.getAuthor(), pluginPackage.getTypes(),
525 pluginPackage.getTags(), pluginPackage.getLicenses(),
526 pluginPackage.getLiferayVersions(),
527 pluginPackage.getShortDescription(),
528 pluginPackage.getLongDescription(),
529 pluginPackage.getChangeLog(),
530 pluginPackage.getPageURL(),
531 pluginPackage.getRepositoryURL(), status,
532 installedVersion);
533
534 writer.addDocument(doc);
535 }
536 }
537 catch (SystemException se) {
538 throw se;
539 }
540 catch (Exception e) {
541 throw new SystemException(e);
542 }
543 finally {
544 try {
545 if (writer != null) {
546 LuceneUtil.write(CompanyImpl.SYSTEM);
547 }
548 }
549 catch (Exception e) {
550 _log.error(e);
551 }
552 }
553 }
554
555 public static RepositoryReport reloadRepositories() throws SystemException {
556 if (_log.isInfoEnabled()) {
557 _log.info("Reloading repositories");
558 }
559
560 RepositoryReport report = new RepositoryReport();
561
562 String[] repositoryURLs = getRepositoryURLs();
563
564 for (int i = 0; i < repositoryURLs.length; i++) {
565 String repositoryURL = repositoryURLs[i];
566
567 try {
568 _loadRepository(repositoryURL);
569
570 report.addSuccess(repositoryURL);
571 }
572 catch(PluginPackageException pe) {
573 report.addError(repositoryURL, pe);
574
575 _log.error(
576 "Unable to load repository " + repositoryURL + " " +
577 pe.toString());
578 }
579
580 }
581
582 reIndex();
583
584 return report;
585 }
586
587 public static void registerInstalledPluginPackage(
588 PluginPackage pluginPackage) {
589
590 _installedPluginPackages.addPluginPackage(pluginPackage);
591
592 _updateAvailable = null;
593
594 _indexPluginPackage(pluginPackage);
595 }
596
597 public static void registerPluginPackageInstallation(
598 String preliminaryContext) {
599
600 _installedPluginPackages.registerPluginPackageInstallation(
601 preliminaryContext);
602 }
603
604 public static Hits search(
605 String keywords, String type, String tag, String license,
606 String repositoryURL, String status)
607 throws SystemException {
608
609 _checkRepositories(repositoryURL);
610
611 Searcher searcher = null;
612
613 try {
614 HitsImpl hits = new HitsImpl();
615
616 BooleanQuery contextQuery = new BooleanQuery();
617
618 LuceneUtil.addRequiredTerm(
619 contextQuery, LuceneFields.PORTLET_ID,
620 PluginPackageIndexer.PORTLET_ID);
621
622 BooleanQuery fullQuery = new BooleanQuery();
623
624 fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
625
626 if (Validator.isNotNull(keywords)) {
627 BooleanQuery searchQuery = new BooleanQuery();
628
629 LuceneUtil.addTerm(searchQuery, LuceneFields.TITLE, keywords);
630 LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT, keywords);
631
632 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
633 }
634
635 if (Validator.isNotNull(type)) {
636 BooleanQuery searchQuery = new BooleanQuery();
637
638 LuceneUtil.addExactTerm(searchQuery, "type", type);
639
640 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
641 }
642
643 if (Validator.isNotNull(tag)) {
644 BooleanQuery searchQuery = new BooleanQuery();
645
646 LuceneUtil.addExactTerm(searchQuery, "tag", tag);
647
648 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
649 }
650
651 if (Validator.isNotNull(repositoryURL)) {
652 BooleanQuery searchQuery = new BooleanQuery();
653
654 Query query = new TermQuery(
655 new Term("repositoryURL", repositoryURL));
656
657 searchQuery.add(query, BooleanClause.Occur.SHOULD);
658
659 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
660 }
661
662 if (Validator.isNotNull(license)) {
663 BooleanQuery searchQuery = new BooleanQuery();
664
665 LuceneUtil.addExactTerm(searchQuery, "license", license);
666
667 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
668 }
669
670 if (Validator.isNotNull(status) && !status.equals("all")) {
671 BooleanQuery searchQuery = new BooleanQuery();
672
673 if (status.equals(PluginPackageImpl.
674 STATUS_NOT_INSTALLED_OR_OLDER_VERSION_INSTALLED)) {
675
676 LuceneUtil.addExactTerm(
677 searchQuery, "status",
678 PluginPackageImpl.STATUS_NOT_INSTALLED);
679 LuceneUtil.addExactTerm(
680 searchQuery, "status",
681 PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED);
682 }
683 else {
684 LuceneUtil.addExactTerm(searchQuery, "status", status);
685 }
686
687 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
688 }
689
690 searcher = LuceneUtil.getSearcher(CompanyImpl.SYSTEM);
691
692 hits.recordHits(searcher.search(fullQuery), searcher);
693
694 return hits;
695 }
696 catch (Exception e) {
697 return LuceneUtil.closeSearcher(searcher, keywords, e);
698 }
699 }
700
701 public static void unregisterInstalledPluginPackage(
702 PluginPackage pluginPackage) {
703
704 _installedPluginPackages.removePluginPackage(pluginPackage);
705 }
706
707 public static void updateInstallingPluginPackage(
708 String preliminaryContext, PluginPackage pluginPackage) {
709
710 _installedPluginPackages.unregisterPluginPackageInstallation(
711 preliminaryContext);
712 _installedPluginPackages.registerPluginPackageInstallation(
713 pluginPackage);
714 }
715
716 private static void _checkRepositories(String repositoryURL)
717 throws PluginPackageException {
718
719 String[] repositoryURLs = null;
720
721 if (Validator.isNotNull(repositoryURL)) {
722 repositoryURLs = new String[] {repositoryURL};
723 }
724 else {
725 repositoryURLs = getRepositoryURLs();
726 }
727
728 for (int i = 0; i < repositoryURLs.length; i++) {
729 getRepository(repositoryURLs[i]);
730 }
731 }
732
733 private static PluginPackage _findLatestVersion(List pluginPackages) {
734 PluginPackage pluginPackage = null;
735
736 Iterator itr = pluginPackages.iterator();
737
738 while (itr.hasNext()) {
739 PluginPackage curPluginPackage = (PluginPackage)itr.next();
740
741 if ((pluginPackage == null) ||
742 (curPluginPackage.isLaterVersionThan(pluginPackage))) {
743
744 pluginPackage = curPluginPackage;
745 }
746 }
747
748 return pluginPackage;
749 }
750
751 private static String[] _getStatusAndInstalledVersion(
752 PluginPackage pluginPackage) {
753
754 PluginPackage installedPluginPackage =
755 _installedPluginPackages.getLatestPluginPackage(
756 pluginPackage.getGroupId(), pluginPackage.getArtifactId());
757
758 String status = null;
759 String installedVersion = null;
760
761 if (installedPluginPackage == null) {
762 status = PluginPackageImpl.STATUS_NOT_INSTALLED;
763 }
764 else {
765 installedVersion = installedPluginPackage.getVersion();
766
767 if (installedPluginPackage.isLaterVersionThan(pluginPackage)) {
768 status = PluginPackageImpl.STATUS_NEWER_VERSION_INSTALLED;
769 }
770 else if (installedPluginPackage.isPreviousVersionThan(
771 pluginPackage)) {
772
773 status = PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED;
774 }
775 else {
776 status = PluginPackageImpl.STATUS_SAME_VERSION_INSTALLED;
777 }
778 }
779
780 return new String[] {status, installedVersion};
781 }
782
783 private static void _indexPluginPackage(PluginPackage pluginPackage) {
784 String[] statusAndInstalledVersion =
785 _getStatusAndInstalledVersion(pluginPackage);
786
787 String status = statusAndInstalledVersion[0];
788 String installedVersion = statusAndInstalledVersion[1];
789
790 try {
791 PluginPackageIndexer.updatePluginPackage(
792 pluginPackage.getModuleId(), pluginPackage.getName(),
793 pluginPackage.getVersion(), pluginPackage.getModifiedDate(),
794 pluginPackage.getAuthor(), pluginPackage.getTypes(),
795 pluginPackage.getTags(), pluginPackage.getLicenses(),
796 pluginPackage.getLiferayVersions(),
797 pluginPackage.getShortDescription(),
798 pluginPackage.getLongDescription(),
799 pluginPackage.getChangeLog(), pluginPackage.getPageURL(),
800 pluginPackage.getRepositoryURL(), status, installedVersion);
801 }
802 catch (Exception e) {
803 _log.error("Error reindexing " + pluginPackage.getModuleId(), e);
804 }
805 }
806
807 private static RemotePluginPackageRepository _loadRepository(
808 String repositoryURL)
809 throws PluginPackageException {
810
811 RemotePluginPackageRepository repository = null;
812
813 StringMaker sm = new StringMaker();
814
815 sm.append(repositoryURL);
816 sm.append(StringPool.SLASH);
817 sm.append(REPOSITORY_XML_FILENAME_PREFIX);
818 sm.append(StringPool.DASH);
819 sm.append(ReleaseInfo.getVersion());
820 sm.append(StringPool.PERIOD);
821 sm.append(REPOSITORY_XML_FILENAME_EXTENSION);
822
823 String pluginsXmlURL = sm.toString();
824
825 try {
826 HostConfiguration hostConfig = Http.getHostConfig(pluginsXmlURL);
827
828 HttpClient client = Http.getClient(hostConfig);
829
830 GetMethod getFileMethod = new GetMethod(pluginsXmlURL);
831
832 byte[] bytes = null;
833
834 try {
835 int responseCode = client.executeMethod(
836 hostConfig, getFileMethod);
837
838 if (responseCode != 200) {
839 if (_log.isDebugEnabled()) {
840 _log.debug(
841 "A repository for version " +
842 ReleaseInfo.getVersion() + " was not found. " +
843 "Checking general repository");
844 }
845
846 sm = new StringMaker();
847
848 sm.append(repositoryURL);
849 sm.append(StringPool.SLASH);
850 sm.append(REPOSITORY_XML_FILENAME_PREFIX);
851 sm.append(StringPool.PERIOD);
852 sm.append(REPOSITORY_XML_FILENAME_EXTENSION);
853
854 pluginsXmlURL = sm.toString();
855
856 getFileMethod = new GetMethod(pluginsXmlURL);
857
858 responseCode = client.executeMethod(
859 hostConfig, getFileMethod);
860
861 if (responseCode != 200) {
862 throw new PluginPackageException(
863 "Unable to download file " + pluginsXmlURL +
864 " because of response code " + responseCode);
865 }
866 }
867
868 bytes = getFileMethod.getResponseBody();
869 }
870 finally {
871 getFileMethod.releaseConnection();
872 }
873
874 if ((bytes != null) && (bytes.length > 0)) {
875 repository = _parseRepositoryXml(
876 new String(bytes), repositoryURL);
877
878 _repositoryCache.put(repositoryURL, repository);
879 _availableTagsCache.addAll(repository.getTags());
880 _lastUpdateDate = new Date();
881 _updateAvailable = null;
882
883 return repository;
884 }
885 else {
886 _lastUpdateDate = new Date();
887
888 throw new PluginPackageException("Download returned 0 bytes");
889 }
890 }
891 catch (MalformedURLException mue) {
892 _repositoryCache.remove(repositoryURL);
893
894 throw new PluginPackageException(
895 "Invalid URL " + pluginsXmlURL, mue);
896 }
897 catch (IOException ioe) {
898 _repositoryCache.remove(repositoryURL);
899
900 throw new PluginPackageException(
901 "Unable to communicate with repository " + repositoryURL, ioe);
902 }
903 catch (DocumentException de) {
904 _repositoryCache.remove(repositoryURL);
905
906 throw new PluginPackageException(
907 "Unable to parse plugin list for repository " + repositoryURL,
908 de);
909 }
910 }
911
912 private static RemotePluginPackageRepository _parseRepositoryXml(
913 String xml, String repositoryURL)
914 throws DocumentException, IOException {
915
916 List supportedPluginTypes = Arrays.asList(getSupportedTypes());
917
918 if (_log.isDebugEnabled()) {
919 _log.debug(
920 "Loading plugin repository " + repositoryURL + ":\n" + xml);
921 }
922
923 RemotePluginPackageRepository pluginPackageRepository =
924 new RemotePluginPackageRepository(repositoryURL);
925
926 if (xml == null) {
927 return pluginPackageRepository;
928 }
929
930 Document doc = PortalUtil.readDocumentFromXML(xml);
931
932 Element root = doc.getRootElement();
933
934 Properties settings = _readProperties(
935 root.element("settings"), "setting");
936
937 pluginPackageRepository.setSettings(settings);
938
939 Iterator itr1 = root.elements("plugin-package").iterator();
940
941 while (itr1.hasNext()) {
942 Element pluginPackageEl = (Element)itr1.next();
943
944 PluginPackage pluginPackage = readPluginPackageXml(pluginPackageEl);
945
946 if (!isCurrentVersionSupported(
947 pluginPackage.getLiferayVersions())) {
948
949 continue;
950 }
951
952 Iterator itr2 = pluginPackage.getTypes().iterator();
953
954 boolean containsSupportedTypes = false;
955
956 while (itr2.hasNext()) {
957 String type = (String)itr2.next();
958
959 if (supportedPluginTypes.contains(type)) {
960 containsSupportedTypes = true;
961
962 break;
963 }
964 }
965
966 if (!containsSupportedTypes) {
967 continue;
968 }
969
970 pluginPackage.setRepository(pluginPackageRepository);
971
972 pluginPackageRepository.addPluginPackage(pluginPackage);
973
974 _indexPluginPackage(pluginPackage);
975 }
976
977 return pluginPackageRepository;
978 }
979
980 private static Date _readDate(String text) {
981 if (Validator.isNotNull(text)) {
982 DateFormat dateFormat = new SimpleDateFormat(
983 Time.RFC822_FORMAT, Locale.US);
984
985 try {
986 return dateFormat.parse(text);
987 }
988 catch (Exception e) {
989 if (_log.isWarnEnabled()) {
990 _log.warn("Unable to parse date " + text);
991 }
992 }
993 }
994
995 return new Date();
996 }
997
998 private static String _readHtml(String text) {
999 return XSSUtil.strip(GetterUtil.getString(text));
1000 }
1001
1002 private static List _readLicenseList(Element parent, String childTagName) {
1003 List result = new ArrayList();
1004
1005 Iterator itr = parent.elements(childTagName).iterator();
1006
1007 while (itr.hasNext()) {
1008 Element tagEl = (Element)itr.next();
1009
1010 License license = new License();
1011
1012 license.setName(tagEl.getText());
1013
1014 Attribute osiApproved = tagEl.attribute("osi-approved");
1015
1016 if (osiApproved != null) {
1017 license.setOsiApproved(
1018 GetterUtil.getBoolean(osiApproved.getText()));
1019 }
1020
1021 Attribute url = tagEl.attribute("url");
1022
1023 if (url != null) {
1024 license.setUrl(url.getText());
1025 }
1026
1027 result.add(license);
1028 }
1029
1030 return result;
1031 }
1032
1033 private static List _readList(Element parent, String childTagName) {
1034 List result = new ArrayList();
1035
1036 if (parent != null) {
1037 Iterator itr = parent.elements(childTagName).iterator();
1038
1039 while (itr.hasNext()) {
1040 Element element = (Element)itr.next();
1041
1042 String text = element.getText().trim().toLowerCase();
1043
1044 result.add(text);
1045 }
1046 }
1047
1048 return result;
1049 }
1050
1051 private static Properties _readProperties(
1052 Element parent, String childTagName) {
1053
1054 Properties result = new Properties();
1055
1056 if (parent != null) {
1057 Iterator itr = parent.elements(childTagName).iterator();
1058
1059 while (itr.hasNext()) {
1060 Element tagEl = (Element)itr.next();
1061
1062 result.setProperty(
1063 tagEl.attribute("name").getValue(),
1064 tagEl.attribute("value").getValue());
1065 }
1066 }
1067
1068 return result;
1069 }
1070
1071 private static List _readScreenshots(Element parent) {
1072 List result = new ArrayList();
1073
1074 if (parent != null) {
1075 List screenshots = parent.elements("screenshot");
1076
1077 Iterator itr = screenshots.iterator();
1078
1079 while (itr.hasNext()) {
1080 Element screenshotEl = (Element)itr.next();
1081
1082 Screenshot screenshot = new Screenshot();
1083
1084 screenshot.setThumbnailURL(
1085 screenshotEl.element("thumbnail-url").getText());
1086 screenshot.setLargeImageURL(
1087 screenshotEl.element("large-image-url").getText());
1088
1089 result.add(screenshot);
1090 }
1091 }
1092
1093 return result;
1094 }
1095
1096 private static String _readText(String text) {
1097 return Html.stripHtml(GetterUtil.getString(text));
1098 }
1099
1100 private PluginPackageUtil() {
1101 }
1102
1103 private boolean _isUpdateAvailable()
1104 throws PortalException, SystemException {
1105
1106 if (!PrefsPropsUtil.getBoolean(
1107 PropsUtil.PLUGIN_NOTIFICATIONS_ENABLED)) {
1108
1109 return false;
1110 }
1111
1112 if (_updateAvailable != null) {
1113 return _updateAvailable.booleanValue();
1114 }
1115 else if (!_settingUpdateAvailable) {
1116 _settingUpdateAvailable = true;
1117
1118 Thread indexerThread = new Thread(
1119 new UpdateAvailableRunner(), PluginPackageUtil.class.getName());
1120
1121 indexerThread.setPriority(Thread.MIN_PRIORITY);
1122
1123 indexerThread.start();
1124 }
1125
1126 return false;
1127 }
1128
1129 private static Log _log = LogFactory.getLog(PluginPackageUtil.class);
1130
1131 private static PluginPackageUtil _instance = new PluginPackageUtil();
1132
1133 private static LocalPluginPackageRepository _installedPluginPackages =
1134 new LocalPluginPackageRepository();
1135 private static Map _repositoryCache = new HashMap();
1136 private static Set _availableTagsCache = new TreeSet();
1137 private static Date _lastUpdateDate;
1138 private static Boolean _updateAvailable;
1139 private static boolean _settingUpdateAvailable;
1140
1141 private class UpdateAvailableRunner implements Runnable {
1142
1143 public void run() {
1144 try {
1145 setUpdateAvailable();
1146 }
1147 catch (Exception e) {
1148 _log.error(e, e);
1149 }
1150 }
1151
1152 protected void setUpdateAvailable() throws Exception {
1153 StopWatch stopWatch = null;
1154
1155 if (_log.isInfoEnabled()) {
1156 _log.info("Checking for available updates");
1157
1158 stopWatch = new StopWatch();
1159
1160 stopWatch.start();
1161 }
1162
1163 Iterator itr =
1164 _installedPluginPackages.getPluginPackages().iterator();
1165
1166 while (itr.hasNext()) {
1167 PluginPackage pluginPackage = (PluginPackage)itr.next();
1168
1169 PluginPackage availablePluginPackage = null;
1170
1171 if (isIgnored(pluginPackage)) {
1172 continue;
1173 }
1174
1175 availablePluginPackage =
1176 PluginPackageUtil.getLatestAvailablePluginPackage(
1177 pluginPackage.getGroupId(),
1178 pluginPackage.getArtifactId());
1179
1180 if (availablePluginPackage == null) {
1181 continue;
1182 }
1183
1184 Version availablePluginPackageVersion = Version.getInstance(
1185 availablePluginPackage.getVersion());
1186
1187 if (availablePluginPackageVersion.isLaterVersionThan(
1188 pluginPackage.getVersion())) {
1189
1190 _updateAvailable = Boolean.TRUE;
1191
1192 break;
1193 }
1194 }
1195
1196 if (_updateAvailable == null) {
1197 _updateAvailable = Boolean.FALSE;
1198 }
1199
1200 _settingUpdateAvailable = false;
1201
1202 if (_log.isInfoEnabled()) {
1203 _log.info(
1204 "Finished checking for available updates in " +
1205 stopWatch.getTime() + " ms");
1206 }
1207 }
1208 }
1209
1210}