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