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