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