001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.PropertiesUtil;
038    import com.liferay.portal.kernel.util.PropsKeys;
039    import com.liferay.portal.kernel.util.ReleaseInfo;
040    import com.liferay.portal.kernel.util.StringBundler;
041    import com.liferay.portal.kernel.util.StringPool;
042    import com.liferay.portal.kernel.util.StringUtil;
043    import com.liferay.portal.kernel.util.Time;
044    import com.liferay.portal.kernel.util.Validator;
045    import com.liferay.portal.kernel.xml.Attribute;
046    import com.liferay.portal.kernel.xml.Document;
047    import com.liferay.portal.kernel.xml.DocumentException;
048    import com.liferay.portal.kernel.xml.Element;
049    import com.liferay.portal.kernel.xml.SAXReaderUtil;
050    import com.liferay.portal.model.CompanyConstants;
051    import com.liferay.portal.model.Plugin;
052    import com.liferay.portal.util.HttpImpl;
053    import com.liferay.portal.util.PrefsPropsUtil;
054    import com.liferay.portal.util.PropsValues;
055    
056    import java.io.IOException;
057    import java.io.InputStream;
058    import java.io.Serializable;
059    
060    import java.net.MalformedURLException;
061    
062    import java.text.DateFormat;
063    
064    import java.util.ArrayList;
065    import java.util.Arrays;
066    import java.util.Collection;
067    import java.util.Date;
068    import java.util.HashMap;
069    import java.util.List;
070    import java.util.Locale;
071    import java.util.Map;
072    import java.util.Properties;
073    import java.util.Set;
074    import java.util.TreeSet;
075    import java.util.jar.Attributes;
076    import java.util.jar.Manifest;
077    
078    import javax.servlet.ServletContext;
079    import javax.servlet.http.HttpServletResponse;
080    
081    import org.apache.commons.httpclient.HostConfiguration;
082    import org.apache.commons.httpclient.HttpClient;
083    import org.apache.commons.httpclient.methods.GetMethod;
084    import org.apache.commons.lang.time.StopWatch;
085    
086    /**
087     * @author Jorge Ferrer
088     * @author Brian Wing Shun Chan
089     * @author Sandeep Soni
090     */
091    public class PluginPackageUtil {
092    
093            public static final String REPOSITORY_XML_FILENAME_EXTENSION =
094                    "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[] getStatusAndInstalledVersion(
159                    PluginPackage pluginPackage) {
160    
161                    return _instance._getStatusAndInstalledVersion(pluginPackage);
162            }
163    
164            public static String[] getRepositoryURLs() throws SystemException {
165                    return _instance._getRepositoryURLs();
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 =
325                                            _getRepository(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 =
356                                    _getRepository(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 =
423                                            _getRepository(repositoryURL);
424    
425                                    return repository.findPluginByArtifactURL(url);
426                            }
427                            catch (PluginPackageException pe) {
428                                    _log.error("Unable to load repository " + repositoryURL, pe);
429                            }
430                    }
431    
432                    return null;
433            }
434    
435            private RemotePluginPackageRepository _getRepository(
436                            String repositoryURL)
437                    throws PortalException, SystemException {
438    
439                    RemotePluginPackageRepository repository = _repositoryCache.get(
440                            repositoryURL);
441    
442                    if (repository != null) {
443                            return repository;
444                    }
445    
446                    return _loadRepository(repositoryURL);
447            }
448    
449            private String[] _getRepositoryURLs() throws PluginPackageException {
450                    try {
451                            String[] trusted = PrefsPropsUtil.getStringArray(
452                                    PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
453                                    PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
454                            String[] untrusted = PrefsPropsUtil.getStringArray(
455                                    PropsKeys.PLUGIN_REPOSITORIES_UNTRUSTED, StringPool.NEW_LINE,
456                                    PropsValues.PLUGIN_REPOSITORIES_UNTRUSTED);
457    
458                            return ArrayUtil.append(trusted, untrusted);
459                    }
460                    catch (Exception e) {
461                            throw new PluginPackageException(
462                                    "Unable to read repository list", e);
463                    }
464            }
465    
466            private String[] _getStatusAndInstalledVersion(
467                    PluginPackage pluginPackage) {
468    
469                    PluginPackage installedPluginPackage =
470                            _installedPluginPackages.getLatestPluginPackage(
471                                    pluginPackage.getGroupId(), pluginPackage.getArtifactId());
472    
473                    String status = null;
474                    String installedVersion = null;
475    
476                    if (installedPluginPackage == null) {
477                            status = PluginPackageImpl.STATUS_NOT_INSTALLED;
478                    }
479                    else {
480                            installedVersion = installedPluginPackage.getVersion();
481    
482                            if (installedPluginPackage.isLaterVersionThan(pluginPackage)) {
483                                    status = PluginPackageImpl.STATUS_NEWER_VERSION_INSTALLED;
484                            }
485                            else if (installedPluginPackage.isPreviousVersionThan(
486                                                    pluginPackage)) {
487    
488                                    status = PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED;
489                            }
490                            else {
491                                    status = PluginPackageImpl.STATUS_SAME_VERSION_INSTALLED;
492                            }
493                    }
494    
495                    return new String[] {status, installedVersion};
496            }
497    
498            private String[] _getSupportedTypes() {
499                    return PropsValues.PLUGIN_TYPES;
500            }
501    
502            private void _indexPluginPackage(PluginPackage pluginPackage)
503                    throws PortalException {
504    
505                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
506    
507                    indexer.reindex(pluginPackage);
508            }
509    
510            private boolean _isCurrentVersionSupported(List<String> versions) {
511                    Version currentVersion = Version.getInstance(ReleaseInfo.getVersion());
512    
513                    for (String version : versions) {
514                            Version supportedVersion = Version.getInstance(version);
515    
516                            if (supportedVersion.includes(currentVersion)) {
517                                    return true;
518                            }
519                    }
520    
521                    return false;
522            }
523    
524            private boolean _isIgnored(PluginPackage pluginPackage)
525                    throws SystemException {
526    
527                    String packageId = pluginPackage.getPackageId();
528    
529                    String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
530                            PropsKeys.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
531                            StringPool.NEW_LINE,
532                            PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
533    
534                    for (int i = 0; i < pluginPackagesIgnored.length; i++) {
535                            String curPluginPackagesIgnored = pluginPackagesIgnored[i];
536    
537                            if (curPluginPackagesIgnored.endsWith(StringPool.STAR)) {
538                                    String prefix = curPluginPackagesIgnored.substring(
539                                            0, curPluginPackagesIgnored.length() - 2);
540    
541                                    if (packageId.startsWith(prefix)) {
542                                            return true;
543                                    }
544                            }
545                            else {
546                                    if (packageId.equals(curPluginPackagesIgnored)) {
547                                            return true;
548                                    }
549                            }
550                    }
551    
552                    return false;
553            }
554    
555            private boolean _isInstallationInProcess(String context) {
556                    if (_installedPluginPackages.getInstallingPluginPackage(
557                                    context) != null) {
558    
559                            return true;
560                    }
561                    else {
562                            return false;
563                    }
564            }
565    
566            private boolean _isInstalled(String context) {
567                    PluginPackage pluginPackage = _installedPluginPackages.getPluginPackage(
568                            context);
569    
570                    if (pluginPackage != null) {
571                            return true;
572                    }
573                    else {
574                            return false;
575                    }
576            }
577    
578            private boolean _isTrusted(String repositoryURL)
579                    throws PluginPackageException {
580    
581                    try {
582                            String[] trusted = PrefsPropsUtil.getStringArray(
583                                    PropsKeys.PLUGIN_REPOSITORIES_TRUSTED, StringPool.NEW_LINE,
584                                    PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
585    
586                            if (ArrayUtil.contains(trusted, repositoryURL)) {
587                                    return true;
588                            }
589                            else {
590                                    return false;
591                            }
592                    }
593                    catch (Exception e) {
594                            throw new PluginPackageException(
595                                    "Unable to read repository list", e);
596                    }
597            }
598    
599            private boolean _isUpdateAvailable() throws SystemException {
600                    if (!PrefsPropsUtil.getBoolean(
601                                    PropsKeys.PLUGIN_NOTIFICATIONS_ENABLED,
602                                    PropsValues.PLUGIN_NOTIFICATIONS_ENABLED)) {
603    
604                            return false;
605                    }
606    
607                    if (_updateAvailable != null) {
608                            return _updateAvailable.booleanValue();
609                    }
610                    else if (!_settingUpdateAvailable) {
611                            _settingUpdateAvailable = true;
612    
613                            Thread indexerThread = new Thread(
614                                    new UpdateAvailableRunner(), PluginPackageUtil.class.getName());
615    
616                            indexerThread.setPriority(Thread.MIN_PRIORITY);
617    
618                            indexerThread.start();
619                    }
620    
621                    return false;
622            }
623    
624            private RemotePluginPackageRepository _loadRepository(String repositoryURL)
625                    throws PluginPackageException, PortalException {
626    
627                    RemotePluginPackageRepository repository = null;
628    
629                    StringBundler sb = new StringBundler(8);
630    
631                    if (!repositoryURL.startsWith(Http.HTTP_WITH_SLASH) &&
632                            !repositoryURL.startsWith(Http.HTTPS_WITH_SLASH)) {
633    
634                            sb.append(Http.HTTP_WITH_SLASH);
635                    }
636    
637                    sb.append(repositoryURL);
638                    sb.append(StringPool.SLASH);
639                    sb.append(REPOSITORY_XML_FILENAME_PREFIX);
640                    sb.append(StringPool.DASH);
641                    sb.append(ReleaseInfo.getVersion());
642                    sb.append(StringPool.PERIOD);
643                    sb.append(REPOSITORY_XML_FILENAME_EXTENSION);
644    
645                    String pluginsXmlURL = sb.toString();
646    
647                    try {
648                            HttpImpl httpImpl = (HttpImpl)HttpUtil.getHttp();
649    
650                            HostConfiguration hostConfiguration = httpImpl.getHostConfiguration(
651                                    pluginsXmlURL);
652    
653                            HttpClient httpClient = httpImpl.getClient(hostConfiguration);
654    
655                            httpImpl.proxifyState(httpClient.getState(), hostConfiguration);
656    
657                            GetMethod getFileMethod = new GetMethod(pluginsXmlURL);
658    
659                            byte[] bytes = null;
660    
661                            try {
662                                    int responseCode = httpClient.executeMethod(
663                                            hostConfiguration, getFileMethod);
664    
665                                    if (responseCode != HttpServletResponse.SC_OK) {
666                                            if (_log.isDebugEnabled()) {
667                                                    _log.debug(
668                                                            "A repository for version " +
669                                                                    ReleaseInfo.getVersion() + " was not found. " +
670                                                                            "Checking general repository");
671                                            }
672    
673                                            sb.setIndex(0);
674    
675                                            sb.append(repositoryURL);
676                                            sb.append(StringPool.SLASH);
677                                            sb.append(REPOSITORY_XML_FILENAME_PREFIX);
678                                            sb.append(StringPool.PERIOD);
679                                            sb.append(REPOSITORY_XML_FILENAME_EXTENSION);
680    
681                                            pluginsXmlURL = sb.toString();
682    
683                                            getFileMethod.releaseConnection();
684    
685                                            getFileMethod = new GetMethod(pluginsXmlURL);
686    
687                                            responseCode = httpClient.executeMethod(
688                                                    hostConfiguration, getFileMethod);
689    
690                                            if (responseCode != HttpServletResponse.SC_OK) {
691                                                    throw new PluginPackageException(
692                                                            "Unable to download file " + pluginsXmlURL +
693                                                                    " because of response code " + responseCode);
694                                            }
695                                    }
696    
697                                    bytes = getFileMethod.getResponseBody();
698                            }
699                            finally {
700                                    getFileMethod.releaseConnection();
701                            }
702    
703                            if ((bytes != null) && (bytes.length > 0)) {
704                                    repository = _parseRepositoryXml(
705                                            new String(bytes), repositoryURL);
706    
707                                    _repositoryCache.put(repositoryURL, repository);
708                                    _availableTagsCache.addAll(repository.getTags());
709                                    _lastUpdateDate = new Date();
710                                    _updateAvailable = null;
711    
712                                    return repository;
713                            }
714                            else {
715                                    _lastUpdateDate = new Date();
716    
717                                    throw new PluginPackageException("Download returned 0 bytes");
718                            }
719                    }
720                    catch (MalformedURLException mue) {
721                            _repositoryCache.remove(repositoryURL);
722    
723                            throw new PluginPackageException(
724                                    "Invalid URL " + pluginsXmlURL, mue);
725                    }
726                    catch (IOException ioe) {
727                            _repositoryCache.remove(repositoryURL);
728    
729                            throw new PluginPackageException(
730                                    "Unable to communicate with repository " + repositoryURL, ioe);
731                    }
732                    catch (DocumentException de) {
733                            _repositoryCache.remove(repositoryURL);
734    
735                            throw new PluginPackageException(
736                                    "Unable to parse plugin list for repository " + repositoryURL,
737                                    de);
738                    }
739            }
740    
741            private RemotePluginPackageRepository _parseRepositoryXml(
742                            String xml, String repositoryURL)
743                    throws DocumentException, PortalException {
744    
745                    List<String> supportedPluginTypes = Arrays.asList(getSupportedTypes());
746    
747                    if (_log.isDebugEnabled()) {
748                            _log.debug(
749                                    "Loading plugin repository " + repositoryURL + ":\n" + xml);
750                    }
751    
752                    RemotePluginPackageRepository pluginPackageRepository =
753                            new RemotePluginPackageRepository(repositoryURL);
754    
755                    if (xml == null) {
756                            return pluginPackageRepository;
757                    }
758    
759                    Document document = SAXReaderUtil.read(xml);
760    
761                    Element rootElement = document.getRootElement();
762    
763                    Properties settings = _readProperties(
764                            rootElement.element("settings"), "setting");
765    
766                    pluginPackageRepository.setSettings(settings);
767    
768                    List<Element> pluginPackageElements = rootElement.elements(
769                            "plugin-package");
770    
771                    for (Element pluginPackageElement : pluginPackageElements) {
772                            PluginPackage pluginPackage = _readPluginPackageXml(
773                                    pluginPackageElement);
774    
775                            if (!_isCurrentVersionSupported(
776                                            pluginPackage.getLiferayVersions())) {
777    
778                                    continue;
779                            }
780    
781                            boolean containsSupportedTypes = false;
782    
783                            List<String> pluginTypes = pluginPackage.getTypes();
784    
785                            for (String pluginType : pluginTypes) {
786                                    if (supportedPluginTypes.contains(pluginType)) {
787                                            containsSupportedTypes = true;
788    
789                                            break;
790                                    }
791                            }
792    
793                            if (!containsSupportedTypes) {
794                                    continue;
795                            }
796    
797                            pluginPackage.setRepository(pluginPackageRepository);
798    
799                            pluginPackageRepository.addPluginPackage(pluginPackage);
800    
801                            _indexPluginPackage(pluginPackage);
802                    }
803    
804                    return pluginPackageRepository;
805            }
806    
807            private Date _readDate(String text) {
808                    if (Validator.isNotNull(text)) {
809                            DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
810                                    Time.RFC822_FORMAT, Locale.US);
811    
812                            try {
813                                    return dateFormat.parse(text);
814                            }
815                            catch (Exception e) {
816                                    if (_log.isWarnEnabled()) {
817                                            _log.warn("Unable to parse date " + text);
818                                    }
819                            }
820                    }
821    
822                    return new Date();
823            }
824    
825            private String _readHtml(String text) {
826                    return GetterUtil.getString(text);
827            }
828    
829            private List<License> _readLicenseList(Element parentElement, String name) {
830                    List<License> licenses = new ArrayList<License>();
831    
832                    for (Element licenseElement : parentElement.elements(name)) {
833                            License license = new License();
834    
835                            license.setName(licenseElement.getText());
836    
837                            Attribute osiApproved = licenseElement.attribute("osi-approved");
838    
839                            if (osiApproved != null) {
840                                    license.setOsiApproved(
841                                            GetterUtil.getBoolean(osiApproved.getText()));
842                            }
843    
844                            Attribute url = licenseElement.attribute("url");
845    
846                            if (url != null) {
847                                    license.setUrl(url.getText());
848                            }
849    
850                            licenses.add(license);
851                    }
852    
853                    return licenses;
854            }
855    
856            private List<String> _readList(Element parentElement, String name) {
857                    List<String> list = new ArrayList<String>();
858    
859                    if (parentElement == null) {
860                            return list;
861                    }
862    
863                    for (Element element : parentElement.elements(name)) {
864                            String text = element.getText().trim().toLowerCase();
865    
866                            list.add(text);
867                    }
868    
869                    return list;
870            }
871    
872            private PluginPackage _readPluginPackageProperties(
873                    String displayName, Properties properties) {
874    
875                    int pos = displayName.indexOf("-portlet");
876    
877                    String pluginType = Plugin.TYPE_PORTLET;
878    
879                    if (pos == -1) {
880                            pos = displayName.indexOf("-ext");
881    
882                            pluginType = Plugin.TYPE_EXT;
883                    }
884    
885                    if (pos == -1) {
886                            pos = displayName.indexOf("-hook");
887    
888                            pluginType = Plugin.TYPE_HOOK;
889                    }
890    
891                    if (pos == -1) {
892                            pos = displayName.indexOf("-layouttpl");
893    
894                            pluginType = Plugin.TYPE_LAYOUT_TEMPLATE;
895                    }
896    
897                    if (pos == -1) {
898                            pos = displayName.indexOf("-theme");
899    
900                            pluginType = Plugin.TYPE_THEME;
901                    }
902    
903                    if (pos == -1) {
904                            pos = displayName.indexOf("-web");
905    
906                            pluginType = Plugin.TYPE_WEB;
907                    }
908    
909                    if (pos == -1) {
910                            return null;
911                    }
912    
913                    String displayPrefix = displayName.substring(0, pos);
914    
915                    String moduleGroupId = GetterUtil.getString(
916                            properties.getProperty("module-group-id"));
917                    String moduleArtifactId = displayPrefix + "-" + pluginType;
918    
919                    String moduleVersion = null;
920    
921                    int moduleVersionPos = pos + pluginType.length() + 2;
922    
923                    if (displayName.length() > moduleVersionPos) {
924                            moduleVersion = displayName.substring(moduleVersionPos);
925                    }
926                    else {
927                            moduleVersion = ReleaseInfo.getVersion();
928                    }
929    
930                    String moduleId =
931                            moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
932                                    "/war";
933    
934                    String pluginName = GetterUtil.getString(
935                            properties.getProperty("name"));
936    
937                    String deploymentContext = GetterUtil.getString(
938                            properties.getProperty("recommended-deployment-context"),
939                            moduleArtifactId);
940    
941                    String author = GetterUtil.getString(properties.getProperty("author"));
942    
943                    List<String> types = new ArrayList<String>();
944    
945                    types.add(pluginType);
946    
947                    List<License> licenses = new ArrayList<License>();
948    
949                    String[] licensesArray = StringUtil.split(
950                            properties.getProperty("licenses"));
951    
952                    for (int i = 0; i < licensesArray.length; i++) {
953                            License license = new License();
954    
955                            license.setName(licensesArray[i].trim());
956                            license.setOsiApproved(true);
957    
958                            licenses.add(license);
959                    }
960    
961                    List<String> liferayVersions = new ArrayList<String>();
962    
963                    String[] liferayVersionsArray = StringUtil.split(
964                            properties.getProperty("liferay-versions"));
965    
966                    for (String liferayVersion : liferayVersionsArray) {
967                            liferayVersions.add(liferayVersion.trim());
968                    }
969    
970                    if (liferayVersions.size() == 0) {
971                            liferayVersions.add(ReleaseInfo.getVersion() + "+");
972                    }
973    
974                    List<String> tags = new ArrayList<String>();
975    
976                    String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
977    
978                    for (String tag : tagsArray) {
979                            tags.add(tag.trim());
980                    }
981    
982                    String shortDescription = GetterUtil.getString(
983                            properties.getProperty("short-description"));
984                    String longDescription = GetterUtil.getString(
985                            properties.getProperty("long-description"));
986                    String changeLog = GetterUtil.getString(
987                            properties.getProperty("change-log"));
988                    String pageURL = GetterUtil.getString(
989                            properties.getProperty("page-url"));
990                    String downloadURL = GetterUtil.getString(
991                            properties.getProperty("download-url"));
992    
993                    PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
994    
995                    pluginPackage.setName(pluginName);
996                    pluginPackage.setRecommendedDeploymentContext(deploymentContext);
997                    //pluginPackage.setModifiedDate(null);
998                    pluginPackage.setAuthor(author);
999                    pluginPackage.setTypes(types);
1000                    pluginPackage.setLicenses(licenses);
1001                    pluginPackage.setLiferayVersions(liferayVersions);
1002                    pluginPackage.setTags(tags);
1003                    pluginPackage.setShortDescription(shortDescription);
1004                    pluginPackage.setLongDescription(longDescription);
1005                    pluginPackage.setChangeLog(changeLog);
1006                    //pluginPackage.setScreenshots(null);
1007                    pluginPackage.setPageURL(pageURL);
1008                    pluginPackage.setDownloadURL(downloadURL);
1009                    //pluginPackage.setDeploymentSettings(null);
1010    
1011                    return pluginPackage;
1012            }
1013    
1014            private PluginPackage _readPluginPackageServletManifest(
1015                            ServletContext servletContext)
1016                    throws IOException {
1017                            Attributes attributes = null;
1018    
1019                    String servletContextName = servletContext.getServletContextName();
1020    
1021                    InputStream inputStream = servletContext.getResourceAsStream(
1022                            "/META-INF/MANIFEST.MF");
1023    
1024                    if (inputStream != null) {
1025                            Manifest manifest = new Manifest(inputStream);
1026    
1027                            attributes = manifest.getMainAttributes();
1028                    }
1029                    else {
1030                            attributes = new Attributes();
1031                    }
1032    
1033                    String artifactGroupId = attributes.getValue(
1034                            "Implementation-Vendor-Id");
1035    
1036                    if (Validator.isNull(artifactGroupId)) {
1037                            artifactGroupId = attributes.getValue("Implementation-Vendor");
1038                    }
1039    
1040                    if (Validator.isNull(artifactGroupId)) {
1041                            artifactGroupId = GetterUtil.getString(
1042                                    attributes.getValue("Bundle-Vendor"), servletContextName);
1043                    }
1044    
1045                    String artifactId = attributes.getValue("Implementation-Title");
1046    
1047                    if (Validator.isNull(artifactId)) {
1048                            artifactId = GetterUtil.getString(
1049                                    attributes.getValue("Bundle-Name"), servletContextName);
1050                    }
1051    
1052                    String version = attributes.getValue("Implementation-Version");
1053    
1054                    if (Validator.isNull(version)) {
1055                            version = GetterUtil.getString(
1056                                    attributes.getValue("Bundle-Version"), Version.UNKNOWN);
1057                    }
1058    
1059                    if (version.equals(Version.UNKNOWN) && _log.isWarnEnabled()) {
1060                            _log.warn(
1061                                    "Plugin package on context " + servletContextName +
1062                                            " cannot be tracked because this WAR does not contain a " +
1063                                                    "liferay-plugin-package.xml file");
1064                    }
1065    
1066                    PluginPackage pluginPackage = new PluginPackageImpl(
1067                            artifactGroupId + StringPool.SLASH + artifactId + StringPool.SLASH +
1068                                    version + StringPool.SLASH + "war");
1069    
1070                    pluginPackage.setName(artifactId);
1071    
1072                    String shortDescription = attributes.getValue("Bundle-Description");
1073    
1074                    if (Validator.isNotNull(shortDescription)) {
1075                            pluginPackage.setShortDescription(shortDescription);
1076                    }
1077    
1078                    String pageURL = attributes.getValue("Bundle-DocURL");
1079    
1080                    if (Validator.isNotNull(pageURL)) {
1081                            pluginPackage.setPageURL(pageURL);
1082                    }
1083    
1084                    return pluginPackage;
1085            }
1086    
1087            private PluginPackage _readPluginPackageServletContext(
1088                            ServletContext servletContext)
1089                    throws DocumentException, IOException {
1090    
1091                    String servletContextName = servletContext.getServletContextName();
1092    
1093                    String xml = HttpUtil.URLtoString(
1094                            servletContext.getResource("/WEB-INF/liferay-plugin-package.xml"));
1095    
1096                    if (_log.isInfoEnabled()) {
1097                            if (servletContextName == null) {
1098                                    _log.info("Reading plugin package for the root context");
1099                            }
1100                            else {
1101                                    _log.info("Reading plugin package for " + servletContextName);
1102                            }
1103                    }
1104    
1105                    PluginPackage pluginPackage = null;
1106    
1107                    if (xml == null) {
1108                            String propertiesString = HttpUtil.URLtoString(
1109                                    servletContext.getResource(
1110                                            "/WEB-INF/liferay-plugin-package.properties"));
1111    
1112                            if (propertiesString != null) {
1113                                    if (_log.isDebugEnabled()) {
1114                                            _log.debug(
1115                                                    "Reading plugin package from " +
1116                                                            "liferay-plugin-package.properties");
1117                                    }
1118    
1119                                    Properties properties = PropertiesUtil.load(propertiesString);
1120    
1121                                    String displayName = servletContextName;
1122    
1123                                    if (displayName.startsWith(StringPool.SLASH)) {
1124                                            displayName = displayName.substring(1);
1125                                    }
1126    
1127                                    pluginPackage = _readPluginPackageProperties(
1128                                            displayName, properties);
1129                            }
1130    
1131                            if (pluginPackage == null) {
1132                                    if (_log.isDebugEnabled()) {
1133                                            _log.debug("Reading plugin package from MANIFEST.MF");
1134                                    }
1135    
1136                                    pluginPackage =_readPluginPackageServletManifest(
1137                                            servletContext);
1138                            }
1139                    }
1140                    else {
1141                            if (_log.isDebugEnabled()) {
1142                                    _log.debug(
1143                                            "Reading plugin package from liferay-plugin-package.xml");
1144                            }
1145    
1146                            pluginPackage = _readPluginPackageXml(xml);
1147                    }
1148    
1149                    pluginPackage.setContext(servletContextName);
1150    
1151                    return pluginPackage;
1152            }
1153    
1154            private PluginPackage _readPluginPackageXml(Element pluginPackageElement) {
1155                    String name = pluginPackageElement.elementText("name");
1156    
1157                    if (_log.isDebugEnabled()) {
1158                            _log.debug("Reading pluginPackage definition " + name);
1159                    }
1160    
1161                    PluginPackage pluginPackage = new PluginPackageImpl(
1162                            GetterUtil.getString(
1163                                    pluginPackageElement.elementText("module-id")));
1164    
1165                    List<String> liferayVersions = _readList(
1166                            pluginPackageElement.element("liferay-versions"),
1167                            "liferay-version");
1168    
1169                    List<String> types = _readList(
1170                            pluginPackageElement.element("types"), "type");
1171    
1172                    pluginPackage.setName(_readText(name));
1173                    pluginPackage.setRecommendedDeploymentContext(
1174                            _readText(
1175                                    pluginPackageElement.elementText(
1176                                            "recommended-deployment-context")));
1177                    pluginPackage.setModifiedDate(
1178                            _readDate(pluginPackageElement.elementText("modified-date")));
1179                    pluginPackage.setAuthor(
1180                            _readText(pluginPackageElement.elementText("author")));
1181                    pluginPackage.setTypes(types);
1182                    pluginPackage.setLicenses(
1183                            _readLicenseList(
1184                                    pluginPackageElement.element("licenses"), "license"));
1185                    pluginPackage.setLiferayVersions(liferayVersions);
1186                    pluginPackage.setTags(
1187                            _readList(pluginPackageElement.element("tags"), "tag"));
1188                    pluginPackage.setShortDescription(
1189                            _readText(pluginPackageElement.elementText("short-description")));
1190                    pluginPackage.setLongDescription(
1191                            _readHtml(pluginPackageElement.elementText("long-description")));
1192                    pluginPackage.setChangeLog(
1193                            _readHtml(pluginPackageElement.elementText("change-log")));
1194                    pluginPackage.setScreenshots(
1195                            _readScreenshots(pluginPackageElement.element("screenshots")));
1196                    pluginPackage.setPageURL(
1197                            _readText(pluginPackageElement.elementText("page-url")));
1198                    pluginPackage.setDownloadURL(
1199                            _readText(pluginPackageElement.elementText("download-url")));
1200                    pluginPackage.setDeploymentSettings(
1201                            _readProperties(
1202                                    pluginPackageElement.element("deployment-settings"),
1203                                    "setting"));
1204    
1205                    return pluginPackage;
1206            }
1207    
1208            private PluginPackage _readPluginPackageXml(String xml)
1209                    throws DocumentException {
1210    
1211                    Document document = SAXReaderUtil.read(xml);
1212    
1213                    Element rootElement = document.getRootElement();
1214    
1215                    return _readPluginPackageXml(rootElement);
1216            }
1217    
1218            private Properties _readProperties(Element parentElement, String name) {
1219                    Properties properties = new Properties();
1220    
1221                    if (parentElement == null) {
1222                            return properties;
1223                    }
1224    
1225                    for (Element element : parentElement.elements(name)) {
1226                            properties.setProperty(
1227                                    element.attributeValue("name"),
1228                                    element.attributeValue("value"));
1229                    }
1230    
1231                    return properties;
1232            }
1233    
1234            private List<Screenshot> _readScreenshots(Element parentElement) {
1235                    List<Screenshot> screenshots = new ArrayList<Screenshot>();
1236    
1237                    if (parentElement == null) {
1238                            return screenshots;
1239                    }
1240    
1241                    for (Element screenshotElement : parentElement.elements("screenshot")) {
1242                            Screenshot screenshot = new Screenshot();
1243    
1244                            screenshot.setThumbnailURL(
1245                                    screenshotElement.elementText("thumbnail-url"));
1246                            screenshot.setLargeImageURL(
1247                                    screenshotElement.elementText("large-image-url"));
1248    
1249                            screenshots.add(screenshot);
1250                    }
1251    
1252                    return screenshots;
1253            }
1254    
1255            private String _readText(String text) {
1256                    return HtmlUtil.extractText(GetterUtil.getString(text));
1257            }
1258    
1259            private void _refreshUpdatesAvailableCache() {
1260                    _updateAvailable = null;
1261            }
1262    
1263            private void _registerInstalledPluginPackage(PluginPackage pluginPackage)
1264                    throws PortalException {
1265    
1266                    _installedPluginPackages.addPluginPackage(pluginPackage);
1267    
1268                    _updateAvailable = null;
1269    
1270                    _indexPluginPackage(pluginPackage);
1271            }
1272    
1273            private void _registerPluginPackageInstallation(String preliminaryContext) {
1274                    _installedPluginPackages.registerPluginPackageInstallation(
1275                            preliminaryContext);
1276            }
1277    
1278            private RepositoryReport _reloadRepositories()
1279                    throws PortalException, SystemException {
1280    
1281                    if (_log.isInfoEnabled()) {
1282                            _log.info("Reloading repositories");
1283                    }
1284    
1285                    RepositoryReport repositoryReport = new RepositoryReport();
1286    
1287                    String[] repositoryURLs = _getRepositoryURLs();
1288    
1289                    for (int i = 0; i < repositoryURLs.length; i++) {
1290                            String repositoryURL = repositoryURLs[i];
1291    
1292                            try {
1293                                    _loadRepository(repositoryURL);
1294    
1295                                    repositoryReport.addSuccess(repositoryURL);
1296                            }
1297                            catch (PluginPackageException pe) {
1298                                    repositoryReport.addError(repositoryURL, pe);
1299    
1300                                    _log.error(
1301                                            "Unable to load repository " + repositoryURL + " " +
1302                                                    pe.toString());
1303                            }
1304    
1305                    }
1306    
1307                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1308    
1309                    indexer.reindex(new String[0]);
1310    
1311                    return repositoryReport;
1312            }
1313    
1314            private Hits _search(
1315                            String keywords, String type, String tag, String license,
1316                            String repositoryURL, String status, int start, int end)
1317                    throws PortalException, SystemException {
1318    
1319                    _checkRepositories(repositoryURL);
1320    
1321                    Map<String, Serializable> attributes =
1322                            new HashMap<String, Serializable>();
1323    
1324                    attributes.put("license", license);
1325                    attributes.put("repositoryURL", repositoryURL);
1326                    attributes.put("status", status);
1327                    attributes.put("tag", tag);
1328                    attributes.put("type", type);
1329    
1330                    SearchContext searchContext = new SearchContext();
1331    
1332                    searchContext.setAttributes(attributes);
1333                    searchContext.setCompanyId(CompanyConstants.SYSTEM);
1334                    searchContext.setEnd(end);
1335                    searchContext.setKeywords(keywords);
1336    
1337                    QueryConfig queryConfig = new QueryConfig();
1338    
1339                    queryConfig.setHighlightEnabled(false);
1340                    queryConfig.setScoreEnabled(false);
1341    
1342                    searchContext.setQueryConfig(queryConfig);
1343    
1344                    searchContext.setStart(start);
1345    
1346                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1347    
1348                    return indexer.search(searchContext);
1349            }
1350    
1351            private void _unregisterInstalledPluginPackage(
1352                            PluginPackage pluginPackage)
1353                    throws PortalException, SystemException {
1354    
1355                    _installedPluginPackages.removePluginPackage(pluginPackage);
1356    
1357                    try {
1358                            List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1359                                    pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1360    
1361                            for (PluginPackage availablePackage : pluginPackages) {
1362                                    _indexPluginPackage(availablePackage);
1363                            }
1364                    }
1365                    catch (PluginPackageException ppe) {
1366                            if (_log.isWarnEnabled()) {
1367                                    _log.warn(
1368                                            "Unable to reindex unistalled package " +
1369                                                    pluginPackage.getContext() + ": " + ppe.getMessage());
1370                            }
1371                    }
1372            }
1373    
1374            private void _updateInstallingPluginPackage(
1375                    String preliminaryContext, PluginPackage pluginPackage) {
1376    
1377                    _installedPluginPackages.unregisterPluginPackageInstallation(
1378                            preliminaryContext);
1379                    _installedPluginPackages.registerPluginPackageInstallation(
1380                            pluginPackage);
1381            }
1382    
1383            private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1384    
1385            private static PluginPackageUtil _instance = new PluginPackageUtil();
1386    
1387            private Set<String> _availableTagsCache;
1388            private LocalPluginPackageRepository _installedPluginPackages;
1389            private Date _lastUpdateDate;
1390            private Map<String, RemotePluginPackageRepository> _repositoryCache;
1391            private boolean _settingUpdateAvailable;
1392            private Boolean _updateAvailable;
1393    
1394            private class UpdateAvailableRunner implements Runnable {
1395    
1396                    public void run() {
1397                            try {
1398                                    setUpdateAvailable();
1399                            }
1400                            catch (Exception e) {
1401                                    if (_log.isWarnEnabled()) {
1402                                            _log.warn(e.getMessage());
1403                                    }
1404                            }
1405                    }
1406    
1407                    protected void setUpdateAvailable() throws Exception {
1408                            StopWatch stopWatch = null;
1409    
1410                            if (_log.isInfoEnabled()) {
1411                                    _log.info("Checking for available updates");
1412    
1413                                    stopWatch = new StopWatch();
1414    
1415                                    stopWatch.start();
1416                            }
1417    
1418                            for (PluginPackage pluginPackage :
1419                                            _installedPluginPackages.getPluginPackages()) {
1420    
1421                                    PluginPackage availablePluginPackage = null;
1422    
1423                                    if (_isIgnored(pluginPackage)) {
1424                                            continue;
1425                                    }
1426    
1427                                    availablePluginPackage =
1428                                            PluginPackageUtil.getLatestAvailablePluginPackage(
1429                                                    pluginPackage.getGroupId(),
1430                                                    pluginPackage.getArtifactId());
1431    
1432                                    if (availablePluginPackage == null) {
1433                                            continue;
1434                                    }
1435    
1436                                    Version availablePluginPackageVersion = Version.getInstance(
1437                                            availablePluginPackage.getVersion());
1438    
1439                                    if (availablePluginPackageVersion.isLaterVersionThan(
1440                                                    pluginPackage.getVersion())) {
1441    
1442                                            _updateAvailable = Boolean.TRUE;
1443    
1444                                            break;
1445                                    }
1446                            }
1447    
1448                            if (_updateAvailable == null) {
1449                                    _updateAvailable = Boolean.FALSE;
1450                            }
1451    
1452                            _settingUpdateAvailable = false;
1453    
1454                            if (_log.isInfoEnabled()) {
1455                                    _log.info(
1456                                            "Finished checking for available updates in " +
1457                                                    stopWatch.getTime() + " ms");
1458                            }
1459                    }
1460            }
1461    
1462    }