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