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