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