001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.plugin;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.plugin.License;
022    import com.liferay.portal.kernel.plugin.PluginPackage;
023    import com.liferay.portal.kernel.plugin.RemotePluginPackageRepository;
024    import com.liferay.portal.kernel.plugin.Screenshot;
025    import com.liferay.portal.kernel.plugin.Version;
026    import com.liferay.portal.kernel.search.Hits;
027    import com.liferay.portal.kernel.search.Indexer;
028    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
029    import com.liferay.portal.kernel.search.QueryConfig;
030    import com.liferay.portal.kernel.search.SearchContext;
031    import com.liferay.portal.kernel.util.ArrayUtil;
032    import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.kernel.util.HtmlUtil;
035    import com.liferay.portal.kernel.util.Http;
036    import com.liferay.portal.kernel.util.HttpUtil;
037    import com.liferay.portal.kernel.util.ListUtil;
038    import com.liferay.portal.kernel.util.PropertiesUtil;
039    import com.liferay.portal.kernel.util.PropsKeys;
040    import com.liferay.portal.kernel.util.ReleaseInfo;
041    import com.liferay.portal.kernel.util.StringBundler;
042    import com.liferay.portal.kernel.util.StringPool;
043    import com.liferay.portal.kernel.util.StringUtil;
044    import com.liferay.portal.kernel.util.Time;
045    import com.liferay.portal.kernel.util.Validator;
046    import com.liferay.portal.kernel.xml.Attribute;
047    import com.liferay.portal.kernel.xml.Document;
048    import com.liferay.portal.kernel.xml.DocumentException;
049    import com.liferay.portal.kernel.xml.Element;
050    import com.liferay.portal.kernel.xml.SAXReaderUtil;
051    import com.liferay.portal.model.CompanyConstants;
052    import com.liferay.portal.model.Plugin;
053    import com.liferay.portal.security.lang.DoPrivilegedBean;
054    import com.liferay.portal.util.HttpImpl;
055    import com.liferay.portal.util.PrefsPropsUtil;
056    import com.liferay.portal.util.PropsValues;
057    
058    import java.io.IOException;
059    import java.io.InputStream;
060    import java.io.Serializable;
061    
062    import java.net.MalformedURLException;
063    
064    import java.text.DateFormat;
065    
066    import java.util.ArrayList;
067    import java.util.Arrays;
068    import java.util.Collection;
069    import java.util.Date;
070    import java.util.HashMap;
071    import java.util.List;
072    import java.util.Locale;
073    import java.util.Map;
074    import java.util.Properties;
075    import java.util.Set;
076    import java.util.TreeSet;
077    import java.util.jar.Attributes;
078    import java.util.jar.Manifest;
079    
080    import javax.servlet.ServletContext;
081    import javax.servlet.http.HttpServletResponse;
082    
083    import org.apache.commons.httpclient.HostConfiguration;
084    import org.apache.commons.httpclient.HttpClient;
085    import org.apache.commons.httpclient.methods.GetMethod;
086    import org.apache.commons.lang.time.StopWatch;
087    
088    /**
089     * @author Jorge Ferrer
090     * @author Brian Wing Shun Chan
091     * @author Sandeep Soni
092     */
093    public class PluginPackageUtil {
094    
095            public static void endPluginPackageInstallation(String preliminaryContext) {
096                    _instance._endPluginPackageInstallation(preliminaryContext);
097            }
098    
099            public static List<PluginPackage> getAllAvailablePluginPackages()
100                    throws PortalException, SystemException {
101    
102                    return _instance._getAllAvailablePluginPackages();
103            }
104    
105            public static Collection<String> getAvailableTags() {
106                    return _instance._getAvailableTags();
107            }
108    
109            public static PluginPackage getInstalledPluginPackage(String context) {
110                    return _instance._getInstalledPluginPackage(context);
111            }
112    
113            public static List<PluginPackage> getInstalledPluginPackages() {
114                    return _instance._getInstalledPluginPackages();
115            }
116    
117            public static Date getLastUpdateDate() {
118                    return _instance._getLastUpdateDate();
119            }
120    
121            public static PluginPackage getLatestAvailablePluginPackage(
122                            String groupId, String artifactId)
123                    throws PortalException, SystemException {
124    
125                    return _instance._getLatestAvailablePluginPackage(groupId, artifactId);
126            }
127    
128            public static PluginPackage getLatestInstalledPluginPackage(
129                    String groupId, String artifactId) {
130    
131                    return _instance._getLatestInstalledPluginPackage(groupId, artifactId);
132            }
133    
134            public static PluginPackage getPluginPackageByModuleId(
135                            String moduleId, String repositoryURL)
136                    throws PortalException, SystemException {
137    
138                    return _instance._getPluginPackageByModuleId(moduleId, repositoryURL);
139            }
140    
141            public static PluginPackage getPluginPackageByURL(String url)
142                    throws PortalException, SystemException {
143    
144                    return _instance._getPluginPackageByURL(url);
145            }
146    
147            public static RemotePluginPackageRepository getRepository(
148                            String repositoryURL)
149                    throws PortalException, SystemException {
150    
151                    return _instance._getRepository(repositoryURL);
152            }
153    
154            public static String[] getRepositoryURLs() throws SystemException {
155                    return _instance._getRepositoryURLs();
156            }
157    
158            public static String[] getStatusAndInstalledVersion(
159                    PluginPackage pluginPackage) {
160    
161                    return _instance._getStatusAndInstalledVersion(pluginPackage);
162            }
163    
164            public static String[] getSupportedTypes() {
165                    return _instance._getSupportedTypes();
166            }
167    
168            public static boolean isCurrentVersionSupported(List<String> versions) {
169                    return _instance._isCurrentVersionSupported(versions);
170            }
171    
172            public static boolean isIgnored(PluginPackage pluginPackage)
173                    throws SystemException {
174    
175                    return _instance._isIgnored(pluginPackage);
176            }
177    
178            public static boolean isInstallationInProcess(String context) {
179                    return _instance._isInstallationInProcess(context);
180            }
181    
182            public static boolean isInstalled(String context) {
183                    return _instance._isInstalled(context);
184            }
185    
186            public static boolean isTrusted(String repositoryURL)
187                    throws SystemException {
188    
189                    return _instance._isTrusted(repositoryURL);
190            }
191    
192            public static boolean isUpdateAvailable() throws SystemException {
193                    return _instance._isUpdateAvailable();
194            }
195    
196            public static PluginPackage readPluginPackageProperties(
197                    String displayName, Properties properties) {
198    
199                    return _instance._readPluginPackageProperties(displayName, properties);
200            }
201    
202            public static PluginPackage readPluginPackageServletContext(
203                            ServletContext servletContext)
204                    throws DocumentException, IOException {
205    
206                    return _instance._readPluginPackageServletContext(servletContext);
207            }
208    
209            public static PluginPackage readPluginPackageXml(
210                    Element pluginPackageElement) {
211    
212                    return _instance._readPluginPackageXml(pluginPackageElement);
213            }
214    
215            public static PluginPackage readPluginPackageXml(String xml)
216                    throws DocumentException {
217    
218                    return _instance._readPluginPackageXml(xml);
219            }
220    
221            public static void refreshUpdatesAvailableCache() {
222                    _instance._refreshUpdatesAvailableCache();
223            }
224    
225            public static void registerInstalledPluginPackage(
226                            PluginPackage pluginPackage)
227                    throws PortalException {
228    
229                    _instance._registerInstalledPluginPackage(pluginPackage);
230            }
231    
232            public static void registerPluginPackageInstallation(
233                    String preliminaryContext) {
234    
235                    _instance._registerPluginPackageInstallation(preliminaryContext);
236            }
237    
238            public static RepositoryReport reloadRepositories()
239                    throws PortalException, SystemException {
240    
241                    return _instance._reloadRepositories();
242            }
243    
244            public static Hits search(
245                            String keywords, String type, String tag, String license,
246                            String repositoryURL, String status, int start, int end)
247                    throws PortalException, SystemException {
248    
249                    return _instance._search(
250                            keywords, type, tag, license, repositoryURL, status, start, end);
251            }
252    
253            public static void unregisterInstalledPluginPackage(
254                            PluginPackage pluginPackage)
255                    throws PortalException, SystemException {
256    
257                    _instance._unregisterInstalledPluginPackage(pluginPackage);
258            }
259    
260            public static void updateInstallingPluginPackage(
261                    String preliminaryContext, PluginPackage pluginPackage) {
262    
263                    _instance._updateInstallingPluginPackage(
264                            preliminaryContext, pluginPackage);
265            }
266    
267            private PluginPackageUtil() {
268                    _installedPluginPackages = new LocalPluginPackageRepository();
269                    _repositoryCache = new HashMap<String, RemotePluginPackageRepository>();
270                    _availableTagsCache = new TreeSet<String>();
271            }
272    
273            private void _checkRepositories(String repositoryURL)
274                    throws PortalException, SystemException {
275    
276                    String[] repositoryURLs = null;
277    
278                    if (Validator.isNotNull(repositoryURL)) {
279                            repositoryURLs = new String[] {repositoryURL};
280                    }
281                    else {
282                            repositoryURLs = _getRepositoryURLs();
283                    }
284    
285                    for (int i = 0; i < repositoryURLs.length; i++) {
286                            _getRepository(repositoryURLs[i]);
287                    }
288            }
289    
290            private void _endPluginPackageInstallation(String preliminaryContext) {
291                    _installedPluginPackages.unregisterPluginPackageInstallation(
292                            preliminaryContext);
293            }
294    
295            private PluginPackage _findLatestVersion(
296                    List<PluginPackage> pluginPackages) {
297    
298                    PluginPackage latestPluginPackage = null;
299    
300                    for (PluginPackage pluginPackage : pluginPackages) {
301                            if ((latestPluginPackage == null) ||
302                                    pluginPackage.isLaterVersionThan(latestPluginPackage)) {
303    
304                                    latestPluginPackage = pluginPackage;
305                            }
306                    }
307    
308                    return latestPluginPackage;
309            }
310    
311            private List<PluginPackage> _getAllAvailablePluginPackages()
312                    throws PortalException, SystemException {
313    
314                    List<PluginPackage> pluginPackages = new ArrayList<PluginPackage>();
315    
316                    String[] repositoryURLs = _getRepositoryURLs();
317    
318                    for (int i = 0; i < repositoryURLs.length; i++) {
319                            try {
320                                    RemotePluginPackageRepository repository = _getRepository(
321                                            repositoryURLs[i]);
322    
323                                    pluginPackages.addAll(repository.getPluginPackages());
324                            }
325                            catch (PluginPackageException ppe) {
326                                    String message = ppe.getMessage();
327    
328                                    if (message.startsWith("Unable to communicate")) {
329                                            if (_log.isWarnEnabled()) {
330                                                    _log.warn(message);
331                                            }
332                                    }
333                                    else {
334                                            _log.error(message);
335                                    }
336                            }
337                    }
338    
339                    return pluginPackages;
340            }
341    
342            private List<PluginPackage> _getAvailablePluginPackages(
343                            String groupId, String artifactId)
344                    throws PortalException, SystemException {
345    
346                    List<PluginPackage> pluginPackages = new ArrayList<PluginPackage>();
347    
348                    String[] repositoryURLs = _getRepositoryURLs();
349    
350                    for (int i = 0; i < repositoryURLs.length; i++) {
351                            RemotePluginPackageRepository repository = _getRepository(
352                                    repositoryURLs[i]);
353    
354                            List<PluginPackage> curPluginPackages =
355                                    repository.findPluginsByGroupIdAndArtifactId(
356                                            groupId, artifactId);
357    
358                            if (curPluginPackages != null) {
359                                    pluginPackages.addAll(curPluginPackages);
360                            }
361                    }
362    
363                    return pluginPackages;
364            }
365    
366            private Collection<String> _getAvailableTags() {
367                    return _availableTagsCache;
368            }
369    
370            private PluginPackage _getInstalledPluginPackage(String context) {
371                    return _installedPluginPackages.getPluginPackage(context);
372            }
373    
374            private List<PluginPackage> _getInstalledPluginPackages() {
375                    return _installedPluginPackages.getSortedPluginPackages();
376            }
377    
378            private Date _getLastUpdateDate() {
379                    return _lastUpdateDate;
380            }
381    
382            private PluginPackage _getLatestAvailablePluginPackage(
383                            String groupId, String artifactId)
384                    throws PortalException, SystemException {
385    
386                    List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
387                            groupId, artifactId);
388    
389                    return _findLatestVersion(pluginPackages);
390            }
391    
392            private PluginPackage _getLatestInstalledPluginPackage(
393                    String groupId, String artifactId) {
394    
395                    return _installedPluginPackages.getLatestPluginPackage(
396                            groupId, artifactId);
397            }
398    
399            private PluginPackage _getPluginPackageByModuleId(
400                            String moduleId, String repositoryURL)
401                    throws PortalException, SystemException {
402    
403                    RemotePluginPackageRepository repository = _getRepository(
404                            repositoryURL);
405    
406                    return repository.findPluginPackageByModuleId(moduleId);
407            }
408    
409            private PluginPackage _getPluginPackageByURL(String url)
410                    throws PortalException, SystemException {
411    
412                    String[] repositoryURLs = _getRepositoryURLs();
413    
414                    for (int i = 0; i < repositoryURLs.length; i++) {
415                            String repositoryURL = repositoryURLs[i];
416    
417                            try {
418                                    RemotePluginPackageRepository repository = _getRepository(
419                                            repositoryURL);
420    
421                                    return repository.findPluginByArtifactURL(url);
422                            }
423                            catch (PluginPackageException ppe) {
424                                    _log.error("Unable to load repository " + repositoryURL, ppe);
425                            }
426                    }
427    
428                    return null;
429            }
430    
431            private RemotePluginPackageRepository _getRepository(String repositoryURL)
432                    throws PortalException, SystemException {
433    
434                    RemotePluginPackageRepository repository = _repositoryCache.get(
435                            repositoryURL);
436    
437                    if (repository != null) {
438                            return repository;
439                    }
440    
441                    return _loadRepository(repositoryURL);
442            }
443    
444            private String[] _getRepositoryURLs() throws PluginPackageException {
445                    try {
446                            String[] trusted = PrefsPropsUtil.getStringArray(
447                                    PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
448                                    PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
449                            String[] untrusted = PrefsPropsUtil.getStringArray(
450                                    PropsKeys.PLUGIN_REPOSITORIES_UNTRUSTED, StringPool.NEW_LINE,
451                                    PropsValues.PLUGIN_REPOSITORIES_UNTRUSTED);
452    
453                            return ArrayUtil.append(trusted, untrusted);
454                    }
455                    catch (Exception e) {
456                            throw new PluginPackageException(
457                                    "Unable to read repository list", e);
458                    }
459            }
460    
461            private String[] _getStatusAndInstalledVersion(
462                    PluginPackage pluginPackage) {
463    
464                    PluginPackage installedPluginPackage =
465                            _installedPluginPackages.getLatestPluginPackage(
466                                    pluginPackage.getGroupId(), pluginPackage.getArtifactId());
467    
468                    String status = null;
469                    String installedVersion = null;
470    
471                    if (installedPluginPackage == null) {
472                            status = PluginPackageImpl.STATUS_NOT_INSTALLED;
473                    }
474                    else {
475                            installedVersion = installedPluginPackage.getVersion();
476    
477                            if (installedPluginPackage.isLaterVersionThan(pluginPackage)) {
478                                    status = PluginPackageImpl.STATUS_NEWER_VERSION_INSTALLED;
479                            }
480                            else if (installedPluginPackage.isPreviousVersionThan(
481                                                    pluginPackage)) {
482    
483                                    status = PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED;
484                            }
485                            else {
486                                    status = PluginPackageImpl.STATUS_SAME_VERSION_INSTALLED;
487                            }
488                    }
489    
490                    return new String[] {status, installedVersion};
491            }
492    
493            private String[] _getSupportedTypes() {
494                    return PropsValues.PLUGIN_TYPES;
495            }
496    
497            private void _indexPluginPackage(PluginPackage pluginPackage)
498                    throws PortalException {
499    
500                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
501    
502                    indexer.reindex(pluginPackage);
503            }
504    
505            private boolean _isCurrentVersionSupported(List<String> versions) {
506                    Version currentVersion = Version.getInstance(ReleaseInfo.getVersion());
507    
508                    for (String version : versions) {
509                            Version supportedVersion = Version.getInstance(version);
510    
511                            if (supportedVersion.includes(currentVersion)) {
512                                    return true;
513                            }
514                    }
515    
516                    return false;
517            }
518    
519            private boolean _isIgnored(PluginPackage pluginPackage)
520                    throws SystemException {
521    
522                    String packageId = pluginPackage.getPackageId();
523    
524                    String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
525                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
526                            StringPool.NEW_LINE,
527                            PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
528    
529                    for (int i = 0; i < pluginPackagesIgnored.length; i++) {
530                            String curPluginPackagesIgnored = pluginPackagesIgnored[i];
531    
532                            if (curPluginPackagesIgnored.endsWith(StringPool.STAR)) {
533                                    String prefix = curPluginPackagesIgnored.substring(
534                                            0, curPluginPackagesIgnored.length() - 2);
535    
536                                    if (packageId.startsWith(prefix)) {
537                                            return true;
538                                    }
539                            }
540                            else {
541                                    if (packageId.equals(curPluginPackagesIgnored)) {
542                                            return true;
543                                    }
544                            }
545                    }
546    
547                    return false;
548            }
549    
550            private boolean _isInstallationInProcess(String context) {
551                    if (_installedPluginPackages.getInstallingPluginPackage(
552                                    context) != null) {
553    
554                            return true;
555                    }
556                    else {
557                            return false;
558                    }
559            }
560    
561            private boolean _isInstalled(String context) {
562                    PluginPackage pluginPackage = _installedPluginPackages.getPluginPackage(
563                            context);
564    
565                    if (pluginPackage != null) {
566                            return true;
567                    }
568                    else {
569                            return false;
570                    }
571            }
572    
573            private boolean _isTrusted(String repositoryURL)
574                    throws PluginPackageException {
575    
576                    try {
577                            String[] trusted = PrefsPropsUtil.getStringArray(
578                                    PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
579                                    PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
580    
581                            if (ArrayUtil.contains(trusted, repositoryURL)) {
582                                    return true;
583                            }
584                            else {
585                                    return false;
586                            }
587                    }
588                    catch (Exception e) {
589                            throw new PluginPackageException(
590                                    "Unable to read repository list", e);
591                    }
592            }
593    
594            private boolean _isUpdateAvailable() throws SystemException {
595                    if (!PrefsPropsUtil.getBoolean(
596                                    PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
597                                    PropsValues.PLUGIN_NOTIFICATIONS_ENABLED)) {
598    
599                            return false;
600                    }
601    
602                    if (_updateAvailable != null) {
603                            return _updateAvailable.booleanValue();
604                    }
605                    else if (!_settingUpdateAvailable) {
606                            _settingUpdateAvailable = true;
607    
608                            Thread indexerThread = new Thread(
609                                    new UpdateAvailableRunner(), PluginPackageUtil.class.getName());
610    
611                            indexerThread.setPriority(Thread.MIN_PRIORITY);
612    
613                            indexerThread.start();
614                    }
615    
616                    return false;
617            }
618    
619            private RemotePluginPackageRepository _loadRepository(String repositoryURL)
620                    throws PluginPackageException, PortalException {
621    
622                    RemotePluginPackageRepository repository = null;
623    
624                    StringBundler sb = new StringBundler(8);
625    
626                    if (!repositoryURL.startsWith(Http.HTTP_WITH_SLASH) &&
627                            !repositoryURL.startsWith(Http.HTTPS_WITH_SLASH)) {
628    
629                            sb.append(Http.HTTP_WITH_SLASH);
630                    }
631    
632                    sb.append(repositoryURL);
633                    sb.append(StringPool.SLASH);
634                    sb.append(PluginPackage.REPOSITORY_XML_FILENAME_PREFIX);
635                    sb.append(StringPool.DASH);
636                    sb.append(ReleaseInfo.getVersion());
637                    sb.append(StringPool.PERIOD);
638                    sb.append(PluginPackage.REPOSITORY_XML_FILENAME_EXTENSION);
639    
640                    String pluginsXmlURL = sb.toString();
641    
642                    try {
643                            HttpImpl httpImpl = null;
644    
645                            Object httpObject = HttpUtil.getHttp();
646    
647                            if (httpObject instanceof DoPrivilegedBean) {
648                                    DoPrivilegedBean doPrivilegedBean =
649                                            (DoPrivilegedBean)httpObject;
650    
651                                    httpImpl = (HttpImpl)doPrivilegedBean.getActualBean();
652                            }
653                            else {
654                                    httpImpl = (HttpImpl)httpObject;
655                            }
656    
657                            HostConfiguration hostConfiguration = httpImpl.getHostConfiguration(
658                                    pluginsXmlURL);
659    
660                            HttpClient httpClient = httpImpl.getClient(hostConfiguration);
661    
662                            httpImpl.proxifyState(httpClient.getState(), hostConfiguration);
663    
664                            GetMethod getFileMethod = new GetMethod(pluginsXmlURL);
665    
666                            byte[] bytes = null;
667    
668                            try {
669                                    int responseCode = httpClient.executeMethod(
670                                            hostConfiguration, getFileMethod);
671    
672                                    if (responseCode != HttpServletResponse.SC_OK) {
673                                            if (_log.isDebugEnabled()) {
674                                                    _log.debug(
675                                                            "A repository for version " +
676                                                                    ReleaseInfo.getVersion() + " was not found. " +
677                                                                            "Checking general repository");
678                                            }
679    
680                                            sb.setIndex(0);
681    
682                                            sb.append(repositoryURL);
683                                            sb.append(StringPool.SLASH);
684                                            sb.append(PluginPackage.REPOSITORY_XML_FILENAME_PREFIX);
685                                            sb.append(StringPool.PERIOD);
686                                            sb.append(PluginPackage.REPOSITORY_XML_FILENAME_EXTENSION);
687    
688                                            pluginsXmlURL = sb.toString();
689    
690                                            getFileMethod.releaseConnection();
691    
692                                            getFileMethod = new GetMethod(pluginsXmlURL);
693    
694                                            responseCode = httpClient.executeMethod(
695                                                    hostConfiguration, getFileMethod);
696    
697                                            if (responseCode != HttpServletResponse.SC_OK) {
698                                                    throw new PluginPackageException(
699                                                            "Unable to download file " + pluginsXmlURL +
700                                                                    " because of response code " + responseCode);
701                                            }
702                                    }
703    
704                                    bytes = getFileMethod.getResponseBody();
705                            }
706                            finally {
707                                    getFileMethod.releaseConnection();
708                            }
709    
710                            if ((bytes != null) && (bytes.length > 0)) {
711                                    repository = _parseRepositoryXml(
712                                            new String(bytes), repositoryURL);
713    
714                                    _repositoryCache.put(repositoryURL, repository);
715                                    _availableTagsCache.addAll(repository.getTags());
716                                    _lastUpdateDate = new Date();
717                                    _updateAvailable = null;
718    
719                                    return repository;
720                            }
721                            else {
722                                    _lastUpdateDate = new Date();
723    
724                                    throw new PluginPackageException("Download returned 0 bytes");
725                            }
726                    }
727                    catch (MalformedURLException murle) {
728                            _repositoryCache.remove(repositoryURL);
729    
730                            throw new PluginPackageException(
731                                    "Invalid URL " + pluginsXmlURL, murle);
732                    }
733                    catch (IOException ioe) {
734                            _repositoryCache.remove(repositoryURL);
735    
736                            throw new PluginPackageException(
737                                    "Unable to communicate with repository " + repositoryURL, ioe);
738                    }
739                    catch (DocumentException de) {
740                            _repositoryCache.remove(repositoryURL);
741    
742                            throw new PluginPackageException(
743                                    "Unable to parse plugin list for repository " + repositoryURL,
744                                    de);
745                    }
746            }
747    
748            private RemotePluginPackageRepository _parseRepositoryXml(
749                            String xml, String repositoryURL)
750                    throws DocumentException, PortalException {
751    
752                    List<String> supportedPluginTypes = Arrays.asList(getSupportedTypes());
753    
754                    if (_log.isDebugEnabled()) {
755                            _log.debug(
756                                    "Loading plugin repository " + repositoryURL + ":\n" + xml);
757                    }
758    
759                    RemotePluginPackageRepository pluginPackageRepository =
760                            new RemotePluginPackageRepository(repositoryURL);
761    
762                    if (xml == null) {
763                            return pluginPackageRepository;
764                    }
765    
766                    Document document = SAXReaderUtil.read(xml);
767    
768                    Element rootElement = document.getRootElement();
769    
770                    Properties settings = _readProperties(
771                            rootElement.element("settings"), "setting");
772    
773                    pluginPackageRepository.setSettings(settings);
774    
775                    List<Element> pluginPackageElements = rootElement.elements(
776                            "plugin-package");
777    
778                    for (Element pluginPackageElement : pluginPackageElements) {
779                            PluginPackage pluginPackage = _readPluginPackageXml(
780                                    pluginPackageElement);
781    
782                            if (!_isCurrentVersionSupported(
783                                            pluginPackage.getLiferayVersions())) {
784    
785                                    continue;
786                            }
787    
788                            boolean containsSupportedTypes = false;
789    
790                            List<String> pluginTypes = pluginPackage.getTypes();
791    
792                            for (String pluginType : pluginTypes) {
793                                    if (supportedPluginTypes.contains(pluginType)) {
794                                            containsSupportedTypes = true;
795    
796                                            break;
797                                    }
798                            }
799    
800                            if (!containsSupportedTypes) {
801                                    continue;
802                            }
803    
804                            pluginPackage.setRepository(pluginPackageRepository);
805    
806                            pluginPackageRepository.addPluginPackage(pluginPackage);
807    
808                            _indexPluginPackage(pluginPackage);
809                    }
810    
811                    return pluginPackageRepository;
812            }
813    
814            private Date _readDate(String text) {
815                    if (Validator.isNotNull(text)) {
816                            DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
817                                    Time.RFC822_FORMAT, Locale.US);
818    
819                            try {
820                                    return dateFormat.parse(text);
821                            }
822                            catch (Exception e) {
823                                    if (_log.isWarnEnabled()) {
824                                            _log.warn("Unable to parse date " + text);
825                                    }
826                            }
827                    }
828    
829                    return new Date();
830            }
831    
832            private String _readHtml(String text) {
833                    return GetterUtil.getString(text);
834            }
835    
836            private List<License> _readLicenseList(Element parentElement, String name) {
837                    List<License> licenses = new ArrayList<License>();
838    
839                    for (Element licenseElement : parentElement.elements(name)) {
840                            License license = new License();
841    
842                            license.setName(licenseElement.getText());
843    
844                            Attribute osiApproved = licenseElement.attribute("osi-approved");
845    
846                            if (osiApproved != null) {
847                                    license.setOsiApproved(
848                                            GetterUtil.getBoolean(osiApproved.getText()));
849                            }
850    
851                            Attribute url = licenseElement.attribute("url");
852    
853                            if (url != null) {
854                                    license.setUrl(url.getText());
855                            }
856    
857                            licenses.add(license);
858                    }
859    
860                    return licenses;
861            }
862    
863            private List<String> _readList(Element parentElement, String name) {
864                    List<String> list = new ArrayList<String>();
865    
866                    if (parentElement == null) {
867                            return list;
868                    }
869    
870                    for (Element element : parentElement.elements(name)) {
871                            String text = element.getText().trim().toLowerCase();
872    
873                            list.add(text);
874                    }
875    
876                    return list;
877            }
878    
879            private PluginPackage _readPluginPackageProperties(
880                    String displayName, Properties properties) {
881    
882                    int pos = displayName.indexOf("-portlet");
883    
884                    String pluginType = Plugin.TYPE_PORTLET;
885    
886                    if (pos == -1) {
887                            pos = displayName.indexOf("-ext");
888    
889                            pluginType = Plugin.TYPE_EXT;
890                    }
891    
892                    if (pos == -1) {
893                            pos = displayName.indexOf("-hook");
894    
895                            pluginType = Plugin.TYPE_HOOK;
896                    }
897    
898                    if (pos == -1) {
899                            pos = displayName.indexOf("-layouttpl");
900    
901                            pluginType = Plugin.TYPE_LAYOUT_TEMPLATE;
902                    }
903    
904                    if (pos == -1) {
905                            pos = displayName.indexOf("-theme");
906    
907                            pluginType = Plugin.TYPE_THEME;
908                    }
909    
910                    if (pos == -1) {
911                            pos = displayName.indexOf("-web");
912    
913                            pluginType = Plugin.TYPE_WEB;
914                    }
915    
916                    if (pos == -1) {
917                            return null;
918                    }
919    
920                    String displayPrefix = displayName.substring(0, pos);
921    
922                    String moduleGroupId = GetterUtil.getString(
923                            properties.getProperty("module-group-id"));
924                    String moduleArtifactId = displayPrefix + "-" + pluginType;
925    
926                    String moduleVersion = GetterUtil.getString(
927                            properties.getProperty("module-version"));
928    
929                    if (Validator.isNull(moduleVersion)) {
930                            int moduleVersionPos = pos + pluginType.length() + 2;
931    
932                            if (displayName.length() > moduleVersionPos) {
933                                    moduleVersion = displayName.substring(moduleVersionPos);
934                            }
935                            else {
936                                    moduleVersion = ReleaseInfo.getVersion();
937                            }
938                    }
939    
940                    String moduleId =
941                            moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
942                                    "/war";
943    
944                    String pluginName = GetterUtil.getString(
945                            properties.getProperty("name"));
946    
947                    String deploymentContext = GetterUtil.getString(
948                            properties.getProperty("recommended-deployment-context"),
949                            moduleArtifactId);
950    
951                    String author = GetterUtil.getString(properties.getProperty("author"));
952    
953                    List<String> types = new ArrayList<String>();
954    
955                    types.add(pluginType);
956    
957                    List<License> licenses = new ArrayList<License>();
958    
959                    String[] licensesArray = StringUtil.split(
960                            properties.getProperty("licenses"));
961    
962                    for (int i = 0; i < licensesArray.length; i++) {
963                            License license = new License();
964    
965                            license.setName(licensesArray[i].trim());
966                            license.setOsiApproved(true);
967    
968                            licenses.add(license);
969                    }
970    
971                    List<String> liferayVersions = new ArrayList<String>();
972    
973                    String[] liferayVersionsArray = StringUtil.split(
974                            properties.getProperty("liferay-versions"));
975    
976                    for (String liferayVersion : liferayVersionsArray) {
977                            liferayVersions.add(liferayVersion.trim());
978                    }
979    
980                    if (liferayVersions.size() == 0) {
981                            liferayVersions.add(ReleaseInfo.getVersion() + "+");
982                    }
983    
984                    List<String> tags = new ArrayList<String>();
985    
986                    String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
987    
988                    for (String tag : tagsArray) {
989                            tags.add(tag.trim());
990                    }
991    
992                    String shortDescription = GetterUtil.getString(
993                            properties.getProperty("short-description"));
994                    String longDescription = GetterUtil.getString(
995                            properties.getProperty("long-description"));
996                    String changeLog = GetterUtil.getString(
997                            properties.getProperty("change-log"));
998                    String pageURL = GetterUtil.getString(
999                            properties.getProperty("page-url"));
1000                    String downloadURL = GetterUtil.getString(
1001                            properties.getProperty("download-url"));
1002                    List<String> requiredDeploymentContexts = ListUtil.fromArray(
1003                            StringUtil.split(
1004                                    properties.getProperty("required-deployment-contexts")));
1005    
1006                    PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
1007    
1008                    pluginPackage.setName(pluginName);
1009                    pluginPackage.setRecommendedDeploymentContext(deploymentContext);
1010                    //pluginPackage.setModifiedDate(null);
1011                    pluginPackage.setAuthor(author);
1012                    pluginPackage.setTypes(types);
1013                    pluginPackage.setLicenses(licenses);
1014                    pluginPackage.setLiferayVersions(liferayVersions);
1015                    pluginPackage.setTags(tags);
1016                    pluginPackage.setShortDescription(shortDescription);
1017                    pluginPackage.setLongDescription(longDescription);
1018                    pluginPackage.setChangeLog(changeLog);
1019                    //pluginPackage.setScreenshots(null);
1020                    pluginPackage.setPageURL(pageURL);
1021                    pluginPackage.setDownloadURL(downloadURL);
1022                    //pluginPackage.setDeploymentSettings(null);
1023                    pluginPackage.setRequiredDeploymentContexts(requiredDeploymentContexts);
1024    
1025                    return pluginPackage;
1026            }
1027    
1028            /**
1029             * @see {@link
1030             *      com.liferay.portal.tools.deploy.BaseDeployer#readPluginPackage(
1031             *      java.io.File)}
1032             */
1033            private PluginPackage _readPluginPackageServletContext(
1034                            ServletContext servletContext)
1035                    throws DocumentException, IOException {
1036    
1037                    String servletContextName = servletContext.getServletContextName();
1038    
1039                    if (_log.isInfoEnabled()) {
1040                            if (servletContextName == null) {
1041                                    _log.info("Reading plugin package for the root context");
1042                            }
1043                            else {
1044                                    _log.info("Reading plugin package for " + servletContextName);
1045                            }
1046                    }
1047    
1048                    PluginPackage pluginPackage = null;
1049    
1050                    String xml = HttpUtil.URLtoString(
1051                            servletContext.getResource("/WEB-INF/liferay-plugin-package.xml"));
1052    
1053                    if (xml != null) {
1054                            pluginPackage = _readPluginPackageXml(xml);
1055                    }
1056                    else {
1057                            String propertiesString = HttpUtil.URLtoString(
1058                                    servletContext.getResource(
1059                                            "/WEB-INF/liferay-plugin-package.properties"));
1060    
1061                            if (propertiesString != null) {
1062                                    if (_log.isDebugEnabled()) {
1063                                            _log.debug(
1064                                                    "Reading plugin package from " +
1065                                                            "liferay-plugin-package.properties");
1066                                    }
1067    
1068                                    Properties properties = PropertiesUtil.load(propertiesString);
1069    
1070                                    String displayName = servletContextName;
1071    
1072                                    if (displayName.startsWith(StringPool.SLASH)) {
1073                                            displayName = displayName.substring(1);
1074                                    }
1075    
1076                                    pluginPackage = _readPluginPackageProperties(
1077                                            displayName, properties);
1078                            }
1079    
1080                            if (pluginPackage == null) {
1081                                    if (_log.isDebugEnabled()) {
1082                                            _log.debug("Reading plugin package from MANIFEST.MF");
1083                                    }
1084    
1085                                    pluginPackage =_readPluginPackageServletManifest(
1086                                            servletContext);
1087                            }
1088                    }
1089    
1090                    pluginPackage.setContext(servletContextName);
1091    
1092                    return pluginPackage;
1093            }
1094    
1095            private PluginPackage _readPluginPackageServletManifest(
1096                            ServletContext servletContext)
1097                    throws IOException {
1098    
1099                    Attributes attributes = null;
1100    
1101                    String servletContextName = servletContext.getServletContextName();
1102    
1103                    InputStream inputStream = servletContext.getResourceAsStream(
1104                            "/META-INF/MANIFEST.MF");
1105    
1106                    if (inputStream != null) {
1107                            Manifest manifest = new Manifest(inputStream);
1108    
1109                            attributes = manifest.getMainAttributes();
1110                    }
1111                    else {
1112                            attributes = new Attributes();
1113                    }
1114    
1115                    String artifactGroupId = attributes.getValue(
1116                            "Implementation-Vendor-Id");
1117    
1118                    if (Validator.isNull(artifactGroupId)) {
1119                            artifactGroupId = attributes.getValue("Implementation-Vendor");
1120                    }
1121    
1122                    if (Validator.isNull(artifactGroupId)) {
1123                            artifactGroupId = GetterUtil.getString(
1124                                    attributes.getValue("Bundle-Vendor"), servletContextName);
1125                    }
1126    
1127                    String artifactId = attributes.getValue("Implementation-Title");
1128    
1129                    if (Validator.isNull(artifactId)) {
1130                            artifactId = GetterUtil.getString(
1131                                    attributes.getValue("Bundle-Name"), servletContextName);
1132                    }
1133    
1134                    String version = attributes.getValue("Implementation-Version");
1135    
1136                    if (Validator.isNull(version)) {
1137                            version = GetterUtil.getString(
1138                                    attributes.getValue("Bundle-Version"), Version.UNKNOWN);
1139                    }
1140    
1141                    if (version.equals(Version.UNKNOWN) && _log.isWarnEnabled()) {
1142                            _log.warn(
1143                                    "Plugin package on context " + servletContextName +
1144                                            " cannot be tracked because this WAR does not contain a " +
1145                                                    "liferay-plugin-package.xml file");
1146                    }
1147    
1148                    PluginPackage pluginPackage = new PluginPackageImpl(
1149                            artifactGroupId + StringPool.SLASH + artifactId + StringPool.SLASH +
1150                                    version + StringPool.SLASH + "war");
1151    
1152                    pluginPackage.setName(artifactId);
1153    
1154                    String shortDescription = attributes.getValue("Bundle-Description");
1155    
1156                    if (Validator.isNotNull(shortDescription)) {
1157                            pluginPackage.setShortDescription(shortDescription);
1158                    }
1159    
1160                    String pageURL = attributes.getValue("Bundle-DocURL");
1161    
1162                    if (Validator.isNotNull(pageURL)) {
1163                            pluginPackage.setPageURL(pageURL);
1164                    }
1165    
1166                    return pluginPackage;
1167            }
1168    
1169            private PluginPackage _readPluginPackageXml(Element pluginPackageElement) {
1170                    String name = pluginPackageElement.elementText("name");
1171    
1172                    if (_log.isDebugEnabled()) {
1173                            _log.debug("Reading pluginPackage definition " + name);
1174                    }
1175    
1176                    PluginPackage pluginPackage = new PluginPackageImpl(
1177                            GetterUtil.getString(
1178                                    pluginPackageElement.elementText("module-id")));
1179    
1180                    List<String> liferayVersions = _readList(
1181                            pluginPackageElement.element("liferay-versions"),
1182                            "liferay-version");
1183    
1184                    List<String> types = _readList(
1185                            pluginPackageElement.element("types"), "type");
1186    
1187                    if (types.contains("layout-template")) {
1188                            types.remove("layout-template");
1189    
1190                            types.add(Plugin.TYPE_LAYOUT_TEMPLATE);
1191                    }
1192    
1193                    pluginPackage.setName(_readText(name));
1194                    pluginPackage.setRecommendedDeploymentContext(
1195                            _readText(
1196                                    pluginPackageElement.elementText(
1197                                            "recommended-deployment-context")));
1198                    pluginPackage.setRequiredDeploymentContexts(
1199                            _readList(
1200                                    pluginPackageElement.element(
1201                                            "required-deployment-contexts"),
1202                                            "required-deployment-context"));
1203                    pluginPackage.setModifiedDate(
1204                            _readDate(pluginPackageElement.elementText("modified-date")));
1205                    pluginPackage.setAuthor(
1206                            _readText(pluginPackageElement.elementText("author")));
1207                    pluginPackage.setTypes(types);
1208                    pluginPackage.setLicenses(
1209                            _readLicenseList(
1210                                    pluginPackageElement.element("licenses"), "license"));
1211                    pluginPackage.setLiferayVersions(liferayVersions);
1212                    pluginPackage.setTags(
1213                            _readList(pluginPackageElement.element("tags"), "tag"));
1214                    pluginPackage.setShortDescription(
1215                            _readText(pluginPackageElement.elementText("short-description")));
1216                    pluginPackage.setLongDescription(
1217                            _readHtml(pluginPackageElement.elementText("long-description")));
1218                    pluginPackage.setChangeLog(
1219                            _readHtml(pluginPackageElement.elementText("change-log")));
1220                    pluginPackage.setScreenshots(
1221                            _readScreenshots(pluginPackageElement.element("screenshots")));
1222                    pluginPackage.setPageURL(
1223                            _readText(pluginPackageElement.elementText("page-url")));
1224                    pluginPackage.setDownloadURL(
1225                            _readText(pluginPackageElement.elementText("download-url")));
1226                    pluginPackage.setDeploymentSettings(
1227                            _readProperties(
1228                                    pluginPackageElement.element("deployment-settings"),
1229                                    "setting"));
1230    
1231                    return pluginPackage;
1232            }
1233    
1234            private PluginPackage _readPluginPackageXml(String xml)
1235                    throws DocumentException {
1236    
1237                    Document document = SAXReaderUtil.read(xml);
1238    
1239                    Element rootElement = document.getRootElement();
1240    
1241                    return _readPluginPackageXml(rootElement);
1242            }
1243    
1244            private Properties _readProperties(Element parentElement, String name) {
1245                    Properties properties = new Properties();
1246    
1247                    if (parentElement == null) {
1248                            return properties;
1249                    }
1250    
1251                    for (Element element : parentElement.elements(name)) {
1252                            properties.setProperty(
1253                                    element.attributeValue("name"),
1254                                    element.attributeValue("value"));
1255                    }
1256    
1257                    return properties;
1258            }
1259    
1260            private List<Screenshot> _readScreenshots(Element parentElement) {
1261                    List<Screenshot> screenshots = new ArrayList<Screenshot>();
1262    
1263                    if (parentElement == null) {
1264                            return screenshots;
1265                    }
1266    
1267                    for (Element screenshotElement : parentElement.elements("screenshot")) {
1268                            Screenshot screenshot = new Screenshot();
1269    
1270                            screenshot.setThumbnailURL(
1271                                    screenshotElement.elementText("thumbnail-url"));
1272                            screenshot.setLargeImageURL(
1273                                    screenshotElement.elementText("large-image-url"));
1274    
1275                            screenshots.add(screenshot);
1276                    }
1277    
1278                    return screenshots;
1279            }
1280    
1281            private String _readText(String text) {
1282                    return HtmlUtil.extractText(GetterUtil.getString(text));
1283            }
1284    
1285            private void _refreshUpdatesAvailableCache() {
1286                    _updateAvailable = null;
1287            }
1288    
1289            private void _registerInstalledPluginPackage(PluginPackage pluginPackage)
1290                    throws PortalException {
1291    
1292                    _installedPluginPackages.addPluginPackage(pluginPackage);
1293    
1294                    _updateAvailable = null;
1295    
1296                    _indexPluginPackage(pluginPackage);
1297            }
1298    
1299            private void _registerPluginPackageInstallation(String preliminaryContext) {
1300                    _installedPluginPackages.registerPluginPackageInstallation(
1301                            preliminaryContext);
1302            }
1303    
1304            private RepositoryReport _reloadRepositories()
1305                    throws PortalException, SystemException {
1306    
1307                    if (_log.isInfoEnabled()) {
1308                            _log.info("Reloading repositories");
1309                    }
1310    
1311                    RepositoryReport repositoryReport = new RepositoryReport();
1312    
1313                    String[] repositoryURLs = _getRepositoryURLs();
1314    
1315                    for (int i = 0; i < repositoryURLs.length; i++) {
1316                            String repositoryURL = repositoryURLs[i];
1317    
1318                            try {
1319                                    _loadRepository(repositoryURL);
1320    
1321                                    repositoryReport.addSuccess(repositoryURL);
1322                            }
1323                            catch (PluginPackageException ppe) {
1324                                    repositoryReport.addError(repositoryURL, ppe);
1325    
1326                                    _log.error(
1327                                            "Unable to load repository " + repositoryURL + " " +
1328                                                    ppe.toString());
1329                            }
1330    
1331                    }
1332    
1333                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1334    
1335                    indexer.reindex(new String[0]);
1336    
1337                    return repositoryReport;
1338            }
1339    
1340            private Hits _search(
1341                            String keywords, String type, String tag, String license,
1342                            String repositoryURL, String status, int start, int end)
1343                    throws PortalException, SystemException {
1344    
1345                    _checkRepositories(repositoryURL);
1346    
1347                    SearchContext searchContext = new SearchContext();
1348    
1349                    Map<String, Serializable> attributes =
1350                            new HashMap<String, Serializable>();
1351    
1352                    attributes.put("license", license);
1353                    attributes.put("repositoryURL", repositoryURL);
1354                    attributes.put("status", status);
1355                    attributes.put("tag", tag);
1356                    attributes.put("type", type);
1357    
1358                    searchContext.setAttributes(attributes);
1359    
1360                    searchContext.setCompanyId(CompanyConstants.SYSTEM);
1361                    searchContext.setEnd(end);
1362                    searchContext.setKeywords(keywords);
1363    
1364                    QueryConfig queryConfig = new QueryConfig();
1365    
1366                    queryConfig.setHighlightEnabled(false);
1367                    queryConfig.setScoreEnabled(false);
1368    
1369                    searchContext.setQueryConfig(queryConfig);
1370    
1371                    searchContext.setStart(start);
1372    
1373                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1374    
1375                    return indexer.search(searchContext);
1376            }
1377    
1378            private void _unregisterInstalledPluginPackage(PluginPackage pluginPackage)
1379                    throws PortalException, SystemException {
1380    
1381                    _installedPluginPackages.removePluginPackage(pluginPackage);
1382    
1383                    try {
1384                            List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1385                                    pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1386    
1387                            for (PluginPackage availablePackage : pluginPackages) {
1388                                    _indexPluginPackage(availablePackage);
1389                            }
1390                    }
1391                    catch (PluginPackageException ppe) {
1392                            if (_log.isWarnEnabled()) {
1393                                    _log.warn(
1394                                            "Unable to reindex unistalled package " +
1395                                                    pluginPackage.getContext() + ": " + ppe.getMessage());
1396                            }
1397                    }
1398            }
1399    
1400            private void _updateInstallingPluginPackage(
1401                    String preliminaryContext, PluginPackage pluginPackage) {
1402    
1403                    _installedPluginPackages.unregisterPluginPackageInstallation(
1404                            preliminaryContext);
1405                    _installedPluginPackages.registerPluginPackageInstallation(
1406                            pluginPackage);
1407            }
1408    
1409            private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1410    
1411            private static PluginPackageUtil _instance = new PluginPackageUtil();
1412    
1413            private Set<String> _availableTagsCache;
1414            private LocalPluginPackageRepository _installedPluginPackages;
1415            private Date _lastUpdateDate;
1416            private Map<String, RemotePluginPackageRepository> _repositoryCache;
1417            private boolean _settingUpdateAvailable;
1418            private Boolean _updateAvailable;
1419    
1420            private class UpdateAvailableRunner implements Runnable {
1421    
1422                    public void run() {
1423                            try {
1424                                    setUpdateAvailable();
1425                            }
1426                            catch (Exception e) {
1427                                    if (_log.isWarnEnabled()) {
1428                                            _log.warn(e.getMessage());
1429                                    }
1430                            }
1431                    }
1432    
1433                    protected void setUpdateAvailable() throws Exception {
1434                            StopWatch stopWatch = null;
1435    
1436                            if (_log.isInfoEnabled()) {
1437                                    _log.info("Checking for available updates");
1438    
1439                                    stopWatch = new StopWatch();
1440    
1441                                    stopWatch.start();
1442                            }
1443    
1444                            for (PluginPackage pluginPackage :
1445                                            _installedPluginPackages.getPluginPackages()) {
1446    
1447                                    PluginPackage availablePluginPackage = null;
1448    
1449                                    if (_isIgnored(pluginPackage)) {
1450                                            continue;
1451                                    }
1452    
1453                                    availablePluginPackage =
1454                                            PluginPackageUtil.getLatestAvailablePluginPackage(
1455                                                    pluginPackage.getGroupId(),
1456                                                    pluginPackage.getArtifactId());
1457    
1458                                    if (availablePluginPackage == null) {
1459                                            continue;
1460                                    }
1461    
1462                                    Version availablePluginPackageVersion = Version.getInstance(
1463                                            availablePluginPackage.getVersion());
1464    
1465                                    if (availablePluginPackageVersion.isLaterVersionThan(
1466                                                    pluginPackage.getVersion())) {
1467    
1468                                            _updateAvailable = Boolean.TRUE;
1469    
1470                                            break;
1471                                    }
1472                            }
1473    
1474                            if (_updateAvailable == null) {
1475                                    _updateAvailable = Boolean.FALSE;
1476                            }
1477    
1478                            _settingUpdateAvailable = false;
1479    
1480                            if (_log.isInfoEnabled()) {
1481                                    _log.info(
1482                                            "Finished checking for available updates in " +
1483                                                    stopWatch.getTime() + " ms");
1484                            }
1485                    }
1486            }
1487    
1488    }