1
14
15 package com.liferay.portal.plugin;
16
17 import com.liferay.portal.kernel.exception.PortalException;
18 import com.liferay.portal.kernel.exception.SystemException;
19 import com.liferay.portal.kernel.log.Log;
20 import com.liferay.portal.kernel.log.LogFactoryUtil;
21 import com.liferay.portal.kernel.plugin.License;
22 import com.liferay.portal.kernel.plugin.PluginPackage;
23 import com.liferay.portal.kernel.plugin.RemotePluginPackageRepository;
24 import com.liferay.portal.kernel.plugin.Screenshot;
25 import com.liferay.portal.kernel.plugin.Version;
26 import com.liferay.portal.kernel.search.Hits;
27 import com.liferay.portal.kernel.search.Indexer;
28 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
29 import com.liferay.portal.kernel.search.SearchContext;
30 import com.liferay.portal.kernel.util.ArrayUtil;
31 import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
32 import com.liferay.portal.kernel.util.GetterUtil;
33 import com.liferay.portal.kernel.util.HtmlUtil;
34 import com.liferay.portal.kernel.util.Http;
35 import com.liferay.portal.kernel.util.HttpUtil;
36 import com.liferay.portal.kernel.util.PropsKeys;
37 import com.liferay.portal.kernel.util.ReleaseInfo;
38 import com.liferay.portal.kernel.util.StringBundler;
39 import com.liferay.portal.kernel.util.StringPool;
40 import com.liferay.portal.kernel.util.StringUtil;
41 import com.liferay.portal.kernel.util.Time;
42 import com.liferay.portal.kernel.util.Validator;
43 import com.liferay.portal.kernel.xml.Attribute;
44 import com.liferay.portal.kernel.xml.Document;
45 import com.liferay.portal.kernel.xml.DocumentException;
46 import com.liferay.portal.kernel.xml.Element;
47 import com.liferay.portal.kernel.xml.SAXReaderUtil;
48 import com.liferay.portal.model.CompanyConstants;
49 import com.liferay.portal.model.Plugin;
50 import com.liferay.portal.model.User;
51 import com.liferay.portal.util.HttpImpl;
52 import com.liferay.portal.util.PrefsPropsUtil;
53 import com.liferay.portal.util.PropsValues;
54
55 import java.io.IOException;
56 import java.io.Serializable;
57
58 import java.net.MalformedURLException;
59
60 import java.text.DateFormat;
61
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collection;
65 import java.util.Date;
66 import java.util.HashMap;
67 import java.util.Iterator;
68 import java.util.List;
69 import java.util.Locale;
70 import java.util.Map;
71 import java.util.Properties;
72 import java.util.Set;
73 import java.util.TreeSet;
74
75 import javax.servlet.http.HttpServletResponse;
76
77 import org.apache.commons.httpclient.HostConfiguration;
78 import org.apache.commons.httpclient.HttpClient;
79 import org.apache.commons.httpclient.methods.GetMethod;
80 import org.apache.commons.lang.time.StopWatch;
81
82
89 public class PluginPackageUtil {
90
91 public static final String REPOSITORY_XML_FILENAME_EXTENSION =
92 "xml";
93
94 public static final String REPOSITORY_XML_FILENAME_PREFIX =
95 "liferay-plugin-repository";
96
97 public static void endPluginPackageInstallation(String preliminaryContext) {
98 _instance._endPluginPackageInstallation(preliminaryContext);
99 }
100
101 public static List<PluginPackage> getAllAvailablePluginPackages()
102 throws PortalException, SystemException {
103
104 return _instance._getAllAvailablePluginPackages();
105 }
106
107 public static Collection<String> getAvailableTags() {
108 return _instance._getAvailableTags();
109 }
110
111 public static List<PluginPackage> getInstalledPluginPackages() {
112 return _instance._getInstalledPluginPackages();
113 }
114
115 public static Date getLastUpdateDate() {
116 return _instance._getLastUpdateDate();
117 }
118
119 public static PluginPackage getLatestAvailablePluginPackage(
120 String groupId, String artifactId)
121 throws PortalException, SystemException {
122
123 return _instance._getLatestAvailablePluginPackage(groupId, artifactId);
124 }
125
126 public static PluginPackage getLatestInstalledPluginPackage(
127 String groupId, String artifactId) {
128
129 return _instance._getLatestInstalledPluginPackage(groupId, artifactId);
130 }
131
132 public static PluginPackage getPluginPackageByModuleId(
133 String moduleId, String repositoryURL)
134 throws PortalException, SystemException {
135
136 return _instance._getPluginPackageByModuleId(moduleId, repositoryURL);
137 }
138
139 public static PluginPackage getPluginPackageByURL(String url)
140 throws PortalException, SystemException {
141
142 return _instance._getPluginPackageByURL(url);
143 }
144
145 public static RemotePluginPackageRepository getRepository(
146 String repositoryURL)
147 throws PortalException, SystemException {
148
149 return _instance._getRepository(repositoryURL);
150 }
151
152 public static String[] getStatusAndInstalledVersion(
153 PluginPackage pluginPackage) {
154
155 return _instance._getStatusAndInstalledVersion(pluginPackage);
156 }
157
158 public static String[] getRepositoryURLs() throws SystemException {
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 SystemException {
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(Element pluginPackageEl) {
197 return _instance._readPluginPackageXml(pluginPackageEl);
198 }
199
200 public static PluginPackage readPluginPackageXml(String xml)
201 throws DocumentException {
202
203 return _instance._readPluginPackageXml(xml);
204 }
205
206 public static void refreshUpdatesAvailableCache() {
207 _instance._refreshUpdatesAvailableCache();
208 }
209
210 public static void registerInstalledPluginPackage(
211 PluginPackage pluginPackage)
212 throws PortalException {
213
214 _instance._registerInstalledPluginPackage(pluginPackage);
215 }
216
217 public static void registerPluginPackageInstallation(
218 String preliminaryContext) {
219
220 _instance._registerPluginPackageInstallation(preliminaryContext);
221 }
222
223 public static RepositoryReport reloadRepositories()
224 throws PortalException, SystemException {
225
226 return _instance._reloadRepositories();
227 }
228
229 public static Hits search(
230 String keywords, String type, String tag, String license,
231 String repositoryURL, String status, int start, int end)
232 throws PortalException, SystemException {
233
234 return _instance._search(
235 keywords, type, tag, license, repositoryURL, status, start, end);
236 }
237
238 public static void unregisterInstalledPluginPackage(
239 PluginPackage pluginPackage)
240 throws PortalException, SystemException {
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 PortalException, SystemException {
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 PortalException, SystemException {
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 PortalException, SystemException {
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 Date _getLastUpdateDate() {
360 return _lastUpdateDate;
361 }
362
363 private PluginPackage _getLatestAvailablePluginPackage(
364 String groupId, String artifactId)
365 throws PortalException, SystemException {
366
367 List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
368 groupId, artifactId);
369
370 return _findLatestVersion(pluginPackages);
371 }
372
373 private PluginPackage _getLatestInstalledPluginPackage(
374 String groupId, String artifactId) {
375
376 return _installedPluginPackages.getLatestPluginPackage(
377 groupId, artifactId);
378 }
379
380 private PluginPackage _getPluginPackageByModuleId(
381 String moduleId, String repositoryURL)
382 throws PortalException, SystemException {
383
384 RemotePluginPackageRepository repository = _getRepository(
385 repositoryURL);
386
387 return repository.findPluginPackageByModuleId(moduleId);
388 }
389
390 private PluginPackage _getPluginPackageByURL(String url)
391 throws PortalException, SystemException {
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 PortalException, SystemException {
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 throws PortalException {
481
482 Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
483
484 indexer.reindex(pluginPackage);
485 }
486
487 private boolean _isCurrentVersionSupported(List<String> versions) {
488 Version currentVersion = Version.getInstance(ReleaseInfo.getVersion());
489
490 for (String version : versions) {
491 Version supportedVersion = Version.getInstance(version);
492
493 if (supportedVersion.includes(currentVersion)) {
494 return true;
495 }
496 }
497
498 return false;
499 }
500
501 private boolean _isIgnored(PluginPackage pluginPackage)
502 throws SystemException {
503
504 String packageId = pluginPackage.getPackageId();
505
506 String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
507 PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
508 StringPool.NEW_LINE,
509 PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
510
511 for (int i = 0; i < pluginPackagesIgnored.length; i++) {
512 String curPluginPackagesIgnored = pluginPackagesIgnored[i];
513
514 if (curPluginPackagesIgnored.endsWith(StringPool.STAR)) {
515 String prefix = curPluginPackagesIgnored.substring(
516 0, curPluginPackagesIgnored.length() - 2);
517
518 if (packageId.startsWith(prefix)) {
519 return true;
520 }
521 }
522 else {
523 if (packageId.equals(curPluginPackagesIgnored)) {
524 return true;
525 }
526 }
527 }
528
529 return false;
530 }
531
532 private boolean _isInstallationInProcess(String context) {
533 if (_installedPluginPackages.getInstallingPluginPackage(
534 context) != null) {
535
536 return true;
537 }
538 else {
539 return false;
540 }
541 }
542
543 private boolean _isTrusted(String repositoryURL)
544 throws PluginPackageException {
545
546 try {
547 String[] trusted = PrefsPropsUtil.getStringArray(
548 PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
549 PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
550
551 if (ArrayUtil.contains(trusted, repositoryURL)) {
552 return true;
553 }
554 else {
555 return false;
556 }
557 }
558 catch (Exception e) {
559 throw new PluginPackageException(
560 "Unable to read repository list", e);
561 }
562 }
563
564 private boolean _isUpdateAvailable() throws SystemException {
565 if (!PrefsPropsUtil.getBoolean(
566 PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
567 PropsValues.PLUGIN_NOTIFICATIONS_ENABLED)) {
568
569 return false;
570 }
571
572 if (_updateAvailable != null) {
573 return _updateAvailable.booleanValue();
574 }
575 else if (!_settingUpdateAvailable) {
576 _settingUpdateAvailable = true;
577
578 Thread indexerThread = new Thread(
579 new UpdateAvailableRunner(), PluginPackageUtil.class.getName());
580
581 indexerThread.setPriority(Thread.MIN_PRIORITY);
582
583 indexerThread.start();
584 }
585
586 return false;
587 }
588
589 private RemotePluginPackageRepository _loadRepository(String repositoryURL)
590 throws PluginPackageException, PortalException {
591
592 RemotePluginPackageRepository repository = null;
593
594 StringBundler sb = new StringBundler(8);
595
596 if (!repositoryURL.startsWith(Http.HTTP_WITH_SLASH) &&
597 !repositoryURL.startsWith(Http.HTTPS_WITH_SLASH)) {
598
599 sb.append(Http.HTTP_WITH_SLASH);
600 }
601
602 sb.append(repositoryURL);
603 sb.append(StringPool.SLASH);
604 sb.append(REPOSITORY_XML_FILENAME_PREFIX);
605 sb.append(StringPool.DASH);
606 sb.append(ReleaseInfo.getVersion());
607 sb.append(StringPool.PERIOD);
608 sb.append(REPOSITORY_XML_FILENAME_EXTENSION);
609
610 String pluginsXmlURL = sb.toString();
611
612 try {
613 HttpImpl httpImpl = (HttpImpl)HttpUtil.getHttp();
614
615 HostConfiguration hostConfig = httpImpl.getHostConfig(
616 pluginsXmlURL);
617
618 HttpClient client = httpImpl.getClient(hostConfig);
619
620 GetMethod getFileMethod = new GetMethod(pluginsXmlURL);
621
622 byte[] bytes = null;
623
624 try {
625 int responseCode = client.executeMethod(
626 hostConfig, getFileMethod);
627
628 if (responseCode != HttpServletResponse.SC_OK) {
629 if (_log.isDebugEnabled()) {
630 _log.debug(
631 "A repository for version " +
632 ReleaseInfo.getVersion() + " was not found. " +
633 "Checking general repository");
634 }
635
636 sb.setIndex(0);
637
638 sb.append(repositoryURL);
639 sb.append(StringPool.SLASH);
640 sb.append(REPOSITORY_XML_FILENAME_PREFIX);
641 sb.append(StringPool.PERIOD);
642 sb.append(REPOSITORY_XML_FILENAME_EXTENSION);
643
644 pluginsXmlURL = sb.toString();
645
646 getFileMethod.releaseConnection();
647
648 getFileMethod = new GetMethod(pluginsXmlURL);
649
650 responseCode = client.executeMethod(
651 hostConfig, getFileMethod);
652
653 if (responseCode != HttpServletResponse.SC_OK) {
654 throw new PluginPackageException(
655 "Unable to download file " + pluginsXmlURL +
656 " because of response code " + responseCode);
657 }
658 }
659
660 bytes = getFileMethod.getResponseBody();
661 }
662 finally {
663 getFileMethod.releaseConnection();
664 }
665
666 if ((bytes != null) && (bytes.length > 0)) {
667 repository = _parseRepositoryXml(
668 new String(bytes), repositoryURL);
669
670 _repositoryCache.put(repositoryURL, repository);
671 _availableTagsCache.addAll(repository.getTags());
672 _lastUpdateDate = new Date();
673 _updateAvailable = null;
674
675 return repository;
676 }
677 else {
678 _lastUpdateDate = new Date();
679
680 throw new PluginPackageException("Download returned 0 bytes");
681 }
682 }
683 catch (MalformedURLException mue) {
684 _repositoryCache.remove(repositoryURL);
685
686 throw new PluginPackageException(
687 "Invalid URL " + pluginsXmlURL, mue);
688 }
689 catch (IOException ioe) {
690 _repositoryCache.remove(repositoryURL);
691
692 throw new PluginPackageException(
693 "Unable to communicate with repository " + repositoryURL, ioe);
694 }
695 catch (DocumentException de) {
696 _repositoryCache.remove(repositoryURL);
697
698 throw new PluginPackageException(
699 "Unable to parse plugin list for repository " + repositoryURL,
700 de);
701 }
702 }
703
704 private RemotePluginPackageRepository _parseRepositoryXml(
705 String xml, String repositoryURL)
706 throws DocumentException, PortalException {
707
708 List<String> supportedPluginTypes = Arrays.asList(getSupportedTypes());
709
710 if (_log.isDebugEnabled()) {
711 _log.debug(
712 "Loading plugin repository " + repositoryURL + ":\n" + xml);
713 }
714
715 RemotePluginPackageRepository pluginPackageRepository =
716 new RemotePluginPackageRepository(repositoryURL);
717
718 if (xml == null) {
719 return pluginPackageRepository;
720 }
721
722 Document doc = SAXReaderUtil.read(xml);
723
724 Element root = doc.getRootElement();
725
726 Properties settings = _readProperties(
727 root.element("settings"), "setting");
728
729 pluginPackageRepository.setSettings(settings);
730
731 Iterator<Element> itr1 = root.elements("plugin-package").iterator();
732
733 while (itr1.hasNext()) {
734 Element pluginPackageEl = itr1.next();
735
736 PluginPackage pluginPackage = _readPluginPackageXml(
737 pluginPackageEl);
738
739 if (!_isCurrentVersionSupported(
740 pluginPackage.getLiferayVersions())) {
741
742 continue;
743 }
744
745 Iterator<String> itr2 = pluginPackage.getTypes().iterator();
746
747 boolean containsSupportedTypes = false;
748
749 while (itr2.hasNext()) {
750 String type = itr2.next();
751
752 if (supportedPluginTypes.contains(type)) {
753 containsSupportedTypes = true;
754
755 break;
756 }
757 }
758
759 if (!containsSupportedTypes) {
760 continue;
761 }
762
763 pluginPackage.setRepository(pluginPackageRepository);
764
765 pluginPackageRepository.addPluginPackage(pluginPackage);
766
767 _indexPluginPackage(pluginPackage);
768 }
769
770 return pluginPackageRepository;
771 }
772
773 private Date _readDate(String text) {
774 if (Validator.isNotNull(text)) {
775 DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
776 Time.RFC822_FORMAT, Locale.US);
777
778 try {
779 return dateFormat.parse(text);
780 }
781 catch (Exception e) {
782 if (_log.isWarnEnabled()) {
783 _log.warn("Unable to parse date " + text);
784 }
785 }
786 }
787
788 return new Date();
789 }
790
791 private String _readHtml(String text) {
792 return GetterUtil.getString(text);
793 }
794
795 private List<License> _readLicenseList(Element parentEL, String name) {
796 List<License> licenses = new ArrayList<License>();
797
798 Iterator<Element> itr = parentEL.elements(name).iterator();
799
800 while (itr.hasNext()) {
801 Element licenseEl = itr.next();
802
803 License license = new License();
804
805 license.setName(licenseEl.getText());
806
807 Attribute osiApproved = licenseEl.attribute("osi-approved");
808
809 if (osiApproved != null) {
810 license.setOsiApproved(
811 GetterUtil.getBoolean(osiApproved.getText()));
812 }
813
814 Attribute url = licenseEl.attribute("url");
815
816 if (url != null) {
817 license.setUrl(url.getText());
818 }
819
820 licenses.add(license);
821 }
822
823 return licenses;
824 }
825 private List<String> _readList(Element parentEl, String name) {
826 List<String> result = new ArrayList<String>();
827
828 if (parentEl != null) {
829 Iterator<Element> itr = parentEl.elements(name).iterator();
830
831 while (itr.hasNext()) {
832 Element el = itr.next();
833
834 String text = el.getText().trim().toLowerCase();
835
836 result.add(text);
837 }
838 }
839
840 return result;
841 }
842 private PluginPackage _readPluginPackageProperties(
843 String displayName, Properties properties) {
844
845 int pos = displayName.indexOf("-portlet");
846
847 String pluginType = Plugin.TYPE_PORTLET;
848
849 if (pos == -1) {
850 pos = displayName.indexOf("-ext");
851
852 pluginType = Plugin.TYPE_EXT;
853 }
854
855 if (pos == -1) {
856 pos = displayName.indexOf("-hook");
857
858 pluginType = Plugin.TYPE_HOOK;
859 }
860
861 if (pos == -1) {
862 pos = displayName.indexOf("-layouttpl");
863
864 pluginType = Plugin.TYPE_LAYOUT_TEMPLATE;
865 }
866
867 if (pos == -1) {
868 pos = displayName.indexOf("-theme");
869
870 pluginType = Plugin.TYPE_THEME;
871 }
872
873 if (pos == -1) {
874 pos = displayName.indexOf("-web");
875
876 pluginType = Plugin.TYPE_WEB;
877 }
878
879 if (pos == -1) {
880 return null;
881 }
882
883 String displayPrefix = displayName.substring(0, pos);
884
885 String moduleGroupId = GetterUtil.getString(
886 properties.getProperty("module-group-id"));
887 String moduleArtifactId = displayPrefix + "-" + pluginType;
888
889 String moduleVersion = null;
890
891 int moduleVersionPos = pos + pluginType.length() + 2;
892
893 if (displayName.length() > moduleVersionPos) {
894 moduleVersion = displayName.substring(moduleVersionPos);
895 }
896 else {
897 moduleVersion = ReleaseInfo.getVersion();
898 }
899
900 String moduleId =
901 moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
902 "/war";
903
904 String pluginName = GetterUtil.getString(
905 properties.getProperty("name"));
906
907 String deploymentContext = GetterUtil.getString(
908 properties.getProperty("recommended-deployment-context"),
909 moduleArtifactId);
910
911 String author = GetterUtil.getString(properties.getProperty("author"));
912
913 List<String> types = new ArrayList<String>();
914
915 types.add(pluginType);
916
917 List<License> licenses = new ArrayList<License>();
918
919 String[] licensesArray = StringUtil.split(
920 properties.getProperty("licenses"));
921
922 for (int i = 0; i < licensesArray.length; i++) {
923 License license = new License();
924
925 license.setName(licensesArray[i].trim());
926 license.setOsiApproved(true);
927
928 licenses.add(license);
929 }
930
931 List<String> liferayVersions = new ArrayList<String>();
932
933 String[] liferayVersionsArray = StringUtil.split(
934 properties.getProperty("liferay-versions"));
935
936 for (String liferayVersion : liferayVersionsArray) {
937 liferayVersions.add(liferayVersion.trim());
938 }
939
940 if (liferayVersions.size() == 0) {
941 liferayVersions.add(ReleaseInfo.getVersion() + "+");
942 }
943
944 List<String> tags = new ArrayList<String>();
945
946 String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
947
948 for (String tag : tagsArray) {
949 tags.add(tag.trim());
950 }
951
952 String shortDescription = GetterUtil.getString(
953 properties.getProperty("short-description"));
954 String longDescription = GetterUtil.getString(
955 properties.getProperty("long-description"));
956 String changeLog = GetterUtil.getString(
957 properties.getProperty("change-log"));
958 String pageURL = GetterUtil.getString(
959 properties.getProperty("page-url"));
960 String downloadURL = GetterUtil.getString(
961 properties.getProperty("download-url"));
962
963 PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
964
965 pluginPackage.setName(pluginName);
966 pluginPackage.setRecommendedDeploymentContext(deploymentContext);
967 pluginPackage.setAuthor(author);
969 pluginPackage.setTypes(types);
970 pluginPackage.setLicenses(licenses);
971 pluginPackage.setLiferayVersions(liferayVersions);
972 pluginPackage.setTags(tags);
973 pluginPackage.setShortDescription(shortDescription);
974 pluginPackage.setLongDescription(longDescription);
975 pluginPackage.setChangeLog(changeLog);
976 pluginPackage.setPageURL(pageURL);
978 pluginPackage.setDownloadURL(downloadURL);
979
981 return pluginPackage;
982 }
983 private PluginPackage _readPluginPackageXml(Element pluginPackageEl) {
984 String name = pluginPackageEl.elementText("name");
985
986 if (_log.isDebugEnabled()) {
987 _log.debug("Reading pluginPackage definition " + name);
988 }
989
990 PluginPackage pluginPackage = new PluginPackageImpl(
991 GetterUtil.getString(pluginPackageEl.elementText("module-id")));
992
993 List<String> liferayVersions = _readList(
994 pluginPackageEl.element("liferay-versions"), "liferay-version");
995
996 List<String> types = _readList(
997 pluginPackageEl.element("types"), "type");
998
999 pluginPackage.setName(_readText(name));
1000 pluginPackage.setRecommendedDeploymentContext(
1001 _readText(
1002 pluginPackageEl.elementText("recommended-deployment-context")));
1003 pluginPackage.setModifiedDate(
1004 _readDate(pluginPackageEl.elementText("modified-date")));
1005 pluginPackage.setAuthor(
1006 _readText(pluginPackageEl.elementText("author")));
1007 pluginPackage.setTypes(types);
1008 pluginPackage.setLicenses(
1009 _readLicenseList(
1010 pluginPackageEl.element("licenses"), "license"));
1011 pluginPackage.setLiferayVersions(liferayVersions);
1012 pluginPackage.setTags(
1013 _readList(pluginPackageEl.element("tags"), "tag"));
1014 pluginPackage.setShortDescription(
1015 _readText(pluginPackageEl.elementText("short-description")));
1016 pluginPackage.setLongDescription(
1017 _readHtml(pluginPackageEl.elementText("long-description")));
1018 pluginPackage.setChangeLog(
1019 _readHtml(pluginPackageEl.elementText("change-log")));
1020 pluginPackage.setScreenshots(
1021 _readScreenshots(pluginPackageEl.element("screenshots")));
1022 pluginPackage.setPageURL(
1023 _readText(pluginPackageEl.elementText("page-url")));
1024 pluginPackage.setDownloadURL(
1025 _readText(pluginPackageEl.elementText("download-url")));
1026 pluginPackage.setDeploymentSettings(
1027 _readProperties(
1028 pluginPackageEl.element("deployment-settings"), "setting"));
1029
1030 return pluginPackage;
1031 }
1032 private PluginPackage _readPluginPackageXml(String xml)
1033 throws DocumentException {
1034
1035 Document doc = SAXReaderUtil.read(xml);
1036
1037 Element root = doc.getRootElement();
1038
1039 return _readPluginPackageXml(root);
1040 }
1041 private Properties _readProperties(Element parentEl, String name) {
1042 Properties result = new Properties();
1043
1044 if (parentEl != null) {
1045 Iterator<Element> itr = parentEl.elements(name).iterator();
1046
1047 while (itr.hasNext()) {
1048 Element el = itr.next();
1049
1050 result.setProperty(
1051 el.attribute("name").getValue(),
1052 el.attribute("value").getValue());
1053 }
1054 }
1055
1056 return result;
1057 }
1058
1059 private List<Screenshot> _readScreenshots(Element parentEl) {
1060 List<Screenshot> screenshots = new ArrayList<Screenshot>();
1061
1062 if (parentEl != null) {
1063 Iterator<Element> itr = parentEl.elements("screenshot").iterator();
1064
1065 while (itr.hasNext()) {
1066 Element screenshotEl = itr.next();
1067
1068 Screenshot screenshot = new Screenshot();
1069
1070 screenshot.setThumbnailURL(
1071 screenshotEl.element("thumbnail-url").getText());
1072 screenshot.setLargeImageURL(
1073 screenshotEl.element("large-image-url").getText());
1074
1075 screenshots.add(screenshot);
1076 }
1077 }
1078
1079 return screenshots;
1080 }
1081
1082 private String _readText(String text) {
1083 return HtmlUtil.extractText(GetterUtil.getString(text));
1084 }
1085
1086 private void _refreshUpdatesAvailableCache() {
1087 _updateAvailable = null;
1088 }
1089
1090 private void _registerInstalledPluginPackage(
1091 PluginPackage pluginPackage)
1092 throws PortalException {
1093
1094 _installedPluginPackages.addPluginPackage(pluginPackage);
1095
1096 _updateAvailable = null;
1097
1098 _indexPluginPackage(pluginPackage);
1099 }
1100
1101 private void _registerPluginPackageInstallation(
1102 String preliminaryContext) {
1103
1104 _installedPluginPackages.registerPluginPackageInstallation(
1105 preliminaryContext);
1106 }
1107
1108 private RepositoryReport _reloadRepositories()
1109 throws PortalException, SystemException {
1110
1111 if (_log.isInfoEnabled()) {
1112 _log.info("Reloading repositories");
1113 }
1114
1115 RepositoryReport repositoryReport = new RepositoryReport();
1116
1117 String[] repositoryURLs = _getRepositoryURLs();
1118
1119 for (int i = 0; i < repositoryURLs.length; i++) {
1120 String repositoryURL = repositoryURLs[i];
1121
1122 try {
1123 _loadRepository(repositoryURL);
1124
1125 repositoryReport.addSuccess(repositoryURL);
1126 }
1127 catch (PluginPackageException pe) {
1128 repositoryReport.addError(repositoryURL, pe);
1129
1130 _log.error(
1131 "Unable to load repository " + repositoryURL + " " +
1132 pe.toString());
1133 }
1134
1135 }
1136
1137 Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1138
1139 indexer.reindex(new String[0]);
1140
1141 return repositoryReport;
1142 }
1143
1144 private Hits _search(
1145 String keywords, String type, String tag, String license,
1146 String repositoryURL, String status, int start, int end)
1147 throws PortalException, SystemException {
1148
1149 _checkRepositories(repositoryURL);
1150
1151 Map<String, Serializable> attributes =
1152 new HashMap<String, Serializable>();
1153
1154 attributes.put("license", license);
1155 attributes.put("repositoryURL", repositoryURL);
1156 attributes.put("status", status);
1157 attributes.put("tag", tag);
1158 attributes.put("type", type);
1159
1160 SearchContext searchContext = new SearchContext();
1161
1162 searchContext.setAttributes(attributes);
1163 searchContext.setCompanyId(CompanyConstants.SYSTEM);
1164 searchContext.setEnd(end);
1165 searchContext.setKeywords(keywords);
1166 searchContext.setStart(start);
1167
1168 Indexer indexer = IndexerRegistryUtil.getIndexer(User.class);
1169
1170 return indexer.search(searchContext);
1171 }
1172
1173 private void _unregisterInstalledPluginPackage(
1174 PluginPackage pluginPackage)
1175 throws PortalException, SystemException {
1176
1177 _installedPluginPackages.removePluginPackage(pluginPackage);
1178
1179 try {
1180 List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1181 pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1182
1183 for (PluginPackage availablePackage : pluginPackages) {
1184 _indexPluginPackage(availablePackage);
1185 }
1186 }
1187 catch (PluginPackageException ppe) {
1188 if (_log.isWarnEnabled()) {
1189 _log.warn(
1190 "Unable to reindex unistalled package " +
1191 pluginPackage.getContext() + ": " + ppe.getMessage());
1192 }
1193 }
1194 }
1195
1196 private void _updateInstallingPluginPackage(
1197 String preliminaryContext, PluginPackage pluginPackage) {
1198
1199 _installedPluginPackages.unregisterPluginPackageInstallation(
1200 preliminaryContext);
1201 _installedPluginPackages.registerPluginPackageInstallation(
1202 pluginPackage);
1203 }
1204
1205 private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1206
1207 private static PluginPackageUtil _instance = new PluginPackageUtil();
1208
1209 private Set<String> _availableTagsCache;
1210 private LocalPluginPackageRepository _installedPluginPackages;
1211 private Date _lastUpdateDate;
1212 private Map<String, RemotePluginPackageRepository> _repositoryCache;
1213 private boolean _settingUpdateAvailable;
1214 private Boolean _updateAvailable;
1215
1216 private class UpdateAvailableRunner implements Runnable {
1217
1218 public void run() {
1219 try {
1220 setUpdateAvailable();
1221 }
1222 catch (Exception e) {
1223 if (_log.isWarnEnabled()) {
1224 _log.warn(e.getMessage());
1225 }
1226 }
1227 }
1228
1229 protected void setUpdateAvailable() throws Exception {
1230 StopWatch stopWatch = null;
1231
1232 if (_log.isInfoEnabled()) {
1233 _log.info("Checking for available updates");
1234
1235 stopWatch = new StopWatch();
1236
1237 stopWatch.start();
1238 }
1239
1240 for (PluginPackage pluginPackage :
1241 _installedPluginPackages.getPluginPackages()) {
1242
1243 PluginPackage availablePluginPackage = null;
1244
1245 if (_isIgnored(pluginPackage)) {
1246 continue;
1247 }
1248
1249 availablePluginPackage =
1250 PluginPackageUtil.getLatestAvailablePluginPackage(
1251 pluginPackage.getGroupId(),
1252 pluginPackage.getArtifactId());
1253
1254 if (availablePluginPackage == null) {
1255 continue;
1256 }
1257
1258 Version availablePluginPackageVersion = Version.getInstance(
1259 availablePluginPackage.getVersion());
1260
1261 if (availablePluginPackageVersion.isLaterVersionThan(
1262 pluginPackage.getVersion())) {
1263
1264 _updateAvailable = Boolean.TRUE;
1265
1266 break;
1267 }
1268 }
1269
1270 if (_updateAvailable == null) {
1271 _updateAvailable = Boolean.FALSE;
1272 }
1273
1274 _settingUpdateAvailable = false;
1275
1276 if (_log.isInfoEnabled()) {
1277 _log.info(
1278 "Finished checking for available updates in " +
1279 stopWatch.getTime() + " ms");
1280 }
1281 }
1282 }
1283
1284}