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