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 (ArrayUtil.isNotEmpty(bytes)) {
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    
695                            _lastUpdateDate = new Date();
696    
697                            throw new PluginPackageException("Download returned 0 bytes");
698                    }
699                    catch (MalformedURLException murle) {
700                            _repositoryCache.remove(repositoryURL);
701    
702                            throw new PluginPackageException(
703                                    "Invalid URL " + pluginsXmlURL, murle);
704                    }
705                    catch (IOException ioe) {
706                            _repositoryCache.remove(repositoryURL);
707    
708                            throw new PluginPackageException(
709                                    "Unable to communicate with repository " + repositoryURL, ioe);
710                    }
711                    catch (DocumentException de) {
712                            _repositoryCache.remove(repositoryURL);
713    
714                            throw new PluginPackageException(
715                                    "Unable to parse plugin list for repository " + repositoryURL,
716                                    de);
717                    }
718            }
719    
720            private RemotePluginPackageRepository _parseRepositoryXml(
721                            String xml, String repositoryURL)
722                    throws DocumentException, PortalException {
723    
724                    List<String> supportedPluginTypes = Arrays.asList(getSupportedTypes());
725    
726                    if (_log.isDebugEnabled()) {
727                            _log.debug(
728                                    "Loading plugin repository " + repositoryURL + ":\n" + xml);
729                    }
730    
731                    RemotePluginPackageRepository pluginPackageRepository =
732                            new RemotePluginPackageRepository(repositoryURL);
733    
734                    if (xml == null) {
735                            return pluginPackageRepository;
736                    }
737    
738                    Document document = SAXReaderUtil.read(xml);
739    
740                    Element rootElement = document.getRootElement();
741    
742                    Properties settings = _readProperties(
743                            rootElement.element("settings"), "setting");
744    
745                    pluginPackageRepository.setSettings(settings);
746    
747                    List<Element> pluginPackageElements = rootElement.elements(
748                            "plugin-package");
749    
750                    for (Element pluginPackageElement : pluginPackageElements) {
751                            PluginPackage pluginPackage = _readPluginPackageXml(
752                                    pluginPackageElement);
753    
754                            if (!_isCurrentVersionSupported(
755                                            pluginPackage.getLiferayVersions())) {
756    
757                                    continue;
758                            }
759    
760                            boolean containsSupportedTypes = false;
761    
762                            List<String> pluginTypes = pluginPackage.getTypes();
763    
764                            for (String pluginType : pluginTypes) {
765                                    if (supportedPluginTypes.contains(pluginType)) {
766                                            containsSupportedTypes = true;
767    
768                                            break;
769                                    }
770                            }
771    
772                            if (!containsSupportedTypes) {
773                                    continue;
774                            }
775    
776                            pluginPackage.setRepository(pluginPackageRepository);
777    
778                            pluginPackageRepository.addPluginPackage(pluginPackage);
779    
780                            _indexPluginPackage(pluginPackage);
781                    }
782    
783                    return pluginPackageRepository;
784            }
785    
786            private Date _readDate(String text) {
787                    if (Validator.isNotNull(text)) {
788                            DateFormat dateFormat = DateFormatFactoryUtil.getSimpleDateFormat(
789                                    Time.RFC822_FORMAT, LocaleUtil.US);
790    
791                            try {
792                                    return dateFormat.parse(text);
793                            }
794                            catch (Exception e) {
795                                    if (_log.isWarnEnabled()) {
796                                            _log.warn("Unable to parse date " + text);
797                                    }
798                            }
799                    }
800    
801                    return new Date();
802            }
803    
804            private String _readHtml(String text) {
805                    return GetterUtil.getString(text);
806            }
807    
808            private List<License> _readLicenseList(Element parentElement, String name) {
809                    List<License> licenses = new ArrayList<License>();
810    
811                    for (Element licenseElement : parentElement.elements(name)) {
812                            License license = new License();
813    
814                            license.setName(licenseElement.getText());
815    
816                            Attribute osiApproved = licenseElement.attribute("osi-approved");
817    
818                            if (osiApproved != null) {
819                                    license.setOsiApproved(
820                                            GetterUtil.getBoolean(osiApproved.getText()));
821                            }
822    
823                            Attribute url = licenseElement.attribute("url");
824    
825                            if (url != null) {
826                                    license.setUrl(url.getText());
827                            }
828    
829                            licenses.add(license);
830                    }
831    
832                    return licenses;
833            }
834    
835            private List<String> _readList(Element parentElement, String name) {
836                    List<String> list = new ArrayList<String>();
837    
838                    if (parentElement == null) {
839                            return list;
840                    }
841    
842                    for (Element element : parentElement.elements(name)) {
843                            String text = StringUtil.toLowerCase(element.getText().trim());
844    
845                            list.add(text);
846                    }
847    
848                    return list;
849            }
850    
851            private PluginPackage _readPluginPackageProperties(
852                    String displayName, Properties properties) {
853    
854                    int pos = displayName.indexOf("-portlet");
855    
856                    String pluginType = Plugin.TYPE_PORTLET;
857    
858                    if (pos == -1) {
859                            pos = displayName.indexOf("-ext");
860    
861                            pluginType = Plugin.TYPE_EXT;
862                    }
863    
864                    if (pos == -1) {
865                            pos = displayName.indexOf("-hook");
866    
867                            pluginType = Plugin.TYPE_HOOK;
868                    }
869    
870                    if (pos == -1) {
871                            pos = displayName.indexOf("-layouttpl");
872    
873                            pluginType = Plugin.TYPE_LAYOUT_TEMPLATE;
874                    }
875    
876                    if (pos == -1) {
877                            pos = displayName.indexOf("-theme");
878    
879                            pluginType = Plugin.TYPE_THEME;
880                    }
881    
882                    if (pos == -1) {
883                            pos = displayName.indexOf("-web");
884    
885                            pluginType = Plugin.TYPE_WEB;
886                    }
887    
888                    if (pos == -1) {
889                            return null;
890                    }
891    
892                    String displayPrefix = displayName.substring(0, pos);
893    
894                    String moduleGroupId = GetterUtil.getString(
895                            properties.getProperty("module-group-id"));
896                    String moduleArtifactId = displayPrefix + "-" + pluginType;
897    
898                    String moduleVersion = GetterUtil.getString(
899                            properties.getProperty("module-version"));
900    
901                    if (Validator.isNull(moduleVersion)) {
902                            int moduleVersionPos = pos + pluginType.length() + 2;
903    
904                            if (displayName.length() > moduleVersionPos) {
905                                    moduleVersion = displayName.substring(moduleVersionPos);
906                            }
907                            else {
908                                    moduleVersion = ReleaseInfo.getVersion();
909                            }
910                    }
911    
912                    String moduleId =
913                            moduleGroupId + "/" + moduleArtifactId + "/" + moduleVersion +
914                                    "/war";
915    
916                    String pluginName = GetterUtil.getString(
917                            properties.getProperty("name"));
918    
919                    String deploymentContext = GetterUtil.getString(
920                            properties.getProperty("recommended-deployment-context"),
921                            moduleArtifactId);
922    
923                    String author = GetterUtil.getString(properties.getProperty("author"));
924    
925                    List<String> types = new ArrayList<String>();
926    
927                    types.add(pluginType);
928    
929                    List<License> licenses = new ArrayList<License>();
930    
931                    String[] licensesArray = StringUtil.split(
932                            properties.getProperty("licenses"));
933    
934                    for (int i = 0; i < licensesArray.length; i++) {
935                            License license = new License();
936    
937                            license.setName(licensesArray[i].trim());
938                            license.setOsiApproved(true);
939    
940                            licenses.add(license);
941                    }
942    
943                    List<String> liferayVersions = new ArrayList<String>();
944    
945                    String[] liferayVersionsArray = StringUtil.split(
946                            properties.getProperty("liferay-versions"));
947    
948                    for (String liferayVersion : liferayVersionsArray) {
949                            liferayVersions.add(liferayVersion.trim());
950                    }
951    
952                    if (liferayVersions.size() == 0) {
953                            liferayVersions.add(ReleaseInfo.getVersion() + "+");
954                    }
955    
956                    List<String> tags = new ArrayList<String>();
957    
958                    String[] tagsArray = StringUtil.split(properties.getProperty("tags"));
959    
960                    for (String tag : tagsArray) {
961                            tags.add(tag.trim());
962                    }
963    
964                    String shortDescription = GetterUtil.getString(
965                            properties.getProperty("short-description"));
966                    String longDescription = GetterUtil.getString(
967                            properties.getProperty("long-description"));
968                    String changeLog = GetterUtil.getString(
969                            properties.getProperty("change-log"));
970                    String pageURL = GetterUtil.getString(
971                            properties.getProperty("page-url"));
972                    String downloadURL = GetterUtil.getString(
973                            properties.getProperty("download-url"));
974                    List<String> requiredDeploymentContexts = ListUtil.fromArray(
975                            StringUtil.split(
976                                    properties.getProperty("required-deployment-contexts")));
977    
978                    PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
979    
980                    pluginPackage.setName(pluginName);
981                    pluginPackage.setRecommendedDeploymentContext(deploymentContext);
982                    //pluginPackage.setModifiedDate(null);
983                    pluginPackage.setAuthor(author);
984                    pluginPackage.setTypes(types);
985                    pluginPackage.setLicenses(licenses);
986                    pluginPackage.setLiferayVersions(liferayVersions);
987                    pluginPackage.setTags(tags);
988                    pluginPackage.setShortDescription(shortDescription);
989                    pluginPackage.setLongDescription(longDescription);
990                    pluginPackage.setChangeLog(changeLog);
991                    //pluginPackage.setScreenshots(null);
992                    pluginPackage.setPageURL(pageURL);
993                    pluginPackage.setDownloadURL(downloadURL);
994                    //pluginPackage.setDeploymentSettings(null);
995                    pluginPackage.setRequiredDeploymentContexts(requiredDeploymentContexts);
996    
997                    return pluginPackage;
998            }
999    
1000            /**
1001             * @see {@link
1002             *      com.liferay.portal.tools.deploy.BaseDeployer#readPluginPackage(
1003             *      java.io.File)}
1004             */
1005            private PluginPackage _readPluginPackageServletContext(
1006                            ServletContext servletContext)
1007                    throws DocumentException, IOException {
1008    
1009                    String servletContextName = servletContext.getServletContextName();
1010    
1011                    if (_log.isInfoEnabled()) {
1012                            if (servletContextName == null) {
1013                                    _log.info("Reading plugin package for the root context");
1014                            }
1015                            else {
1016                                    _log.info("Reading plugin package for " + servletContextName);
1017                            }
1018                    }
1019    
1020                    PluginPackage pluginPackage = null;
1021    
1022                    String xml = HttpUtil.URLtoString(
1023                            servletContext.getResource("/WEB-INF/liferay-plugin-package.xml"));
1024    
1025                    if (xml != null) {
1026                            pluginPackage = _readPluginPackageXml(xml);
1027                    }
1028                    else {
1029                            String propertiesString = HttpUtil.URLtoString(
1030                                    servletContext.getResource(
1031                                            "/WEB-INF/liferay-plugin-package.properties"));
1032    
1033                            if (propertiesString != null) {
1034                                    if (_log.isDebugEnabled()) {
1035                                            _log.debug(
1036                                                    "Reading plugin package from " +
1037                                                            "liferay-plugin-package.properties");
1038                                    }
1039    
1040                                    Properties properties = PropertiesUtil.load(propertiesString);
1041    
1042                                    String displayName = servletContextName;
1043    
1044                                    if (displayName.startsWith(StringPool.SLASH)) {
1045                                            displayName = displayName.substring(1);
1046                                    }
1047    
1048                                    pluginPackage = _readPluginPackageProperties(
1049                                            displayName, properties);
1050                            }
1051    
1052                            if (pluginPackage == null) {
1053                                    if (_log.isDebugEnabled()) {
1054                                            _log.debug("Reading plugin package from MANIFEST.MF");
1055                                    }
1056    
1057                                    pluginPackage =_readPluginPackageServletManifest(
1058                                            servletContext);
1059                            }
1060                    }
1061    
1062                    pluginPackage.setContext(servletContextName);
1063    
1064                    return pluginPackage;
1065            }
1066    
1067            private PluginPackage _readPluginPackageServletManifest(
1068                            ServletContext servletContext)
1069                    throws IOException {
1070    
1071                    Attributes attributes = null;
1072    
1073                    String servletContextName = servletContext.getServletContextName();
1074    
1075                    InputStream inputStream = servletContext.getResourceAsStream(
1076                            "/META-INF/MANIFEST.MF");
1077    
1078                    if (inputStream != null) {
1079                            Manifest manifest = new Manifest(inputStream);
1080    
1081                            attributes = manifest.getMainAttributes();
1082                    }
1083                    else {
1084                            attributes = new Attributes();
1085                    }
1086    
1087                    String artifactGroupId = attributes.getValue(
1088                            "Implementation-Vendor-Id");
1089    
1090                    if (Validator.isNull(artifactGroupId)) {
1091                            artifactGroupId = attributes.getValue("Implementation-Vendor");
1092                    }
1093    
1094                    if (Validator.isNull(artifactGroupId)) {
1095                            artifactGroupId = GetterUtil.getString(
1096                                    attributes.getValue("Bundle-Vendor"), servletContextName);
1097                    }
1098    
1099                    String artifactId = attributes.getValue("Implementation-Title");
1100    
1101                    if (Validator.isNull(artifactId)) {
1102                            artifactId = GetterUtil.getString(
1103                                    attributes.getValue("Bundle-Name"), servletContextName);
1104                    }
1105    
1106                    String version = attributes.getValue("Implementation-Version");
1107    
1108                    if (Validator.isNull(version)) {
1109                            version = GetterUtil.getString(
1110                                    attributes.getValue("Bundle-Version"), Version.UNKNOWN);
1111                    }
1112    
1113                    if (version.equals(Version.UNKNOWN) && _log.isWarnEnabled()) {
1114                            _log.warn(
1115                                    "Plugin package on context " + servletContextName +
1116                                            " cannot be tracked because this WAR does not contain a " +
1117                                                    "liferay-plugin-package.xml file");
1118                    }
1119    
1120                    PluginPackage pluginPackage = new PluginPackageImpl(
1121                            artifactGroupId + StringPool.SLASH + artifactId + StringPool.SLASH +
1122                                    version + StringPool.SLASH + "war");
1123    
1124                    pluginPackage.setName(artifactId);
1125    
1126                    String shortDescription = attributes.getValue("Bundle-Description");
1127    
1128                    if (Validator.isNotNull(shortDescription)) {
1129                            pluginPackage.setShortDescription(shortDescription);
1130                    }
1131    
1132                    String pageURL = attributes.getValue("Bundle-DocURL");
1133    
1134                    if (Validator.isNotNull(pageURL)) {
1135                            pluginPackage.setPageURL(pageURL);
1136                    }
1137    
1138                    return pluginPackage;
1139            }
1140    
1141            private PluginPackage _readPluginPackageXml(Element pluginPackageElement) {
1142                    String name = pluginPackageElement.elementText("name");
1143    
1144                    if (_log.isDebugEnabled()) {
1145                            _log.debug("Reading pluginPackage definition " + name);
1146                    }
1147    
1148                    PluginPackage pluginPackage = new PluginPackageImpl(
1149                            GetterUtil.getString(
1150                                    pluginPackageElement.elementText("module-id")));
1151    
1152                    List<String> liferayVersions = _readList(
1153                            pluginPackageElement.element("liferay-versions"),
1154                            "liferay-version");
1155    
1156                    List<String> types = _readList(
1157                            pluginPackageElement.element("types"), "type");
1158    
1159                    if (types.contains("layout-template")) {
1160                            types.remove("layout-template");
1161    
1162                            types.add(Plugin.TYPE_LAYOUT_TEMPLATE);
1163                    }
1164    
1165                    pluginPackage.setName(_readText(name));
1166                    pluginPackage.setRecommendedDeploymentContext(
1167                            _readText(
1168                                    pluginPackageElement.elementText(
1169                                            "recommended-deployment-context")));
1170                    pluginPackage.setRequiredDeploymentContexts(
1171                            _readList(
1172                                    pluginPackageElement.element(
1173                                            "required-deployment-contexts"),
1174                                            "required-deployment-context"));
1175                    pluginPackage.setModifiedDate(
1176                            _readDate(pluginPackageElement.elementText("modified-date")));
1177                    pluginPackage.setAuthor(
1178                            _readText(pluginPackageElement.elementText("author")));
1179                    pluginPackage.setTypes(types);
1180                    pluginPackage.setLicenses(
1181                            _readLicenseList(
1182                                    pluginPackageElement.element("licenses"), "license"));
1183                    pluginPackage.setLiferayVersions(liferayVersions);
1184                    pluginPackage.setTags(
1185                            _readList(pluginPackageElement.element("tags"), "tag"));
1186                    pluginPackage.setShortDescription(
1187                            _readText(pluginPackageElement.elementText("short-description")));
1188                    pluginPackage.setLongDescription(
1189                            _readHtml(pluginPackageElement.elementText("long-description")));
1190                    pluginPackage.setChangeLog(
1191                            _readHtml(pluginPackageElement.elementText("change-log")));
1192                    pluginPackage.setScreenshots(
1193                            _readScreenshots(pluginPackageElement.element("screenshots")));
1194                    pluginPackage.setPageURL(
1195                            _readText(pluginPackageElement.elementText("page-url")));
1196                    pluginPackage.setDownloadURL(
1197                            _readText(pluginPackageElement.elementText("download-url")));
1198                    pluginPackage.setDeploymentSettings(
1199                            _readProperties(
1200                                    pluginPackageElement.element("deployment-settings"),
1201                                    "setting"));
1202    
1203                    return pluginPackage;
1204            }
1205    
1206            private PluginPackage _readPluginPackageXml(String xml)
1207                    throws DocumentException {
1208    
1209                    Document document = SAXReaderUtil.read(xml);
1210    
1211                    Element rootElement = document.getRootElement();
1212    
1213                    return _readPluginPackageXml(rootElement);
1214            }
1215    
1216            private Properties _readProperties(Element parentElement, String name) {
1217                    Properties properties = new Properties();
1218    
1219                    if (parentElement == null) {
1220                            return properties;
1221                    }
1222    
1223                    for (Element element : parentElement.elements(name)) {
1224                            properties.setProperty(
1225                                    element.attributeValue("name"),
1226                                    element.attributeValue("value"));
1227                    }
1228    
1229                    return properties;
1230            }
1231    
1232            private List<Screenshot> _readScreenshots(Element parentElement) {
1233                    List<Screenshot> screenshots = new ArrayList<Screenshot>();
1234    
1235                    if (parentElement == null) {
1236                            return screenshots;
1237                    }
1238    
1239                    for (Element screenshotElement : parentElement.elements("screenshot")) {
1240                            Screenshot screenshot = new Screenshot();
1241    
1242                            screenshot.setThumbnailURL(
1243                                    screenshotElement.elementText("thumbnail-url"));
1244                            screenshot.setLargeImageURL(
1245                                    screenshotElement.elementText("large-image-url"));
1246    
1247                            screenshots.add(screenshot);
1248                    }
1249    
1250                    return screenshots;
1251            }
1252    
1253            private String _readText(String text) {
1254                    return HtmlUtil.extractText(GetterUtil.getString(text));
1255            }
1256    
1257            private void _refreshUpdatesAvailableCache() {
1258                    _updateAvailable = null;
1259            }
1260    
1261            private void _registerInstalledPluginPackage(PluginPackage pluginPackage)
1262                    throws PortalException {
1263    
1264                    _installedPluginPackages.addPluginPackage(pluginPackage);
1265    
1266                    _updateAvailable = null;
1267    
1268                    _indexPluginPackage(pluginPackage);
1269            }
1270    
1271            private void _registerPluginPackageInstallation(String preliminaryContext) {
1272                    _installedPluginPackages.registerPluginPackageInstallation(
1273                            preliminaryContext);
1274            }
1275    
1276            private RepositoryReport _reloadRepositories()
1277                    throws PortalException, SystemException {
1278    
1279                    if (_log.isInfoEnabled()) {
1280                            _log.info("Reloading repositories");
1281                    }
1282    
1283                    RepositoryReport repositoryReport = new RepositoryReport();
1284    
1285                    String[] repositoryURLs = _getRepositoryURLs();
1286    
1287                    for (int i = 0; i < repositoryURLs.length; i++) {
1288                            String repositoryURL = repositoryURLs[i];
1289    
1290                            try {
1291                                    _loadRepository(repositoryURL);
1292    
1293                                    repositoryReport.addSuccess(repositoryURL);
1294                            }
1295                            catch (PluginPackageException ppe) {
1296                                    repositoryReport.addError(repositoryURL, ppe);
1297    
1298                                    _log.error(
1299                                            "Unable to load repository " + repositoryURL + " " +
1300                                                    ppe.toString());
1301                            }
1302                    }
1303    
1304                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1305    
1306                    indexer.reindex(new String[0]);
1307    
1308                    return repositoryReport;
1309            }
1310    
1311            private Hits _search(
1312                            String keywords, String type, String tag, String license,
1313                            String repositoryURL, String status, int start, int end)
1314                    throws PortalException, SystemException {
1315    
1316                    _checkRepositories(repositoryURL);
1317    
1318                    SearchContext searchContext = new SearchContext();
1319    
1320                    Map<String, Serializable> attributes =
1321                            new HashMap<String, Serializable>();
1322    
1323                    attributes.put("license", license);
1324                    attributes.put("repositoryURL", repositoryURL);
1325                    attributes.put("status", status);
1326                    attributes.put("tag", tag);
1327                    attributes.put("type", type);
1328    
1329                    searchContext.setAttributes(attributes);
1330    
1331                    searchContext.setCompanyId(CompanyConstants.SYSTEM);
1332                    searchContext.setEnd(end);
1333                    searchContext.setKeywords(keywords);
1334    
1335                    QueryConfig queryConfig = new QueryConfig();
1336    
1337                    queryConfig.setHighlightEnabled(false);
1338                    queryConfig.setScoreEnabled(false);
1339    
1340                    searchContext.setQueryConfig(queryConfig);
1341    
1342                    searchContext.setStart(start);
1343    
1344                    Indexer indexer = IndexerRegistryUtil.getIndexer(PluginPackage.class);
1345    
1346                    return indexer.search(searchContext);
1347            }
1348    
1349            private void _unregisterInstalledPluginPackage(PluginPackage pluginPackage)
1350                    throws PortalException, SystemException {
1351    
1352                    _installedPluginPackages.removePluginPackage(pluginPackage);
1353    
1354                    try {
1355                            List<PluginPackage> pluginPackages = _getAvailablePluginPackages(
1356                                    pluginPackage.getGroupId(), pluginPackage.getArtifactId());
1357    
1358                            for (PluginPackage availablePackage : pluginPackages) {
1359                                    _indexPluginPackage(availablePackage);
1360                            }
1361                    }
1362                    catch (PluginPackageException ppe) {
1363                            if (_log.isWarnEnabled()) {
1364                                    _log.warn(
1365                                            "Unable to reindex unistalled package " +
1366                                                    pluginPackage.getContext() + ": " + ppe.getMessage());
1367                            }
1368                    }
1369            }
1370    
1371            private void _updateInstallingPluginPackage(
1372                    String preliminaryContext, PluginPackage pluginPackage) {
1373    
1374                    _installedPluginPackages.unregisterPluginPackageInstallation(
1375                            preliminaryContext);
1376                    _installedPluginPackages.registerPluginPackageInstallation(
1377                            pluginPackage);
1378            }
1379    
1380            private static Log _log = LogFactoryUtil.getLog(PluginPackageUtil.class);
1381    
1382            private static PluginPackageUtil _instance = new PluginPackageUtil();
1383    
1384            private Set<String> _availableTagsCache;
1385            private LocalPluginPackageRepository _installedPluginPackages;
1386            private Date _lastUpdateDate;
1387            private Map<String, RemotePluginPackageRepository> _repositoryCache;
1388            private boolean _settingUpdateAvailable;
1389            private Boolean _updateAvailable;
1390    
1391            private class UpdateAvailableRunner implements Runnable {
1392    
1393                    @Override
1394                    public void run() {
1395                            try {
1396                                    setUpdateAvailable();
1397                            }
1398                            catch (Exception e) {
1399                                    if (_log.isWarnEnabled()) {
1400                                            _log.warn(e.getMessage());
1401                                    }
1402                            }
1403                    }
1404    
1405                    protected void setUpdateAvailable() throws Exception {
1406                            StopWatch stopWatch = new StopWatch();
1407    
1408                            stopWatch.start();
1409    
1410                            if (_log.isInfoEnabled()) {
1411                                    _log.info("Checking for available updates");
1412                            }
1413    
1414                            for (PluginPackage pluginPackage :
1415                                            _installedPluginPackages.getPluginPackages()) {
1416    
1417                                    PluginPackage availablePluginPackage = null;
1418    
1419                                    if (_isIgnored(pluginPackage)) {
1420                                            continue;
1421                                    }
1422    
1423                                    availablePluginPackage =
1424                                            PluginPackageUtil.getLatestAvailablePluginPackage(
1425                                                    pluginPackage.getGroupId(),
1426                                                    pluginPackage.getArtifactId());
1427    
1428                                    if (availablePluginPackage == null) {
1429                                            continue;
1430                                    }
1431    
1432                                    Version availablePluginPackageVersion = Version.getInstance(
1433                                            availablePluginPackage.getVersion());
1434    
1435                                    if (availablePluginPackageVersion.isLaterVersionThan(
1436                                                    pluginPackage.getVersion())) {
1437    
1438                                            _updateAvailable = Boolean.TRUE;
1439    
1440                                            break;
1441                                    }
1442                            }
1443    
1444                            if (_updateAvailable == null) {
1445                                    _updateAvailable = Boolean.FALSE;
1446                            }
1447    
1448                            _settingUpdateAvailable = false;
1449    
1450                            if (_log.isInfoEnabled()) {
1451                                    _log.info(
1452                                            "Finished checking for available updates in " +
1453                                                    stopWatch.getTime() + " ms");
1454                            }
1455                    }
1456            }
1457    
1458    }