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