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