001
014
015 package com.liferay.portal.plugin;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.plugin.License;
022 import com.liferay.portal.kernel.plugin.PluginPackage;
023 import com.liferay.portal.kernel.plugin.RemotePluginPackageRepository;
024 import com.liferay.portal.kernel.plugin.Screenshot;
025 import com.liferay.portal.kernel.plugin.Version;
026 import com.liferay.portal.kernel.search.Hits;
027 import com.liferay.portal.kernel.search.Indexer;
028 import com.liferay.portal.kernel.search.IndexerRegistryUtil;
029 import com.liferay.portal.kernel.search.QueryConfig;
030 import com.liferay.portal.kernel.search.SearchContext;
031 import com.liferay.portal.kernel.util.ArrayUtil;
032 import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
033 import com.liferay.portal.kernel.util.GetterUtil;
034 import com.liferay.portal.kernel.util.HtmlUtil;
035 import com.liferay.portal.kernel.util.Http;
036 import com.liferay.portal.kernel.util.HttpUtil;
037 import com.liferay.portal.kernel.util.ListUtil;
038 import com.liferay.portal.kernel.util.LocaleUtil;
039 import com.liferay.portal.kernel.util.PropertiesUtil;
040 import com.liferay.portal.kernel.util.PropsKeys;
041 import com.liferay.portal.kernel.util.ReleaseInfo;
042 import com.liferay.portal.kernel.util.StringBundler;
043 import com.liferay.portal.kernel.util.StringPool;
044 import com.liferay.portal.kernel.util.StringUtil;
045 import com.liferay.portal.kernel.util.Time;
046 import com.liferay.portal.kernel.util.Validator;
047 import com.liferay.portal.kernel.xml.Attribute;
048 import com.liferay.portal.kernel.xml.Document;
049 import com.liferay.portal.kernel.xml.DocumentException;
050 import com.liferay.portal.kernel.xml.Element;
051 import com.liferay.portal.kernel.xml.SAXReaderUtil;
052 import com.liferay.portal.model.CompanyConstants;
053 import com.liferay.portal.model.Plugin;
054 import com.liferay.portal.util.PrefsPropsUtil;
055 import com.liferay.portal.util.PropsValues;
056
057 import java.io.IOException;
058 import java.io.InputStream;
059 import java.io.Serializable;
060
061 import java.net.MalformedURLException;
062
063 import java.text.DateFormat;
064
065 import java.util.ArrayList;
066 import java.util.Arrays;
067 import java.util.Collection;
068 import java.util.Date;
069 import java.util.HashMap;
070 import java.util.List;
071 import java.util.Map;
072 import java.util.Properties;
073 import java.util.Set;
074 import java.util.TreeSet;
075 import java.util.jar.Attributes;
076 import java.util.jar.Manifest;
077
078 import javax.servlet.ServletContext;
079 import javax.servlet.http.HttpServletResponse;
080
081 import org.apache.commons.lang.time.StopWatch;
082
083
088 public class PluginPackageUtil {
089
090 public static void endPluginPackageInstallation(String preliminaryContext) {
091 _instance._endPluginPackageInstallation(preliminaryContext);
092 }
093
094 public static List<PluginPackage> getAllAvailablePluginPackages()
095 throws PortalException, SystemException {
096
097 return _instance._getAllAvailablePluginPackages();
098 }
099
100 public static Collection<String> getAvailableTags() {
101 return _instance._getAvailableTags();
102 }
103
104 public static PluginPackage getInstalledPluginPackage(String context) {
105 return _instance._getInstalledPluginPackage(context);
106 }
107
108 public static List<PluginPackage> getInstalledPluginPackages() {
109 return _instance._getInstalledPluginPackages();
110 }
111
112 public static Date getLastUpdateDate() {
113 return _instance._getLastUpdateDate();
114 }
115
116 public static PluginPackage getLatestAvailablePluginPackage(
117 String groupId, String artifactId)
118 throws PortalException, SystemException {
119
120 return _instance._getLatestAvailablePluginPackage(groupId, artifactId);
121 }
122
123 public static PluginPackage getLatestInstalledPluginPackage(
124 String groupId, String artifactId) {
125
126 return _instance._getLatestInstalledPluginPackage(groupId, artifactId);
127 }
128
129 public static PluginPackage getPluginPackageByModuleId(
130 String moduleId, String repositoryURL)
131 throws PortalException, SystemException {
132
133 return _instance._getPluginPackageByModuleId(moduleId, repositoryURL);
134 }
135
136 public static PluginPackage getPluginPackageByURL(String url)
137 throws PortalException, SystemException {
138
139 return _instance._getPluginPackageByURL(url);
140 }
141
142 public static RemotePluginPackageRepository getRepository(
143 String repositoryURL)
144 throws PortalException, SystemException {
145
146 return _instance._getRepository(repositoryURL);
147 }
148
149 public static String[] getRepositoryURLs() throws SystemException {
150 return _instance._getRepositoryURLs();
151 }
152
153 public static String[] getStatusAndInstalledVersion(
154 PluginPackage pluginPackage) {
155
156 return _instance._getStatusAndInstalledVersion(pluginPackage);
157 }
158
159 public static String[] getSupportedTypes() {
160 return _instance._getSupportedTypes();
161 }
162
163 public static boolean isCurrentVersionSupported(List<String> versions) {
164 return _instance._isCurrentVersionSupported(versions);
165 }
166
167 public static boolean isIgnored(PluginPackage pluginPackage)
168 throws SystemException {
169
170 return _instance._isIgnored(pluginPackage);
171 }
172
173 public static boolean isInstallationInProcess(String context) {
174 return _instance._isInstallationInProcess(context);
175 }
176
177 public static boolean isInstalled(String context) {
178 return _instance._isInstalled(context);
179 }
180
181 public static boolean isTrusted(String repositoryURL)
182 throws SystemException {
183
184 return _instance._isTrusted(repositoryURL);
185 }
186
187 public static boolean isUpdateAvailable() throws SystemException {
188 return _instance._isUpdateAvailable();
189 }
190
191 public static PluginPackage readPluginPackageProperties(
192 String displayName, Properties properties) {
193
194 return _instance._readPluginPackageProperties(displayName, properties);
195 }
196
197 public static PluginPackage readPluginPackageServletContext(
198 ServletContext servletContext)
199 throws DocumentException, IOException {
200
201 return _instance._readPluginPackageServletContext(servletContext);
202 }
203
204 public static PluginPackage readPluginPackageXml(
205 Element pluginPackageElement) {
206
207 return _instance._readPluginPackageXml(pluginPackageElement);
208 }
209
210 public static PluginPackage readPluginPackageXml(String xml)
211 throws DocumentException {
212
213 return _instance._readPluginPackageXml(xml);
214 }
215
216 public static void refreshUpdatesAvailableCache() {
217 _instance._refreshUpdatesAvailableCache();
218 }
219
220 public static void registerInstalledPluginPackage(
221 PluginPackage pluginPackage)
222 throws PortalException {
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 RepositoryReport reloadRepositories()
234 throws PortalException, SystemException {
235
236 return _instance._reloadRepositories();
237 }
238
239 public static Hits search(
240 String keywords, String type, String tag, String license,
241 String repositoryURL, String status, int start, int end)
242 throws PortalException, SystemException {
243
244 return _instance._search(
245 keywords, type, tag, license, repositoryURL, status, start, end);
246 }
247
248 public static void unregisterInstalledPluginPackage(
249 PluginPackage pluginPackage)
250 throws PortalException, SystemException {
251
252 _instance._unregisterInstalledPluginPackage(pluginPackage);
253 }
254
255 public static void updateInstallingPluginPackage(
256 String preliminaryContext, PluginPackage pluginPackage) {
257
258 _instance._updateInstallingPluginPackage(
259 preliminaryContext, pluginPackage);
260 }
261
262 private PluginPackageUtil() {
263 _installedPluginPackages = new LocalPluginPackageRepository();
264 _repositoryCache = new HashMap<String, RemotePluginPackageRepository>();
265 _availableTagsCache = new TreeSet<String>();
266 }
267
268 private void _checkRepositories(String repositoryURL)
269 throws PortalException, SystemException {
270
271 String[] repositoryURLs = null;
272
273 if (Validator.isNotNull(repositoryURL)) {
274 repositoryURLs = new String[] {repositoryURL};
275 }
276 else {
277 repositoryURLs = _getRepositoryURLs();
278 }
279
280 for (int i = 0; i < repositoryURLs.length; i++) {
281 _getRepository(repositoryURLs[i]);
282 }
283 }
284
285 private void _endPluginPackageInstallation(String preliminaryContext) {
286 _installedPluginPackages.unregisterPluginPackageInstallation(
287 preliminaryContext);
288 }
289
290 private PluginPackage _findLatestVersion(
291 List<PluginPackage> pluginPackages) {
292
293 PluginPackage latestPluginPackage = null;
294
295 for (PluginPackage pluginPackage : pluginPackages) {
296 if ((latestPluginPackage == null) ||
297 pluginPackage.isLaterVersionThan(latestPluginPackage)) {
298
299 latestPluginPackage = pluginPackage;
300 }
301 }
302
303 return latestPluginPackage;
304 }
305
306 private List<PluginPackage> _getAllAvailablePluginPackages()
307 throws PortalException, SystemException {
308
309 List<PluginPackage> pluginPackages = new ArrayList<PluginPackage>();
310
311 String[] repositoryURLs = _getRepositoryURLs();
312
313 for (int i = 0; i < repositoryURLs.length; i++) {
314 try {
315 RemotePluginPackageRepository repository = _getRepository(
316 repositoryURLs[i]);
317
318 pluginPackages.addAll(repository.getPluginPackages());
319 }
320 catch (PluginPackageException ppe) {
321 String message = ppe.getMessage();
322
323 if (message.startsWith("Unable to communicate")) {
324 if (_log.isWarnEnabled()) {
325 _log.warn(message);
326 }
327 }
328 else {
329 _log.error(message);
330 }
331 }
332 }
333
334 return pluginPackages;
335 }
336
337 private List<PluginPackage> _getAvailablePluginPackages(
338 String groupId, String artifactId)
339 throws PortalException, SystemException {
340
341 List<PluginPackage> pluginPackages = new ArrayList<PluginPackage>();
342
343 String[] repositoryURLs = _getRepositoryURLs();
344
345 for (int i = 0; i < repositoryURLs.length; i++) {
346 RemotePluginPackageRepository repository = _getRepository(
347 repositoryURLs[i]);
348
349 List<PluginPackage> curPluginPackages =
350 repository.findPluginsByGroupIdAndArtifactId(
351 groupId, artifactId);
352
353 if (curPluginPackages != null) {
354 pluginPackages.addAll(curPluginPackages);
355 }
356 }
357
358 return pluginPackages;
359 }
360
361 private Collection<String> _getAvailableTags() {
362 return _availableTagsCache;
363 }
364
365 private PluginPackage _getInstalledPluginPackage(String context) {
366 return _installedPluginPackages.getPluginPackage(context);
367 }
368
369 private List<PluginPackage> _getInstalledPluginPackages() {
370 return _installedPluginPackages.getSortedPluginPackages();
371 }
372
373 private Date _getLastUpdateDate() {
374 return _lastUpdateDate;
375 }
376
377 private PluginPackage _getLatestAvailablePluginPackage(
378 String groupId, String artifactId)
379 throws PortalException, SystemException {
380
381 List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
382 groupId, artifactId);
383
384 return _findLatestVersion(pluginPackages);
385 }
386
387 private PluginPackage _getLatestInstalledPluginPackage(
388 String groupId, String artifactId) {
389
390 return _installedPluginPackages.getLatestPluginPackage(
391 groupId, artifactId);
392 }
393
394 private PluginPackage _getPluginPackageByModuleId(
395 String moduleId, String repositoryURL)
396 throws PortalException, SystemException {
397
398 RemotePluginPackageRepository repository = _getRepository(
399 repositoryURL);
400
401 return repository.findPluginPackageByModuleId(moduleId);
402 }
403
404 private PluginPackage _getPluginPackageByURL(String url)
405 throws PortalException, SystemException {
406
407 String[] repositoryURLs = _getRepositoryURLs();
408
409 for (int i = 0; i < repositoryURLs.length; i++) {
410 String repositoryURL = repositoryURLs[i];
411
412 try {
413 RemotePluginPackageRepository repository = _getRepository(
414 repositoryURL);
415
416 return repository.findPluginByArtifactURL(url);
417 }
418 catch (PluginPackageException ppe) {
419 _log.error("Unable to load repository " + repositoryURL, ppe);
420 }
421 }
422
423 return null;
424 }
425
426 private RemotePluginPackageRepository _getRepository(String repositoryURL)
427 throws PortalException, SystemException {
428
429 RemotePluginPackageRepository repository = _repositoryCache.get(
430 repositoryURL);
431
432 if (repository != null) {
433 return repository;
434 }
435
436 return _loadRepository(repositoryURL);
437 }
438
439 private String[] _getRepositoryURLs() throws PluginPackageException {
440 try {
441 String[] trusted = PrefsPropsUtil.getStringArray(
442 PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
443 PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
444 String[] untrusted = PrefsPropsUtil.getStringArray(
445 PropsKeys.PLUGIN_REPOSITORIES_UNTRUSTED, StringPool.NEW_LINE,
446 PropsValues.PLUGIN_REPOSITORIES_UNTRUSTED);
447
448 return ArrayUtil.append(trusted, untrusted);
449 }
450 catch (Exception e) {
451 throw new PluginPackageException(
452 "Unable to read repository list", e);
453 }
454 }
455
456 private String[] _getStatusAndInstalledVersion(
457 PluginPackage pluginPackage) {
458
459 PluginPackage installedPluginPackage =
460 _installedPluginPackages.getLatestPluginPackage(
461 pluginPackage.getGroupId(), pluginPackage.getArtifactId());
462
463 String status = null;
464 String installedVersion = null;
465
466 if (installedPluginPackage == null) {
467 status = PluginPackageImpl.STATUS_NOT_INSTALLED;
468 }
469 else {
470 installedVersion = installedPluginPackage.getVersion();
471
472 if (installedPluginPackage.isLaterVersionThan(pluginPackage)) {
473 status = PluginPackageImpl.STATUS_NEWER_VERSION_INSTALLED;
474 }
475 else if (installedPluginPackage.isPreviousVersionThan(
476 pluginPackage)) {
477
478 status = PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED;
479 }
480 else {
481 status = PluginPackageImpl.STATUS_SAME_VERSION_INSTALLED;
482 }
483 }
484
485 return new String[] {status, installedVersion};
486 }
487
488 private String[] _getSupportedTypes() {
489 return PropsValues.PLUGIN_TYPES;
490 }
491
492 private void _indexPluginPackage(PluginPackage pluginPackage)
493 throws PortalException {
494
495 Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
496
497 indexer.reindex(pluginPackage);
498 }
499
500 private boolean _isCurrentVersionSupported(List<String> versions) {
501 Version currentVersion = Version.getInstance(ReleaseInfo.getVersion());
502
503 for (String version : versions) {
504 Version supportedVersion = Version.getInstance(version);
505
506 if (supportedVersion.includes(currentVersion)) {
507 return true;
508 }
509 }
510
511 return false;
512 }
513
514 private boolean _isIgnored(PluginPackage pluginPackage)
515 throws SystemException {
516
517 String packageId = pluginPackage.getPackageId();
518
519 String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
520 PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
521 StringPool.NEW_LINE,
522 PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
523
524 for (int i = 0; i < pluginPackagesIgnored.length; i++) {
525 String curPluginPackagesIgnored = pluginPackagesIgnored[i];
526
527 if (curPluginPackagesIgnored.endsWith(StringPool.STAR)) {
528 String prefix = curPluginPackagesIgnored.substring(
529 0, curPluginPackagesIgnored.length() - 2);
530
531 if (packageId.startsWith(prefix)) {
532 return true;
533 }
534 }
535 else {
536 if (packageId.equals(curPluginPackagesIgnored)) {
537 return true;
538 }
539 }
540 }
541
542 return false;
543 }
544
545 private boolean _isInstallationInProcess(String context) {
546 if (_installedPluginPackages.getInstallingPluginPackage(
547 context) != null) {
548
549 return true;
550 }
551 else {
552 return false;
553 }
554 }
555
556 private boolean _isInstalled(String context) {
557 PluginPackage pluginPackage = _installedPluginPackages.getPluginPackage(
558 context);
559
560 if (pluginPackage != null) {
561 return true;
562 }
563 else {
564 return false;
565 }
566 }
567
568 private boolean _isTrusted(String repositoryURL)
569 throws PluginPackageException {
570
571 try {
572 String[] trusted = PrefsPropsUtil.getStringArray(
573 PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
574 PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
575
576 if (ArrayUtil.contains(trusted, repositoryURL)) {
577 return true;
578 }
579 else {
580 return false;
581 }
582 }
583 catch (Exception e) {
584 throw new PluginPackageException(
585 "Unable to read repository list", e);
586 }
587 }
588
589 private boolean _isUpdateAvailable() throws SystemException {
590 if (!PrefsPropsUtil.getBoolean(
591 PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
592 PropsValues.PLUGIN_NOTIFICATIONS_ENABLED)) {
593
594 return false;
595 }
596
597 if (_updateAvailable != null) {
598 return _updateAvailable.booleanValue();
599 }
600 else if (!_settingUpdateAvailable) {
601 _settingUpdateAvailable = true;
602
603 Thread indexerThread = new Thread(
604 new UpdateAvailableRunner(), PluginPackageUtil.class.getName());
605
606 indexerThread.setPriority(Thread.MIN_PRIORITY);
607
608 indexerThread.start();
609 }
610
611 return false;
612 }
613
614 private RemotePluginPackageRepository _loadRepository(String repositoryURL)
615 throws PluginPackageException, PortalException {
616
617 RemotePluginPackageRepository repository = null;
618
619 StringBundler sb = new StringBundler(8);
620
621 if (!repositoryURL.startsWith(Http.HTTP_WITH_SLASH) &&
622 !repositoryURL.startsWith(Http.HTTPS_WITH_SLASH)) {
623
624 sb.append(Http.HTTP_WITH_SLASH);
625 }
626
627 sb.append(repositoryURL);
628 sb.append(StringPool.SLASH);
629 sb.append(PluginPackage.REPOSITORY_XML_FILENAME_PREFIX);
630 sb.append(StringPool.DASH);
631 sb.append(ReleaseInfo.getVersion());
632 sb.append(StringPool.PERIOD);
633 sb.append(PluginPackage.REPOSITORY_XML_FILENAME_EXTENSION);
634
635 String pluginsXmlURL = sb.toString();
636
637 try {
638 Http.Options options = new Http.Options();
639
640 options.setLocation(pluginsXmlURL);
641 options.setPost(false);
642
643 byte[] bytes = HttpUtil.URLtoByteArray(options);
644
645 Http.Response response = options.getResponse();
646
647 int responseCode = response.getResponseCode();
648
649 if (responseCode != HttpServletResponse.SC_OK) {
650 if (_log.isDebugEnabled()) {
651 _log.debug(
652 "A repository for version " +
653 ReleaseInfo.getVersion() + " was not found. " +
654 "Checking general repository");
655 }
656
657 sb.setIndex(0);
658
659 sb.append(repositoryURL);
660 sb.append(StringPool.SLASH);
661 sb.append(PluginPackage.REPOSITORY_XML_FILENAME_PREFIX);
662 sb.append(StringPool.PERIOD);
663 sb.append(PluginPackage.REPOSITORY_XML_FILENAME_EXTENSION);
664
665 pluginsXmlURL = sb.toString();
666
667 options = new Http.Options();
668
669 options.setLocation(pluginsXmlURL);
670 options.setPost(false);
671
672 bytes = HttpUtil.URLtoByteArray(options);
673
674 response = options.getResponse();
675
676 if (responseCode != HttpServletResponse.SC_OK) {
677 throw new PluginPackageException(
678 "Unable to download file " + pluginsXmlURL +
679 " because of response code " + responseCode);
680 }
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 murle) {
701 _repositoryCache.remove(repositoryURL);
702
703 throw new PluginPackageException(
704 "Invalid URL " + pluginsXmlURL, murle);
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, PortalException {
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 document = SAXReaderUtil.read(xml);
740
741 Element rootElement = document.getRootElement();
742
743 Properties settings = _readProperties(
744 rootElement.element("settings"), "setting");
745
746 pluginPackageRepository.setSettings(settings);
747
748 List<Element> pluginPackageElements = rootElement.elements(
749 "plugin-package");
750
751 for (Element pluginPackageElement : pluginPackageElements) {
752 PluginPackage pluginPackage = _readPluginPackageXml(
753 pluginPackageElement);
754
755 if (!_isCurrentVersionSupported(
756 pluginPackage.getLiferayVersions())) {
757
758 continue;
759 }
760
761 boolean containsSupportedTypes = false;
762
763 List<String> pluginTypes = pluginPackage.getTypes();
764
765 for (String pluginType : pluginTypes) {
766 if (supportedPluginTypes.contains(pluginType)) {
767 containsSupportedTypes = true;
768
769 break;
770 }
771 }
772
773 if (!containsSupportedTypes) {
774 continue;
775 }
776
777 pluginPackage.setRepository(pluginPackageRepository);
778
779 pluginPackageRepository.addPluginPackage(pluginPackage);
780
781 _indexPluginPackage(pluginPackage);
782 }
783
784 return pluginPackageRepository;
785 }
786
787 private Date _readDate(String text) {
788 if (Validator.isNotNull(text)) {
789 DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
790 Time.RFC822_FORMAT, LocaleUtil.US);
791
792 try {
793 return dateFormat.parse(text);
794 }
795 catch (Exception e) {
796 if (_log.isWarnEnabled()) {
797 _log.warn("Unable to parse date " + text);
798 }
799 }
800 }
801
802 return new Date();
803 }
804
805 private String _readHtml(String text) {
806 return GetterUtil.getString(text);
807 }
808
809 private List<License> _readLicenseList(Element parentElement, String name) {
810 List<License> licenses = new ArrayList<License>();
811
812 for (Element licenseElement : parentElement.elements(name)) {
813 License license = new License();
814
815 license.setName(licenseElement.getText());
816
817 Attribute osiApproved = licenseElement.attribute("osi-approved");
818
819 if (osiApproved != null) {
820 license.setOsiApproved(
821 GetterUtil.getBoolean(osiApproved.getText()));
822 }
823
824 Attribute url = licenseElement.attribute("url");
825
826 if (url != null) {
827 license.setUrl(url.getText());
828 }
829
830 licenses.add(license);
831 }
832
833 return licenses;
834 }
835
836 private List<String> _readList(Element parentElement, String name) {
837 List<String> list = new ArrayList<String>();
838
839 if (parentElement == null) {
840 return list;
841 }
842
843 for (Element element : parentElement.elements(name)) {
844 String text = element.getText().trim().toLowerCase();
845
846 list.add(text);
847 }
848
849 return list;
850 }
851
852 private PluginPackage _readPluginPackageProperties(
853 String displayName, Properties properties) {
854
855 int pos = displayName.indexOf("-portlet");
856
857 String pluginType = Plugin.TYPE_PORTLET;
858
859 if (pos == -1) {
860 pos = displayName.indexOf("-ext");
861
862 pluginType = Plugin.TYPE_EXT;
863 }
864
865 if (pos == -1) {
866 pos = displayName.indexOf("-hook");
867
868 pluginType = Plugin.TYPE_HOOK;
869 }
870
871 if (pos == -1) {
872 pos = displayName.indexOf("-layouttpl");
873
874 pluginType = Plugin.TYPE_LAYOUT_TEMPLATE;
875 }
876
877 if (pos == -1) {
878 pos = displayName.indexOf("-theme");
879
880 pluginType = Plugin.TYPE_THEME;
881 }
882
883 if (pos == -1) {
884 pos = displayName.indexOf("-web");
885
886 pluginType = Plugin.TYPE_WEB;
887 }
888
889 if (pos == -1) {
890 return null;
891 }
892
893 String displayPrefix = displayName.substring(0, pos);
894
895 String moduleGroupId = GetterUtil.getString(
896 properties.getProperty("module-group-id"));
897 String moduleArtifactId = displayPrefix + "-" + pluginType;
898
899 String moduleVersion = GetterUtil.getString(
900 properties.getProperty("module-version"));
901
902 if (Validator.isNull(moduleVersion)) {
903 int moduleVersionPos = pos + pluginType.length() + 2;
904
905 if (displayName.length() > moduleVersionPos) {
906 moduleVersion = displayName.substring(moduleVersionPos);
907 }
908 else {
909 moduleVersion = ReleaseInfo.getVersion();
910 }
911 }
912
913 String moduleId =
914 moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
915 "/war";
916
917 String pluginName = GetterUtil.getString(
918 properties.getProperty("name"));
919
920 String deploymentContext = GetterUtil.getString(
921 properties.getProperty("recommended-deployment-context"),
922 moduleArtifactId);
923
924 String author = GetterUtil.getString(properties.getProperty("author"));
925
926 List<String> types = new ArrayList<String>();
927
928 types.add(pluginType);
929
930 List<License> licenses = new ArrayList<License>();
931
932 String[] licensesArray = StringUtil.split(
933 properties.getProperty("licenses"));
934
935 for (int i = 0; i < licensesArray.length; i++) {
936 License license = new License();
937
938 license.setName(licensesArray[i].trim());
939 license.setOsiApproved(true);
940
941 licenses.add(license);
942 }
943
944 List<String> liferayVersions = new ArrayList<String>();
945
946 String[] liferayVersionsArray = StringUtil.split(
947 properties.getProperty("liferay-versions"));
948
949 for (String liferayVersion : liferayVersionsArray) {
950 liferayVersions.add(liferayVersion.trim());
951 }
952
953 if (liferayVersions.size() == 0) {
954 liferayVersions.add(ReleaseInfo.getVersion() + "+");
955 }
956
957 List<String> tags = new ArrayList<String>();
958
959 String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
960
961 for (String tag : tagsArray) {
962 tags.add(tag.trim());
963 }
964
965 String shortDescription = GetterUtil.getString(
966 properties.getProperty("short-description"));
967 String longDescription = GetterUtil.getString(
968 properties.getProperty("long-description"));
969 String changeLog = GetterUtil.getString(
970 properties.getProperty("change-log"));
971 String pageURL = GetterUtil.getString(
972 properties.getProperty("page-url"));
973 String downloadURL = GetterUtil.getString(
974 properties.getProperty("download-url"));
975 List<String> requiredDeploymentContexts = ListUtil.fromArray(
976 StringUtil.split(
977 properties.getProperty("required-deployment-contexts")));
978
979 PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
980
981 pluginPackage.setName(pluginName);
982 pluginPackage.setRecommendedDeploymentContext(deploymentContext);
983
984 pluginPackage.setAuthor(author);
985 pluginPackage.setTypes(types);
986 pluginPackage.setLicenses(licenses);
987 pluginPackage.setLiferayVersions(liferayVersions);
988 pluginPackage.setTags(tags);
989 pluginPackage.setShortDescription(shortDescription);
990 pluginPackage.setLongDescription(longDescription);
991 pluginPackage.setChangeLog(changeLog);
992
993 pluginPackage.setPageURL(pageURL);
994 pluginPackage.setDownloadURL(downloadURL);
995
996 pluginPackage.setRequiredDeploymentContexts(requiredDeploymentContexts);
997
998 return pluginPackage;
999 }
1000
1001
1006 private PluginPackage _readPluginPackageServletContext(
1007 ServletContext servletContext)
1008 throws DocumentException, IOException {
1009
1010 String servletContextName = servletContext.getServletContextName();
1011
1012 if (_log.isInfoEnabled()) {
1013 if (servletContextName == null) {
1014 _log.info("Reading plugin package for the root context");
1015 }
1016 else {
1017 _log.info("Reading plugin package for " + servletContextName);
1018 }
1019 }
1020
1021 PluginPackage pluginPackage = null;
1022
1023 String xml = HttpUtil.URLtoString(
1024 servletContext.getResource("/WEB-INF/liferay-plugin-package.xml"));
1025
1026 if (xml != null) {
1027 pluginPackage = _readPluginPackageXml(xml);
1028 }
1029 else {
1030 String propertiesString = HttpUtil.URLtoString(
1031 servletContext.getResource(
1032 "/WEB-INF/liferay-plugin-package.properties"));
1033
1034 if (propertiesString != null) {
1035 if (_log.isDebugEnabled()) {
1036 _log.debug(
1037 "Reading plugin package from " +
1038 "liferay-plugin-package.properties");
1039 }
1040
1041 Properties properties = PropertiesUtil.load(propertiesString);
1042
1043 String displayName = servletContextName;
1044
1045 if (displayName.startsWith(StringPool.SLASH)) {
1046 displayName = displayName.substring(1);
1047 }
1048
1049 pluginPackage = _readPluginPackageProperties(
1050 displayName, properties);
1051 }
1052
1053 if (pluginPackage == null) {
1054 if (_log.isDebugEnabled()) {
1055 _log.debug("Reading plugin package from MANIFEST.MF");
1056 }
1057
1058 pluginPackage =_readPluginPackageServletManifest(
1059 servletContext);
1060 }
1061 }
1062
1063 pluginPackage.setContext(servletContextName);
1064
1065 return pluginPackage;
1066 }
1067
1068 private PluginPackage _readPluginPackageServletManifest(
1069 ServletContext servletContext)
1070 throws IOException {
1071
1072 Attributes attributes = null;
1073
1074 String servletContextName = servletContext.getServletContextName();
1075
1076 InputStream inputStream = servletContext.getResourceAsStream(
1077 "/META-INF/MANIFEST.MF");
1078
1079 if (inputStream != null) {
1080 Manifest manifest = new Manifest(inputStream);
1081
1082 attributes = manifest.getMainAttributes();
1083 }
1084 else {
1085 attributes = new Attributes();
1086 }
1087
1088 String artifactGroupId = attributes.getValue(
1089 "Implementation-Vendor-Id");
1090
1091 if (Validator.isNull(artifactGroupId)) {
1092 artifactGroupId = attributes.getValue("Implementation-Vendor");
1093 }
1094
1095 if (Validator.isNull(artifactGroupId)) {
1096 artifactGroupId = GetterUtil.getString(
1097 attributes.getValue("Bundle-Vendor"), servletContextName);
1098 }
1099
1100 String artifactId = attributes.getValue("Implementation-Title");
1101
1102 if (Validator.isNull(artifactId)) {
1103 artifactId = GetterUtil.getString(
1104 attributes.getValue("Bundle-Name"), servletContextName);
1105 }
1106
1107 String version = attributes.getValue("Implementation-Version");
1108
1109 if (Validator.isNull(version)) {
1110 version = GetterUtil.getString(
1111 attributes.getValue("Bundle-Version"), Version.UNKNOWN);
1112 }
1113
1114 if (version.equals(Version.UNKNOWN) && _log.isWarnEnabled()) {
1115 _log.warn(
1116 "Plugin package on context " + servletContextName +
1117 " cannot be tracked because this WAR does not contain a " +
1118 "liferay-plugin-package.xml file");
1119 }
1120
1121 PluginPackage pluginPackage = new PluginPackageImpl(
1122 artifactGroupId + StringPool.SLASH + artifactId + StringPool.SLASH +
1123 version + StringPool.SLASH + "war");
1124
1125 pluginPackage.setName(artifactId);
1126
1127 String shortDescription = attributes.getValue("Bundle-Description");
1128
1129 if (Validator.isNotNull(shortDescription)) {
1130 pluginPackage.setShortDescription(shortDescription);
1131 }
1132
1133 String pageURL = attributes.getValue("Bundle-DocURL");
1134
1135 if (Validator.isNotNull(pageURL)) {
1136 pluginPackage.setPageURL(pageURL);
1137 }
1138
1139 return pluginPackage;
1140 }
1141
1142 private PluginPackage _readPluginPackageXml(Element pluginPackageElement) {
1143 String name = pluginPackageElement.elementText("name");
1144
1145 if (_log.isDebugEnabled()) {
1146 _log.debug("Reading pluginPackage definition " + name);
1147 }
1148
1149 PluginPackage pluginPackage = new PluginPackageImpl(
1150 GetterUtil.getString(
1151 pluginPackageElement.elementText("module-id")));
1152
1153 List<String> liferayVersions = _readList(
1154 pluginPackageElement.element("liferay-versions"),
1155 "liferay-version");
1156
1157 List<String> types = _readList(
1158 pluginPackageElement.element("types"), "type");
1159
1160 if (types.contains("layout-template")) {
1161 types.remove("layout-template");
1162
1163 types.add(Plugin.TYPE_LAYOUT_TEMPLATE);
1164 }
1165
1166 pluginPackage.setName(_readText(name));
1167 pluginPackage.setRecommendedDeploymentContext(
1168 _readText(
1169 pluginPackageElement.elementText(
1170 "recommended-deployment-context")));
1171 pluginPackage.setRequiredDeploymentContexts(
1172 _readList(
1173 pluginPackageElement.element(
1174 "required-deployment-contexts"),
1175 "required-deployment-context"));
1176 pluginPackage.setModifiedDate(
1177 _readDate(pluginPackageElement.elementText("modified-date")));
1178 pluginPackage.setAuthor(
1179 _readText(pluginPackageElement.elementText("author")));
1180 pluginPackage.setTypes(types);
1181 pluginPackage.setLicenses(
1182 _readLicenseList(
1183 pluginPackageElement.element("licenses"), "license"));
1184 pluginPackage.setLiferayVersions(liferayVersions);
1185 pluginPackage.setTags(
1186 _readList(pluginPackageElement.element("tags"), "tag"));
1187 pluginPackage.setShortDescription(
1188 _readText(pluginPackageElement.elementText("short-description")));
1189 pluginPackage.setLongDescription(
1190 _readHtml(pluginPackageElement.elementText("long-description")));
1191 pluginPackage.setChangeLog(
1192 _readHtml(pluginPackageElement.elementText("change-log")));
1193 pluginPackage.setScreenshots(
1194 _readScreenshots(pluginPackageElement.element("screenshots")));
1195 pluginPackage.setPageURL(
1196 _readText(pluginPackageElement.elementText("page-url")));
1197 pluginPackage.setDownloadURL(
1198 _readText(pluginPackageElement.elementText("download-url")));
1199 pluginPackage.setDeploymentSettings(
1200 _readProperties(
1201 pluginPackageElement.element("deployment-settings"),
1202 "setting"));
1203
1204 return pluginPackage;
1205 }
1206
1207 private PluginPackage _readPluginPackageXml(String xml)
1208 throws DocumentException {
1209
1210 Document document = SAXReaderUtil.read(xml);
1211
1212 Element rootElement = document.getRootElement();
1213
1214 return _readPluginPackageXml(rootElement);
1215 }
1216
1217 private Properties _readProperties(Element parentElement, String name) {
1218 Properties properties = new Properties();
1219
1220 if (parentElement == null) {
1221 return properties;
1222 }
1223
1224 for (Element element : parentElement.elements(name)) {
1225 properties.setProperty(
1226 element.attributeValue("name"),
1227 element.attributeValue("value"));
1228 }
1229
1230 return properties;
1231 }
1232
1233 private List<Screenshot> _readScreenshots(Element parentElement) {
1234 List<Screenshot> screenshots = new ArrayList<Screenshot>();
1235
1236 if (parentElement == null) {
1237 return screenshots;
1238 }
1239
1240 for (Element screenshotElement : parentElement.elements("screenshot")) {
1241 Screenshot screenshot = new Screenshot();
1242
1243 screenshot.setThumbnailURL(
1244 screenshotElement.elementText("thumbnail-url"));
1245 screenshot.setLargeImageURL(
1246 screenshotElement.elementText("large-image-url"));
1247
1248 screenshots.add(screenshot);
1249 }
1250
1251 return screenshots;
1252 }
1253
1254 private String _readText(String text) {
1255 return HtmlUtil.extractText(GetterUtil.getString(text));
1256 }
1257
1258 private void _refreshUpdatesAvailableCache() {
1259 _updateAvailable = null;
1260 }
1261
1262 private void _registerInstalledPluginPackage(PluginPackage pluginPackage)
1263 throws PortalException {
1264
1265 _installedPluginPackages.addPluginPackage(pluginPackage);
1266
1267 _updateAvailable = null;
1268
1269 _indexPluginPackage(pluginPackage);
1270 }
1271
1272 private void _registerPluginPackageInstallation(String preliminaryContext) {
1273 _installedPluginPackages.registerPluginPackageInstallation(
1274 preliminaryContext);
1275 }
1276
1277 private RepositoryReport _reloadRepositories()
1278 throws PortalException, SystemException {
1279
1280 if (_log.isInfoEnabled()) {
1281 _log.info("Reloading repositories");
1282 }
1283
1284 RepositoryReport repositoryReport = new RepositoryReport();
1285
1286 String[] repositoryURLs = _getRepositoryURLs();
1287
1288 for (int i = 0; i < repositoryURLs.length; i++) {
1289 String repositoryURL = repositoryURLs[i];
1290
1291 try {
1292 _loadRepository(repositoryURL);
1293
1294 repositoryReport.addSuccess(repositoryURL);
1295 }
1296 catch (PluginPackageException ppe) {
1297 repositoryReport.addError(repositoryURL, ppe);
1298
1299 _log.error(
1300 "Unable to load repository " + repositoryURL + " " +
1301 ppe.toString());
1302 }
1303
1304 }
1305
1306 Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1307
1308 indexer.reindex(new String[0]);
1309
1310 return repositoryReport;
1311 }
1312
1313 private Hits _search(
1314 String keywords, String type, String tag, String license,
1315 String repositoryURL, String status, int start, int end)
1316 throws PortalException, SystemException {
1317
1318 _checkRepositories(repositoryURL);
1319
1320 SearchContext searchContext = new SearchContext();
1321
1322 Map<String, Serializable> attributes =
1323 new HashMap<String, Serializable>();
1324
1325 attributes.put("license", license);
1326 attributes.put("repositoryURL", repositoryURL);
1327 attributes.put("status", status);
1328 attributes.put("tag", tag);
1329 attributes.put("type", type);
1330
1331 searchContext.setAttributes(attributes);
1332
1333 searchContext.setCompanyId(CompanyConstants.SYSTEM);
1334 searchContext.setEnd(end);
1335 searchContext.setKeywords(keywords);
1336
1337 QueryConfig queryConfig = new QueryConfig();
1338
1339 queryConfig.setHighlightEnabled(false);
1340 queryConfig.setScoreEnabled(false);
1341
1342 searchContext.setQueryConfig(queryConfig);
1343
1344 searchContext.setStart(start);
1345
1346 Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1347
1348 return indexer.search(searchContext);
1349 }
1350
1351 private void _unregisterInstalledPluginPackage(PluginPackage pluginPackage)
1352 throws PortalException, SystemException {
1353
1354 _installedPluginPackages.removePluginPackage(pluginPackage);
1355
1356 try {
1357 List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1358 pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1359
1360 for (PluginPackage availablePackage : pluginPackages) {
1361 _indexPluginPackage(availablePackage);
1362 }
1363 }
1364 catch (PluginPackageException ppe) {
1365 if (_log.isWarnEnabled()) {
1366 _log.warn(
1367 "Unable to reindex unistalled package " +
1368 pluginPackage.getContext() + ": " + ppe.getMessage());
1369 }
1370 }
1371 }
1372
1373 private void _updateInstallingPluginPackage(
1374 String preliminaryContext, PluginPackage pluginPackage) {
1375
1376 _installedPluginPackages.unregisterPluginPackageInstallation(
1377 preliminaryContext);
1378 _installedPluginPackages.registerPluginPackageInstallation(
1379 pluginPackage);
1380 }
1381
1382 private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1383
1384 private static PluginPackageUtil _instance = new PluginPackageUtil();
1385
1386 private Set<String> _availableTagsCache;
1387 private LocalPluginPackageRepository _installedPluginPackages;
1388 private Date _lastUpdateDate;
1389 private Map<String, RemotePluginPackageRepository> _repositoryCache;
1390 private boolean _settingUpdateAvailable;
1391 private Boolean _updateAvailable;
1392
1393 private class UpdateAvailableRunner implements Runnable {
1394
1395 @Override
1396 public void run() {
1397 try {
1398 setUpdateAvailable();
1399 }
1400 catch (Exception e) {
1401 if (_log.isWarnEnabled()) {
1402 _log.warn(e.getMessage());
1403 }
1404 }
1405 }
1406
1407 protected void setUpdateAvailable() throws Exception {
1408 StopWatch stopWatch = null;
1409
1410 if (_log.isInfoEnabled()) {
1411 _log.info("Checking for available updates");
1412
1413 stopWatch = new StopWatch();
1414
1415 stopWatch.start();
1416 }
1417
1418 for (PluginPackage pluginPackage :
1419 _installedPluginPackages.getPluginPackages()) {
1420
1421 PluginPackage availablePluginPackage = null;
1422
1423 if (_isIgnored(pluginPackage)) {
1424 continue;
1425 }
1426
1427 availablePluginPackage =
1428 PluginPackageUtil.getLatestAvailablePluginPackage(
1429 pluginPackage.getGroupId(),
1430 pluginPackage.getArtifactId());
1431
1432 if (availablePluginPackage == null) {
1433 continue;
1434 }
1435
1436 Version availablePluginPackageVersion = Version.getInstance(
1437 availablePluginPackage.getVersion());
1438
1439 if (availablePluginPackageVersion.isLaterVersionThan(
1440 pluginPackage.getVersion())) {
1441
1442 _updateAvailable = Boolean.TRUE;
1443
1444 break;
1445 }
1446 }
1447
1448 if (_updateAvailable == null) {
1449 _updateAvailable = Boolean.FALSE;
1450 }
1451
1452 _settingUpdateAvailable = false;
1453
1454 if (_log.isInfoEnabled()) {
1455 _log.info(
1456 "Finished checking for available updates in " +
1457 stopWatch.getTime() + " ms");
1458 }
1459 }
1460 }
1461
1462 }