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