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