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