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 readPluginPackageProperties(
197 String displayName, Properties props) {
198
199 return _instance._readPluginPackageProperties(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 _readPluginPackageProperties(
869 String displayName, Properties properties) {
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 properties.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(
915 properties.getProperty("name"));
916
917 String deploymentContext = GetterUtil.getString(
918 properties.getProperty("recommended-deployment-context"),
919 moduleArtifactId);
920
921 String author = GetterUtil.getString(properties.getProperty("author"));
922
923 List<String> types = new ArrayList<String>();
924
925 types.add(pluginType);
926
927 List<License> licenses = new ArrayList<License>();
928
929 String[] licensesArray = StringUtil.split(
930 properties.getProperty("licenses"));
931
932 for (int i = 0; i < licensesArray.length; i++) {
933 License license = new License();
934
935 license.setName(licensesArray[i].trim());
936 license.setOsiApproved(true);
937
938 licenses.add(license);
939 }
940
941 List<String> liferayVersions = new ArrayList<String>();
942
943 String[] liferayVersionsArray = StringUtil.split(
944 properties.getProperty("liferay-versions"));
945
946 for (String liferayVersion : liferayVersionsArray) {
947 liferayVersions.add(liferayVersion.trim());
948 }
949
950 if (liferayVersions.size() == 0) {
951 liferayVersions.add(ReleaseInfo.getVersion() + "+");
952 }
953
954 List<String> tags = new ArrayList<String>();
955
956 String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
957
958 for (String tag : tagsArray) {
959 tags.add(tag.trim());
960 }
961
962 String shortDescription = GetterUtil.getString(
963 properties.getProperty("short-description"));
964 String longDescription = GetterUtil.getString(
965 properties.getProperty("long-description"));
966 String changeLog = GetterUtil.getString(
967 properties.getProperty("change-log"));
968 String pageURL = GetterUtil.getString(
969 properties.getProperty("page-url"));
970 String downloadURL = GetterUtil.getString(
971 properties.getProperty("download-url"));
972
973 PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
974
975 pluginPackage.setName(pluginName);
976 pluginPackage.setRecommendedDeploymentContext(deploymentContext);
977 pluginPackage.setAuthor(author);
979 pluginPackage.setTypes(types);
980 pluginPackage.setLicenses(licenses);
981 pluginPackage.setLiferayVersions(liferayVersions);
982 pluginPackage.setTags(tags);
983 pluginPackage.setShortDescription(shortDescription);
984 pluginPackage.setLongDescription(longDescription);
985 pluginPackage.setChangeLog(changeLog);
986 pluginPackage.setPageURL(pageURL);
988 pluginPackage.setDownloadURL(downloadURL);
989
991 return pluginPackage;
992 }
993
994 private PluginPackage _readPluginPackageXml(String xml)
995 throws DocumentException {
996
997 Document doc = SAXReaderUtil.read(xml);
998
999 Element root = doc.getRootElement();
1000
1001 return _readPluginPackageXml(root);
1002 }
1003
1004 private PluginPackage _readPluginPackageXml(Element pluginPackageEl) {
1005 String name = pluginPackageEl.elementText("name");
1006
1007 if (_log.isDebugEnabled()) {
1008 _log.debug("Reading pluginPackage definition " + name);
1009 }
1010
1011 PluginPackage pluginPackage = new PluginPackageImpl(
1012 GetterUtil.getString(pluginPackageEl.elementText("module-id")));
1013
1014 List<String> liferayVersions = _readList(
1015 pluginPackageEl.element("liferay-versions"), "liferay-version");
1016
1017 List<String> types = _readList(
1018 pluginPackageEl.element("types"), "type");
1019
1020 pluginPackage.setName(_readText(name));
1021 pluginPackage.setRecommendedDeploymentContext(
1022 _readText(
1023 pluginPackageEl.elementText("recommended-deployment-context")));
1024 pluginPackage.setModifiedDate(
1025 _readDate(pluginPackageEl.elementText("modified-date")));
1026 pluginPackage.setAuthor(
1027 _readText(pluginPackageEl.elementText("author")));
1028 pluginPackage.setTypes(types);
1029 pluginPackage.setLicenses(
1030 _readLicenseList(
1031 pluginPackageEl.element("licenses"), "license"));
1032 pluginPackage.setLiferayVersions(liferayVersions);
1033 pluginPackage.setTags(
1034 _readList(pluginPackageEl.element("tags"), "tag"));
1035 pluginPackage.setShortDescription(
1036 _readText(pluginPackageEl.elementText("short-description")));
1037 pluginPackage.setLongDescription(
1038 _readHtml(pluginPackageEl.elementText("long-description")));
1039 pluginPackage.setChangeLog(
1040 _readHtml(pluginPackageEl.elementText("change-log")));
1041 pluginPackage.setScreenshots(
1042 _readScreenshots(pluginPackageEl.element("screenshots")));
1043 pluginPackage.setPageURL(
1044 _readText(pluginPackageEl.elementText("page-url")));
1045 pluginPackage.setDownloadURL(
1046 _readText(pluginPackageEl.elementText("download-url")));
1047 pluginPackage.setDeploymentSettings(
1048 _readProperties(
1049 pluginPackageEl.element("deployment-settings"), "setting"));
1050
1051 return pluginPackage;
1052 }
1053
1054 private Properties _readProperties(Element parentEl, String name) {
1055 Properties result = new Properties();
1056
1057 if (parentEl != null) {
1058 Iterator<Element> itr = parentEl.elements(name).iterator();
1059
1060 while (itr.hasNext()) {
1061 Element el = itr.next();
1062
1063 result.setProperty(
1064 el.attribute("name").getValue(),
1065 el.attribute("value").getValue());
1066 }
1067 }
1068
1069 return result;
1070 }
1071
1072 private List<Screenshot> _readScreenshots(Element parentEl) {
1073 List<Screenshot> screenshots = new ArrayList<Screenshot>();
1074
1075 if (parentEl != null) {
1076 Iterator<Element> itr = parentEl.elements("screenshot").iterator();
1077
1078 while (itr.hasNext()) {
1079 Element screenshotEl = itr.next();
1080
1081 Screenshot screenshot = new Screenshot();
1082
1083 screenshot.setThumbnailURL(
1084 screenshotEl.element("thumbnail-url").getText());
1085 screenshot.setLargeImageURL(
1086 screenshotEl.element("large-image-url").getText());
1087
1088 screenshots.add(screenshot);
1089 }
1090 }
1091
1092 return screenshots;
1093 }
1094
1095 private String _readText(String text) {
1096 return HtmlUtil.extractText(GetterUtil.getString(text));
1097 }
1098
1099 private void _refreshUpdatesAvailableCache() {
1100 _updateAvailable = null;
1101 }
1102
1103 private void _reIndex() throws SystemException {
1104 if (SearchEngineUtil.isIndexReadOnly()) {
1105 return;
1106 }
1107
1108 try {
1109 PluginPackageIndexer.cleanIndex();
1110
1111 for (PluginPackage pluginPackage :
1112 _getAllAvailablePluginPackages()) {
1113
1114 String[] statusAndInstalledVersion =
1115 _getStatusAndInstalledVersion(pluginPackage);
1116
1117 String status = statusAndInstalledVersion[0];
1118 String installedVersion = statusAndInstalledVersion[1];
1119
1120 com.liferay.portal.kernel.search.Document doc =
1121 PluginPackageIndexer.getPluginPackageDocument(
1122 pluginPackage.getModuleId(), pluginPackage.getName(),
1123 pluginPackage.getVersion(),
1124 pluginPackage.getModifiedDate(),
1125 pluginPackage.getAuthor(), pluginPackage.getTypes(),
1126 pluginPackage.getTags(), pluginPackage.getLicenses(),
1127 pluginPackage.getLiferayVersions(),
1128 pluginPackage.getShortDescription(),
1129 pluginPackage.getLongDescription(),
1130 pluginPackage.getChangeLog(),
1131 pluginPackage.getPageURL(),
1132 pluginPackage.getRepositoryURL(), status,
1133 installedVersion);
1134
1135 SearchEngineUtil.addDocument(CompanyConstants.SYSTEM, doc);
1136 }
1137 }
1138 catch (SystemException se) {
1139 throw se;
1140 }
1141 catch (Exception e) {
1142 throw new SystemException(e);
1143 }
1144 }
1145
1146 private RepositoryReport _reloadRepositories() throws SystemException {
1147 if (_log.isInfoEnabled()) {
1148 _log.info("Reloading repositories");
1149 }
1150
1151 RepositoryReport repositoryReport = new RepositoryReport();
1152
1153 String[] repositoryURLs = _getRepositoryURLs();
1154
1155 for (int i = 0; i < repositoryURLs.length; i++) {
1156 String repositoryURL = repositoryURLs[i];
1157
1158 try {
1159 _loadRepository(repositoryURL);
1160
1161 repositoryReport.addSuccess(repositoryURL);
1162 }
1163 catch (PluginPackageException pe) {
1164 repositoryReport.addError(repositoryURL, pe);
1165
1166 _log.error(
1167 "Unable to load repository " + repositoryURL + " " +
1168 pe.toString());
1169 }
1170
1171 }
1172
1173 _reIndex();
1174
1175 return repositoryReport;
1176 }
1177
1178 private void _registerInstalledPluginPackage(
1179 PluginPackage pluginPackage) {
1180
1181 _installedPluginPackages.addPluginPackage(pluginPackage);
1182
1183 _updateAvailable = null;
1184
1185 _indexPluginPackage(pluginPackage);
1186 }
1187
1188 private void _registerPluginPackageInstallation(
1189 String preliminaryContext) {
1190
1191 _installedPluginPackages.registerPluginPackageInstallation(
1192 preliminaryContext);
1193 }
1194
1195 private Hits _search(
1196 String keywords, String type, String tag, String license,
1197 String repositoryURL, String status, int start, int end)
1198 throws SystemException {
1199
1200 _checkRepositories(repositoryURL);
1201
1202 try {
1203 BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
1204
1205 contextQuery.addRequiredTerm(
1206 Field.PORTLET_ID, PluginPackageIndexer.PORTLET_ID);
1207
1208 BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
1209
1210 fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
1211
1212 if (Validator.isNotNull(keywords)) {
1213 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1214
1215 searchQuery.addTerm(Field.TITLE, keywords);
1216 searchQuery.addTerm(Field.CONTENT, keywords);
1217
1218 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1219 }
1220
1221 if (Validator.isNotNull(type)) {
1222 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1223
1224 searchQuery.addExactTerm("type", type);
1225
1226 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1227 }
1228
1229 if (Validator.isNotNull(tag)) {
1230 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1231
1232 searchQuery.addExactTerm("tag", tag);
1233
1234 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1235 }
1236
1237 if (Validator.isNotNull(repositoryURL)) {
1238 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1239
1240 Query query = TermQueryFactoryUtil.create(
1241 "repositoryURL", repositoryURL);
1242
1243 searchQuery.add(query, BooleanClauseOccur.SHOULD);
1244
1245 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1246 }
1247
1248 if (Validator.isNotNull(license)) {
1249 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1250
1251 searchQuery.addExactTerm("license", license);
1252
1253 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1254 }
1255
1256 if (Validator.isNotNull(status) && !status.equals("all")) {
1257 BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
1258
1259 if (status.equals(PluginPackageImpl.
1260 STATUS_NOT_INSTALLED_OR_OLDER_VERSION_INSTALLED)) {
1261
1262 searchQuery.addExactTerm(
1263 "status", PluginPackageImpl.STATUS_NOT_INSTALLED);
1264 searchQuery.addExactTerm(
1265 "status",
1266 PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED);
1267 }
1268 else {
1269 searchQuery.addExactTerm("status", status);
1270 }
1271
1272 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
1273 }
1274
1275 return SearchEngineUtil.search(
1276 CompanyConstants.SYSTEM, fullQuery, start, end);
1277 }
1278 catch (Exception e) {
1279 throw new SystemException(e);
1280 }
1281 }
1282
1283 private void _unregisterInstalledPluginPackage(
1284 PluginPackage pluginPackage) {
1285
1286 _installedPluginPackages.removePluginPackage(pluginPackage);
1287
1288 try {
1289 List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1290 pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1291
1292 for (PluginPackage availablePackage : pluginPackages) {
1293 _indexPluginPackage(availablePackage);
1294 }
1295 }
1296 catch (PluginPackageException ppe) {
1297 if (_log.isWarnEnabled()) {
1298 _log.warn(
1299 "Unable to reindex unistalled package " +
1300 pluginPackage.getContext() + ": " + ppe.getMessage());
1301 }
1302 }
1303 }
1304
1305 private void _updateInstallingPluginPackage(
1306 String preliminaryContext, PluginPackage pluginPackage) {
1307
1308 _installedPluginPackages.unregisterPluginPackageInstallation(
1309 preliminaryContext);
1310 _installedPluginPackages.registerPluginPackageInstallation(
1311 pluginPackage);
1312 }
1313
1314 private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1315
1316 private static PluginPackageUtil _instance = new PluginPackageUtil();
1317
1318 private LocalPluginPackageRepository _installedPluginPackages;
1319 private Map<String, RemotePluginPackageRepository> _repositoryCache;
1320 private Set<String> _availableTagsCache;
1321 private Date _lastUpdateDate;
1322 private Boolean _updateAvailable;
1323 private boolean _settingUpdateAvailable;
1324
1325 private class UpdateAvailableRunner implements Runnable {
1326
1327 public void run() {
1328 try {
1329 setUpdateAvailable();
1330 }
1331 catch (Exception e) {
1332 if (_log.isWarnEnabled()) {
1333 _log.warn(e.getMessage());
1334 }
1335 }
1336 }
1337
1338 protected void setUpdateAvailable() throws Exception {
1339 StopWatch stopWatch = null;
1340
1341 if (_log.isInfoEnabled()) {
1342 _log.info("Checking for available updates");
1343
1344 stopWatch = new StopWatch();
1345
1346 stopWatch.start();
1347 }
1348
1349 for (PluginPackage pluginPackage :
1350 _installedPluginPackages.getPluginPackages()) {
1351
1352 PluginPackage availablePluginPackage = null;
1353
1354 if (_isIgnored(pluginPackage)) {
1355 continue;
1356 }
1357
1358 availablePluginPackage =
1359 PluginPackageUtil.getLatestAvailablePluginPackage(
1360 pluginPackage.getGroupId(),
1361 pluginPackage.getArtifactId());
1362
1363 if (availablePluginPackage == null) {
1364 continue;
1365 }
1366
1367 Version availablePluginPackageVersion = Version.getInstance(
1368 availablePluginPackage.getVersion());
1369
1370 if (availablePluginPackageVersion.isLaterVersionThan(
1371 pluginPackage.getVersion())) {
1372
1373 _updateAvailable = Boolean.TRUE;
1374
1375 break;
1376 }
1377 }
1378
1379 if (_updateAvailable == null) {
1380 _updateAvailable = Boolean.FALSE;
1381 }
1382
1383 _settingUpdateAvailable = false;
1384
1385 if (_log.isInfoEnabled()) {
1386 _log.info(
1387 "Finished checking for available updates in " +
1388 stopWatch.getTime() + " ms");
1389 }
1390 }
1391 }
1392
1393}