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