1
22
23 package com.liferay.portal.plugin;
24
25 import com.liferay.portal.SystemException;
26 import com.liferay.portal.kernel.log.Log;
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
28 import com.liferay.portal.kernel.plugin.PluginPackage;
29 import com.liferay.portal.kernel.plugin.RemotePluginPackageRepository;
30 import com.liferay.portal.kernel.search.BooleanClauseOccur;
31 import com.liferay.portal.kernel.search.BooleanQuery;
32 import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
33 import com.liferay.portal.kernel.search.Field;
34 import com.liferay.portal.kernel.search.Hits;
35 import com.liferay.portal.kernel.search.Query;
36 import com.liferay.portal.kernel.search.SearchEngineUtil;
37 import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
38 import com.liferay.portal.kernel.util.ArrayUtil;
39 import com.liferay.portal.kernel.util.GetterUtil;
40 import com.liferay.portal.kernel.util.HtmlUtil;
41 import com.liferay.portal.kernel.util.Http;
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.kernel.xml.Attribute;
49 import com.liferay.portal.kernel.xml.Document;
50 import com.liferay.portal.kernel.xml.DocumentException;
51 import com.liferay.portal.kernel.xml.Element;
52 import com.liferay.portal.kernel.xml.SAXReaderUtil;
53 import com.liferay.portal.model.CompanyConstants;
54 import com.liferay.portal.model.Plugin;
55 import com.liferay.portal.util.HttpImpl;
56 import com.liferay.portal.util.PrefsPropsUtil;
57 import com.liferay.portal.util.PropsKeys;
58 import com.liferay.portal.util.PropsValues;
59 import com.liferay.util.License;
60 import com.liferay.util.Screenshot;
61 import com.liferay.util.Version;
62
63 import java.io.IOException;
64
65 import java.net.MalformedURLException;
66
67 import java.text.DateFormat;
68 import java.text.SimpleDateFormat;
69
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Collection;
73 import java.util.Date;
74 import java.util.HashMap;
75 import java.util.Iterator;
76 import java.util.List;
77 import java.util.Locale;
78 import java.util.Map;
79 import java.util.Properties;
80 import java.util.Set;
81 import java.util.TreeSet;
82
83 import javax.servlet.http.HttpServletResponse;
84
85 import org.apache.commons.httpclient.HostConfiguration;
86 import org.apache.commons.httpclient.HttpClient;
87 import org.apache.commons.httpclient.methods.GetMethod;
88 import org.apache.commons.lang.time.StopWatch;
89
90
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 _instance._endPluginPackageInstallation(preliminaryContext);
108 }
109
110 public static List<PluginPackage> getAllAvailablePluginPackages()
111 throws PluginPackageException {
112
113 return _instance._getAllAvailablePluginPackages();
114 }
115
116 public static Collection<String> getAvailableTags() {
117 return _instance._getAvailableTags();
118 }
119
120 public static List<PluginPackage> getInstalledPluginPackages() {
121 return _instance._getInstalledPluginPackages();
122 }
123
124 public static PluginPackage getLatestAvailablePluginPackage(
125 String groupId, String artifactId)
126 throws SystemException {
127
128 return _instance._getLatestAvailablePluginPackage(groupId, artifactId);
129 }
130
131 public static PluginPackage getLatestInstalledPluginPackage(
132 String groupId, String artifactId) {
133
134 return _instance._getLatestInstalledPluginPackage(groupId, artifactId);
135 }
136
137 public static Date getLastUpdateDate() {
138 return _instance._getLastUpdateDate();
139 }
140
141 public static PluginPackage getPluginPackageByModuleId(
142 String moduleId, String repositoryURL)
143 throws PluginPackageException {
144
145 return _instance._getPluginPackageByModuleId(moduleId, repositoryURL);
146 }
147
148 public static PluginPackage getPluginPackageByURL(String url)
149 throws PluginPackageException {
150
151 return _instance._getPluginPackageByURL(url);
152 }
153
154 public static RemotePluginPackageRepository getRepository(
155 String repositoryURL)
156 throws PluginPackageException {
157
158 return _instance._getRepository(repositoryURL);
159 }
160
161 public static String[] getRepositoryURLs() throws PluginPackageException {
162 return _instance._getRepositoryURLs();
163 }
164
165 public static String[] getSupportedTypes() {
166 return _instance._getSupportedTypes();
167 }
168
169 public static boolean isCurrentVersionSupported(List<String> versions) {
170 return _instance._isCurrentVersionSupported(versions);
171 }
172
173 public static boolean isIgnored(PluginPackage pluginPackage)
174 throws SystemException {
175
176 return _instance._isIgnored(pluginPackage);
177 }
178
179 public static boolean isInstallationInProcess(String context) {
180 return _instance._isInstallationInProcess(context);
181 }
182
183 public static boolean isTrusted(String repositoryURL)
184 throws PluginPackageException {
185
186 return _instance._isTrusted(repositoryURL);
187 }
188
189 public static boolean isUpdateAvailable() throws SystemException {
190 return _instance._isUpdateAvailable();
191 }
192
193 public static PluginPackage readPluginPackageProperties(
194 String displayName, Properties props) {
195
196 return _instance._readPluginPackageProperties(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 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() throws SystemException {
584 if (!PrefsPropsUtil.getBoolean(
585 PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
586 PropsValues.PLUGIN_NOTIFICATIONS_ENABLED)) {
587
588 return false;
589 }
590
591 if (_updateAvailable != null) {
592 return _updateAvailable.booleanValue();
593 }
594 else if (!_settingUpdateAvailable) {
595 _settingUpdateAvailable = true;
596
597 Thread indexerThread = new Thread(
598 new UpdateAvailableRunner(), PluginPackageUtil.class.getName());
599
600 indexerThread.setPriority(Thread.MIN_PRIORITY);
601
602 indexerThread.start();
603 }
604
605 return false;
606 }
607
608 private RemotePluginPackageRepository _loadRepository(String repositoryURL)
609 throws PluginPackageException {
610
611 RemotePluginPackageRepository repository = null;
612
613 StringBuilder sb = new StringBuilder();
614
615 if (!repositoryURL.startsWith(Http.HTTP_WITH_SLASH) &&
616 !repositoryURL.startsWith(Http.HTTPS_WITH_SLASH)) {
617
618 sb.append(Http.HTTP_WITH_SLASH);
619 }
620
621 sb.append(repositoryURL);
622 sb.append(StringPool.SLASH);
623 sb.append(REPOSITORY_XML_FILENAME_PREFIX);
624 sb.append(StringPool.DASH);
625 sb.append(ReleaseInfo.getVersion());
626 sb.append(StringPool.PERIOD);
627 sb.append(REPOSITORY_XML_FILENAME_EXTENSION);
628
629 String pluginsXmlURL = sb.toString();
630
631 try {
632 HttpImpl httpImpl = (HttpImpl)HttpUtil.getHttp();
633
634 HostConfiguration hostConfig = httpImpl.getHostConfig(
635 pluginsXmlURL);
636
637 HttpClient client = httpImpl.getClient(hostConfig);
638
639 GetMethod getFileMethod = new GetMethod(pluginsXmlURL);
640
641 byte[] bytes = null;
642
643 try {
644 int responseCode = client.executeMethod(
645 hostConfig, getFileMethod);
646
647 if (responseCode != HttpServletResponse.SC_OK) {
648 if (_log.isDebugEnabled()) {
649 _log.debug(
650 "A repository for version " +
651 ReleaseInfo.getVersion() + " was not found. " +
652 "Checking general repository");
653 }
654
655 sb = new StringBuilder();
656
657 sb.append(repositoryURL);
658 sb.append(StringPool.SLASH);
659 sb.append(REPOSITORY_XML_FILENAME_PREFIX);
660 sb.append(StringPool.PERIOD);
661 sb.append(REPOSITORY_XML_FILENAME_EXTENSION);
662
663 pluginsXmlURL = sb.toString();
664
665 getFileMethod.releaseConnection();
666
667 getFileMethod = new GetMethod(pluginsXmlURL);
668
669 responseCode = client.executeMethod(
670 hostConfig, getFileMethod);
671
672 if (responseCode != HttpServletResponse.SC_OK) {
673 throw new PluginPackageException(
674 "Unable to download file " + pluginsXmlURL +
675 " because of response code " + responseCode);
676 }
677 }
678
679 bytes = getFileMethod.getResponseBody();
680 }
681 finally {
682 getFileMethod.releaseConnection();
683 }
684
685 if ((bytes != null) && (bytes.length > 0)) {
686 repository = _parseRepositoryXml(
687 new String(bytes), repositoryURL);
688
689 _repositoryCache.put(repositoryURL, repository);
690 _availableTagsCache.addAll(repository.getTags());
691 _lastUpdateDate = new Date();
692 _updateAvailable = null;
693
694 return repository;
695 }
696 else {
697 _lastUpdateDate = new Date();
698
699 throw new PluginPackageException("Download returned 0 bytes");
700 }
701 }
702 catch (MalformedURLException mue) {
703 _repositoryCache.remove(repositoryURL);
704
705 throw new PluginPackageException(
706 "Invalid URL " + pluginsXmlURL, mue);
707 }
708 catch (IOException ioe) {
709 _repositoryCache.remove(repositoryURL);
710
711 throw new PluginPackageException(
712 "Unable to communicate with repository " + repositoryURL, ioe);
713 }
714 catch (DocumentException de) {
715 _repositoryCache.remove(repositoryURL);
716
717 throw new PluginPackageException(
718 "Unable to parse plugin list for repository " + repositoryURL,
719 de);
720 }
721 }
722
723 private RemotePluginPackageRepository _parseRepositoryXml(
724 String xml, String repositoryURL)
725 throws DocumentException {
726
727 List<String> supportedPluginTypes = Arrays.asList(getSupportedTypes());
728
729 if (_log.isDebugEnabled()) {
730 _log.debug(
731 "Loading plugin repository " + repositoryURL + ":\n" + xml);
732 }
733
734 RemotePluginPackageRepository pluginPackageRepository =
735 new RemotePluginPackageRepository(repositoryURL);
736
737 if (xml == null) {
738 return pluginPackageRepository;
739 }
740
741 Document doc = SAXReaderUtil.read(xml);
742
743 Element root = doc.getRootElement();
744
745 Properties settings = _readProperties(
746 root.element("settings"), "setting");
747
748 pluginPackageRepository.setSettings(settings);
749
750 Iterator<Element> itr1 = root.elements("plugin-package").iterator();
751
752 while (itr1.hasNext()) {
753 Element pluginPackageEl = itr1.next();
754
755 PluginPackage pluginPackage = _readPluginPackageXml(
756 pluginPackageEl);
757
758 if (!_isCurrentVersionSupported(
759 pluginPackage.getLiferayVersions())) {
760
761 continue;
762 }
763
764 Iterator<String> itr2 = pluginPackage.getTypes().iterator();
765
766 boolean containsSupportedTypes = false;
767
768 while (itr2.hasNext()) {
769 String type = itr2.next();
770
771 if (supportedPluginTypes.contains(type)) {
772 containsSupportedTypes = true;
773
774 break;
775 }
776 }
777
778 if (!containsSupportedTypes) {
779 continue;
780 }
781
782 pluginPackage.setRepository(pluginPackageRepository);
783
784 pluginPackageRepository.addPluginPackage(pluginPackage);
785
786 _indexPluginPackage(pluginPackage);
787 }
788
789 return pluginPackageRepository;
790 }
791
792 private Date _readDate(String text) {
793 if (Validator.isNotNull(text)) {
794 DateFormat dateFormat = new SimpleDateFormat(
795 Time.RFC822_FORMAT, Locale.US);
796
797 try {
798 return dateFormat.parse(text);
799 }
800 catch (Exception e) {
801 if (_log.isWarnEnabled()) {
802 _log.warn("Unable to parse date " + text);
803 }
804 }
805 }
806
807 return new Date();
808 }
809
810 private String _readHtml(String text) {
811 return GetterUtil.getString(text);
812 }
813
814 private List<License> _readLicenseList(Element parentEL, String name) {
815 List<License> licenses = new ArrayList<License>();
816
817 Iterator<Element> itr = parentEL.elements(name).iterator();
818
819 while (itr.hasNext()) {
820 Element licenseEl = itr.next();
821
822 License license = new License();
823
824 license.setName(licenseEl.getText());
825
826 Attribute osiApproved = licenseEl.attribute("osi-approved");
827
828 if (osiApproved != null) {
829 license.setOsiApproved(
830 GetterUtil.getBoolean(osiApproved.getText()));
831 }
832
833 Attribute url = licenseEl.attribute("url");
834
835 if (url != null) {
836 license.setUrl(url.getText());
837 }
838
839 licenses.add(license);
840 }
841
842 return licenses;
843 }
844
845 private List<String> _readList(Element parentEl, String name) {
846 List<String> result = new ArrayList<String>();
847
848 if (parentEl != null) {
849 Iterator<Element> itr = parentEl.elements(name).iterator();
850
851 while (itr.hasNext()) {
852 Element el = itr.next();
853
854 String text = el.getText().trim().toLowerCase();
855
856 result.add(text);
857 }
858 }
859
860 return result;
861 }
862
863 private PluginPackage _readPluginPackageProperties(
864 String displayName, Properties properties) {
865
866 int pos = displayName.indexOf("-portlet");
867
868 String pluginType = Plugin.TYPE_PORTLET;
869
870 if (pos == -1) {
871 pos = displayName.indexOf("-hook");
872
873 pluginType = Plugin.TYPE_HOOK;
874 }
875
876 if (pos == -1) {
877 pos = displayName.indexOf("-layouttpl");
878
879 pluginType = Plugin.TYPE_LAYOUT_TEMPLATE;
880 }
881
882 if (pos == -1) {
883 pos = displayName.indexOf("-theme");
884
885 pluginType = Plugin.TYPE_THEME;
886 }
887
888 if (pos == -1) {
889 pos = displayName.indexOf("-web");
890
891 pluginType = Plugin.TYPE_WEB;
892 }
893
894 if (pos == -1) {
895 return null;
896 }
897
898 String displayPrefix = displayName.substring(0, pos);
899
900 String moduleGroupId = GetterUtil.getString(
901 properties.getProperty("module-group-id"));
902 String moduleArtifactId = displayPrefix + "-" + pluginType;
903
904 String moduleVersion = null;
905
906 int moduleVersionPos = pos + pluginType.length() + 2;
907
908 if (displayName.length() > moduleVersionPos) {
909 moduleVersion = displayName.substring(moduleVersionPos);
910 }
911 else {
912 moduleVersion = ReleaseInfo.getVersion();
913 }
914
915 String moduleId =
916 moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
917 "/war";
918
919 String pluginName = GetterUtil.getString(
920 properties.getProperty("name"));
921
922 String deploymentContext = GetterUtil.getString(
923 properties.getProperty("recommended-deployment-context"),
924 moduleArtifactId);
925
926 String author = GetterUtil.getString(properties.getProperty("author"));
927
928 List<String> types = new ArrayList<String>();
929
930 types.add(pluginType);
931
932 List<License> licenses = new ArrayList<License>();
933
934 String[] licensesArray = StringUtil.split(
935 properties.getProperty("licenses"));
936
937 for (int i = 0; i < licensesArray.length; i++) {
938 License license = new License();
939
940 license.setName(licensesArray[i].trim());
941 license.setOsiApproved(true);
942
943 licenses.add(license);
944 }
945
946 List<String> liferayVersions = new ArrayList<String>();
947
948 String[] liferayVersionsArray = StringUtil.split(
949 properties.getProperty("liferay-versions"));
950
951 for (String liferayVersion : liferayVersionsArray) {
952 liferayVersions.add(liferayVersion.trim());
953 }
954
955 if (liferayVersions.size() == 0) {
956 liferayVersions.add(ReleaseInfo.getVersion() + "+");
957 }
958
959 List<String> tags = new ArrayList<String>();
960
961 String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
962
963 for (String tag : tagsArray) {
964 tags.add(tag.trim());
965 }
966
967 String shortDescription = GetterUtil.getString(
968 properties.getProperty("short-description"));
969 String longDescription = GetterUtil.getString(
970 properties.getProperty("long-description"));
971 String changeLog = GetterUtil.getString(
972 properties.getProperty("change-log"));
973 String pageURL = GetterUtil.getString(
974 properties.getProperty("page-url"));
975 String downloadURL = GetterUtil.getString(
976 properties.getProperty("download-url"));
977
978 PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
979
980 pluginPackage.setName(pluginName);
981 pluginPackage.setRecommendedDeploymentContext(deploymentContext);
982 pluginPackage.setAuthor(author);
984 pluginPackage.setTypes(types);
985 pluginPackage.setLicenses(licenses);
986 pluginPackage.setLiferayVersions(liferayVersions);
987 pluginPackage.setTags(tags);
988 pluginPackage.setShortDescription(shortDescription);
989 pluginPackage.setLongDescription(longDescription);
990 pluginPackage.setChangeLog(changeLog);
991 pluginPackage.setPageURL(pageURL);
993 pluginPackage.setDownloadURL(downloadURL);
994
996 return pluginPackage;
997 }
998
999 private PluginPackage _readPluginPackageXml(String xml)
1000 throws DocumentException {
1001
1002 Document doc = SAXReaderUtil.read(xml);
1003
1004 Element root = doc.getRootElement();
1005
1006 return _readPluginPackageXml(root);
1007 }
1008
1009 private PluginPackage _readPluginPackageXml(Element pluginPackageEl) {
1010 String name = pluginPackageEl.elementText("name");
1011
1012 if (_log.isDebugEnabled()) {
1013 _log.debug("Reading pluginPackage definition " + name);
1014 }
1015
1016 PluginPackage pluginPackage = new PluginPackageImpl(
1017 GetterUtil.getString(pluginPackageEl.elementText("module-id")));
1018
1019 List<String> liferayVersions = _readList(
1020 pluginPackageEl.element("liferay-versions"), "liferay-version");
1021
1022 List<String> types = _readList(
1023 pluginPackageEl.element("types"), "type");
1024
1025 pluginPackage.setName(_readText(name));
1026 pluginPackage.setRecommendedDeploymentContext(
1027 _readText(
1028 pluginPackageEl.elementText("recommended-deployment-context")));
1029 pluginPackage.setModifiedDate(
1030 _readDate(pluginPackageEl.elementText("modified-date")));
1031 pluginPackage.setAuthor(
1032 _readText(pluginPackageEl.elementText("author")));
1033 pluginPackage.setTypes(types);
1034 pluginPackage.setLicenses(
1035 _readLicenseList(
1036 pluginPackageEl.element("licenses"), "license"));
1037 pluginPackage.setLiferayVersions(liferayVersions);
1038 pluginPackage.setTags(
1039 _readList(pluginPackageEl.element("tags"), "tag"));
1040 pluginPackage.setShortDescription(
1041 _readText(pluginPackageEl.elementText("short-description")));
1042 pluginPackage.setLongDescription(
1043 _readHtml(pluginPackageEl.elementText("long-description")));
1044 pluginPackage.setChangeLog(
1045 _readHtml(pluginPackageEl.elementText("change-log")));
1046 pluginPackage.setScreenshots(
1047 _readScreenshots(pluginPackageEl.element("screenshots")));
1048 pluginPackage.setPageURL(
1049 _readText(pluginPackageEl.elementText("page-url")));
1050 pluginPackage.setDownloadURL(
1051 _readText(pluginPackageEl.elementText("download-url")));
1052 pluginPackage.setDeploymentSettings(
1053 _readProperties(
1054 pluginPackageEl.element("deployment-settings"), "setting"));
1055
1056 return pluginPackage;
1057 }
1058
1059 private Properties _readProperties(Element parentEl, String name) {
1060 Properties result = new Properties();
1061
1062 if (parentEl != null) {
1063 Iterator<Element> itr = parentEl.elements(name).iterator();
1064
1065 while (itr.hasNext()) {
1066 Element el = itr.next();
1067
1068 result.setProperty(
1069 el.attribute("name").getValue(),
1070 el.attribute("value").getValue());
1071 }
1072 }
1073
1074 return result;
1075 }
1076
1077 private List<Screenshot> _readScreenshots(Element parentEl) {
1078 List<Screenshot> screenshots = new ArrayList<Screenshot>();
1079
1080 if (parentEl != null) {
1081 Iterator<Element> itr = parentEl.elements("screenshot").iterator();
1082
1083 while (itr.hasNext()) {
1084 Element screenshotEl = itr.next();
1085
1086 Screenshot screenshot = new Screenshot();
1087
1088 screenshot.setThumbnailURL(
1089 screenshotEl.element("thumbnail-url").getText());
1090 screenshot.setLargeImageURL(
1091 screenshotEl.element("large-image-url").getText());
1092
1093 screenshots.add(screenshot);
1094 }
1095 }
1096
1097 return screenshots;
1098 }
1099
1100 private String _readText(String text) {
1101 return HtmlUtil.extractText(GetterUtil.getString(text));
1102 }
1103
1104 private void _refreshUpdatesAvailableCache() {
1105 _updateAvailable = null;
1106 }
1107
1108 private void _reIndex() throws SystemException {
1109 if (SearchEngineUtil.isIndexReadOnly()) {
1110 return;
1111 }
1112
1113 try {
1114 PluginPackageIndexer.cleanIndex();
1115
1116 for (PluginPackage pluginPackage :
1117 _getAllAvailablePluginPackages()) {
1118
1119 String[] statusAndInstalledVersion =
1120 _getStatusAndInstalledVersion(pluginPackage);
1121
1122 String status = statusAndInstalledVersion[0];
1123 String installedVersion = statusAndInstalledVersion[1];
1124
1125 com.liferay.portal.kernel.search.Document doc =
1126 PluginPackageIndexer.getPluginPackageDocument(
1127 pluginPackage.getModuleId(), pluginPackage.getName(),
1128 pluginPackage.getVersion(),
1129 pluginPackage.getModifiedDate(),
1130 pluginPackage.getAuthor(), pluginPackage.getTypes(),
1131 pluginPackage.getTags(), pluginPackage.getLicenses(),
1132 pluginPackage.getLiferayVersions(),
1133 pluginPackage.getShortDescription(),
1134 pluginPackage.getLongDescription(),
1135 pluginPackage.getChangeLog(),
1136 pluginPackage.getPageURL(),
1137 pluginPackage.getRepositoryURL(), status,
1138 installedVersion);
1139
1140 SearchEngineUtil.addDocument(CompanyConstants.SYSTEM, doc);
1141 }
1142 }
1143 catch (SystemException se) {
1144 throw se;
1145 }
1146 catch (Exception e) {
1147 throw new SystemException(e);
1148 }
1149 }
1150
1151 private RepositoryReport _reloadRepositories() throws SystemException {
1152 if (_log.isInfoEnabled()) {
1153 _log.info("Reloading repositories");
1154 }
1155
1156 RepositoryReport repositoryReport = new RepositoryReport();
1157
1158 String[] repositoryURLs = _getRepositoryURLs();
1159
1160 for (int i = 0; i < repositoryURLs.length; i++) {
1161 String repositoryURL = repositoryURLs[i];
1162
1163 try {
1164 _loadRepository(repositoryURL);
1165
1166 repositoryReport.addSuccess(repositoryURL);
1167 }
1168 catch (PluginPackageException pe) {
1169 repositoryReport.addError(repositoryURL, pe);
1170
1171 _log.error(
1172 "Unable to load repository " + repositoryURL + " " +
1173 pe.toString());
1174 }
1175
1176 }
1177
1178 _reIndex();
1179
1180 return repositoryReport;
1181 }
1182
1183 private void _registerInstalledPluginPackage(
1184 PluginPackage pluginPackage) {
1185
1186 _installedPluginPackages.addPluginPackage(pluginPackage);
1187
1188 _updateAvailable = null;
1189
1190 _indexPluginPackage(pluginPackage);
1191 }
1192
1193 private void _registerPluginPackageInstallation(
1194 String preliminaryContext) {
1195
1196 _installedPluginPackages.registerPluginPackageInstallation(
1197 preliminaryContext);
1198 }
1199
1200 private Hits _search(
1201 String keywords, String type, String tag, String license,
1202 String repositoryURL, String status, int start, int end)
1203 throws SystemException {
1204
1205 _checkRepositories(repositoryURL);
1206
1207 try {
1208 BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
1209
1210 contextQuery.addRequiredTerm(
1211 Field.PORTLET_ID, PluginPackageIndexer.PORTLET_ID);
1212
1213 BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
1214
1215 fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
1216
1217 if (Validator.isNotNull(keywords)) {
1218 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1219
1220 searchQuery.addTerm(Field.TITLE, keywords);
1221 searchQuery.addTerm(Field.CONTENT, keywords);
1222
1223 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1224 }
1225
1226 if (Validator.isNotNull(type)) {
1227 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1228
1229 searchQuery.addExactTerm("type", type);
1230
1231 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1232 }
1233
1234 if (Validator.isNotNull(tag)) {
1235 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1236
1237 searchQuery.addExactTerm("tag", tag);
1238
1239 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1240 }
1241
1242 if (Validator.isNotNull(repositoryURL)) {
1243 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1244
1245 Query query = TermQueryFactoryUtil.create(
1246 "repositoryURL", repositoryURL);
1247
1248 searchQuery.add(query, BooleanClauseOccur.SHOULD);
1249
1250 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1251 }
1252
1253 if (Validator.isNotNull(license)) {
1254 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1255
1256 searchQuery.addExactTerm("license", license);
1257
1258 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1259 }
1260
1261 if (Validator.isNotNull(status) && !status.equals("all")) {
1262 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1263
1264 if (status.equals(PluginPackageImpl.
1265 STATUS_NOT_INSTALLED_OR_OLDER_VERSION_INSTALLED)) {
1266
1267 searchQuery.addExactTerm(
1268 "status", PluginPackageImpl.STATUS_NOT_INSTALLED);
1269 searchQuery.addExactTerm(
1270 "status",
1271 PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED);
1272 }
1273 else {
1274 searchQuery.addExactTerm("status", status);
1275 }
1276
1277 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1278 }
1279
1280 return SearchEngineUtil.search(
1281 CompanyConstants.SYSTEM, fullQuery, start, end);
1282 }
1283 catch (Exception e) {
1284 throw new SystemException(e);
1285 }
1286 }
1287
1288 private void _unregisterInstalledPluginPackage(
1289 PluginPackage pluginPackage) {
1290
1291 _installedPluginPackages.removePluginPackage(pluginPackage);
1292
1293 try {
1294 List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1295 pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1296
1297 for (PluginPackage availablePackage : pluginPackages) {
1298 _indexPluginPackage(availablePackage);
1299 }
1300 }
1301 catch (PluginPackageException ppe) {
1302 if (_log.isWarnEnabled()) {
1303 _log.warn(
1304 "Unable to reindex unistalled package " +
1305 pluginPackage.getContext() + ": " + ppe.getMessage());
1306 }
1307 }
1308 }
1309
1310 private void _updateInstallingPluginPackage(
1311 String preliminaryContext, PluginPackage pluginPackage) {
1312
1313 _installedPluginPackages.unregisterPluginPackageInstallation(
1314 preliminaryContext);
1315 _installedPluginPackages.registerPluginPackageInstallation(
1316 pluginPackage);
1317 }
1318
1319 private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1320
1321 private static PluginPackageUtil _instance = new PluginPackageUtil();
1322
1323 private LocalPluginPackageRepository _installedPluginPackages;
1324 private Map<String, RemotePluginPackageRepository> _repositoryCache;
1325 private Set<String> _availableTagsCache;
1326 private Date _lastUpdateDate;
1327 private Boolean _updateAvailable;
1328 private boolean _settingUpdateAvailable;
1329
1330 private class UpdateAvailableRunner implements Runnable {
1331
1332 public void run() {
1333 try {
1334 setUpdateAvailable();
1335 }
1336 catch (Exception e) {
1337 if (_log.isWarnEnabled()) {
1338 _log.warn(e.getMessage());
1339 }
1340 }
1341 }
1342
1343 protected void setUpdateAvailable() throws Exception {
1344 StopWatch stopWatch = null;
1345
1346 if (_log.isInfoEnabled()) {
1347 _log.info("Checking for available updates");
1348
1349 stopWatch = new StopWatch();
1350
1351 stopWatch.start();
1352 }
1353
1354 for (PluginPackage pluginPackage :
1355 _installedPluginPackages.getPluginPackages()) {
1356
1357 PluginPackage availablePluginPackage = null;
1358
1359 if (_isIgnored(pluginPackage)) {
1360 continue;
1361 }
1362
1363 availablePluginPackage =
1364 PluginPackageUtil.getLatestAvailablePluginPackage(
1365 pluginPackage.getGroupId(),
1366 pluginPackage.getArtifactId());
1367
1368 if (availablePluginPackage == null) {
1369 continue;
1370 }
1371
1372 Version availablePluginPackageVersion = Version.getInstance(
1373 availablePluginPackage.getVersion());
1374
1375 if (availablePluginPackageVersion.isLaterVersionThan(
1376 pluginPackage.getVersion())) {
1377
1378 _updateAvailable = Boolean.TRUE;
1379
1380 break;
1381 }
1382 }
1383
1384 if (_updateAvailable == null) {
1385 _updateAvailable = Boolean.FALSE;
1386 }
1387
1388 _settingUpdateAvailable = false;
1389
1390 if (_log.isInfoEnabled()) {
1391 _log.info(
1392 "Finished checking for available updates in " +
1393 stopWatch.getTime() + " ms");
1394 }
1395 }
1396 }
1397
1398}