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