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