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