0001: /**
0002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
0003: *
0004: * Permission is hereby granted, free of charge, to any person obtaining a copy
0005: * of this software and associated documentation files (the "Software"), to deal
0006: * in the Software without restriction, including without limitation the rights
0007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0008: * copies of the Software, and to permit persons to whom the Software is
0009: * furnished to do so, subject to the following conditions:
0010: *
0011: * The above copyright notice and this permission notice shall be included in
0012: * all copies or substantial portions of the Software.
0013: *
0014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0020: * SOFTWARE.
0021: */package com.liferay.portal.plugin;
0022:
0023: import com.liferay.portal.PortalException;
0024: import com.liferay.portal.SystemException;
0025: import com.liferay.portal.kernel.plugin.PluginPackage;
0026: import com.liferay.portal.kernel.plugin.RemotePluginPackageRepository;
0027: import com.liferay.portal.kernel.search.Hits;
0028: import com.liferay.portal.kernel.util.ArrayUtil;
0029: import com.liferay.portal.kernel.util.GetterUtil;
0030: import com.liferay.portal.kernel.util.ReleaseInfo;
0031: import com.liferay.portal.kernel.util.StringMaker;
0032: import com.liferay.portal.kernel.util.StringPool;
0033: import com.liferay.portal.kernel.util.StringUtil;
0034: import com.liferay.portal.kernel.util.Validator;
0035: import com.liferay.portal.lucene.LuceneFields;
0036: import com.liferay.portal.lucene.LuceneUtil;
0037: import com.liferay.portal.model.impl.CompanyImpl;
0038: import com.liferay.portal.util.PortalUtil;
0039: import com.liferay.portal.util.PrefsPropsUtil;
0040: import com.liferay.portal.util.PropsUtil;
0041: import com.liferay.portal.util.PropsValues;
0042: import com.liferay.util.Html;
0043: import com.liferay.util.Http;
0044: import com.liferay.util.License;
0045: import com.liferay.util.Screenshot;
0046: import com.liferay.util.Time;
0047: import com.liferay.util.Version;
0048: import com.liferay.util.lucene.HitsImpl;
0049:
0050: import java.io.IOException;
0051:
0052: import java.net.MalformedURLException;
0053:
0054: import java.text.DateFormat;
0055: import java.text.SimpleDateFormat;
0056:
0057: import java.util.ArrayList;
0058: import java.util.Arrays;
0059: import java.util.Collection;
0060: import java.util.Date;
0061: import java.util.HashMap;
0062: import java.util.Iterator;
0063: import java.util.List;
0064: import java.util.Locale;
0065: import java.util.Map;
0066: import java.util.Properties;
0067: import java.util.Set;
0068: import java.util.TreeSet;
0069:
0070: import org.apache.commons.httpclient.HostConfiguration;
0071: import org.apache.commons.httpclient.HttpClient;
0072: import org.apache.commons.httpclient.methods.GetMethod;
0073: import org.apache.commons.lang.time.StopWatch;
0074: import org.apache.commons.logging.Log;
0075: import org.apache.commons.logging.LogFactory;
0076: import org.apache.lucene.index.IndexWriter;
0077: import org.apache.lucene.index.Term;
0078: import org.apache.lucene.search.BooleanClause;
0079: import org.apache.lucene.search.BooleanQuery;
0080: import org.apache.lucene.search.Query;
0081: import org.apache.lucene.search.Searcher;
0082: import org.apache.lucene.search.TermQuery;
0083:
0084: import org.dom4j.Attribute;
0085: import org.dom4j.Document;
0086: import org.dom4j.DocumentException;
0087: import org.dom4j.Element;
0088:
0089: /**
0090: * <a href="PluginPackageUtil.java.html"><b><i>View Source</i></b></a>
0091: *
0092: * @author Jorge Ferrer
0093: * @author Brian Wing Shun Chan
0094: *
0095: */
0096: public class PluginPackageUtil {
0097:
0098: public static final String REPOSITORY_XML_FILENAME_PREFIX = "liferay-plugin-repository";
0099:
0100: public static final String REPOSITORY_XML_FILENAME_EXTENSION = "xml";
0101:
0102: public static void endPluginPackageInstallation(
0103: String preliminaryContext) {
0104: _instance._endPluginPackageInstallation(preliminaryContext);
0105: }
0106:
0107: public static List getAllAvailablePluginPackages()
0108: throws PluginPackageException {
0109:
0110: return _instance._getAllAvailablePluginPackages();
0111: }
0112:
0113: public static Collection getAvailableTags() {
0114: return _instance._getAvailableTags();
0115: }
0116:
0117: public static List getInstalledPluginPackages() {
0118: return _instance._getInstalledPluginPackages();
0119: }
0120:
0121: public static PluginPackage getLatestAvailablePluginPackage(
0122: String groupId, String artifactId) throws SystemException {
0123:
0124: return _instance._getLatestAvailablePluginPackage(groupId,
0125: artifactId);
0126: }
0127:
0128: public static PluginPackage getLatestInstalledPluginPackage(
0129: String groupId, String artifactId) {
0130:
0131: return _instance._getLatestInstalledPluginPackage(groupId,
0132: artifactId);
0133: }
0134:
0135: public static Date getLastUpdateDate() {
0136: return _instance._getLastUpdateDate();
0137: }
0138:
0139: public static PluginPackage getPluginPackageByModuleId(
0140: String moduleId, String repositoryURL)
0141: throws DocumentException, IOException,
0142: PluginPackageException {
0143:
0144: return _instance._getPluginPackageByModuleId(moduleId,
0145: repositoryURL);
0146: }
0147:
0148: public static PluginPackage getPluginPackageByURL(String url)
0149: throws PluginPackageException {
0150:
0151: return _instance._getPluginPackageByURL(url);
0152: }
0153:
0154: public static RemotePluginPackageRepository getRepository(
0155: String repositoryURL) throws PluginPackageException {
0156:
0157: return _instance._getRepository(repositoryURL);
0158: }
0159:
0160: public static String[] getRepositoryURLs()
0161: throws PluginPackageException {
0162: return _instance._getRepositoryURLs();
0163: }
0164:
0165: public static String[] getSupportedTypes() {
0166: return _instance._getSupportedTypes();
0167: }
0168:
0169: public static boolean isCurrentVersionSupported(List versions) {
0170: return _instance._isCurrentVersionSupported(versions);
0171: }
0172:
0173: public static boolean isIgnored(PluginPackage pluginPackage)
0174: throws PortalException, SystemException {
0175:
0176: return _instance._isIgnored(pluginPackage);
0177: }
0178:
0179: public static boolean isInstallationInProcess(String context) {
0180: return _instance._isInstallationInProcess(context);
0181: }
0182:
0183: public static boolean isTrusted(String repositoryURL)
0184: throws PluginPackageException {
0185:
0186: return _instance._isTrusted(repositoryURL);
0187: }
0188:
0189: public static boolean isUpdateAvailable() throws PortalException,
0190: SystemException {
0191:
0192: return _instance._isUpdateAvailable();
0193: }
0194:
0195: public static PluginPackage readPluginPackageProps(
0196: String displayName, Properties props) {
0197:
0198: return _instance._readPluginPackageProps(displayName, props);
0199: }
0200:
0201: public static PluginPackage readPluginPackageXml(String xml)
0202: throws DocumentException {
0203:
0204: return _instance._readPluginPackageXml(xml);
0205: }
0206:
0207: public static PluginPackage readPluginPackageXml(
0208: Element pluginPackageEl) {
0209: return _instance._readPluginPackageXml(pluginPackageEl);
0210: }
0211:
0212: public static void refreshUpdatesAvailableCache() {
0213: _instance._refreshUpdatesAvailableCache();
0214: }
0215:
0216: public static void reIndex() throws SystemException {
0217: _instance._reIndex();
0218: }
0219:
0220: public static RepositoryReport reloadRepositories()
0221: throws SystemException {
0222: return _instance._reloadRepositories();
0223: }
0224:
0225: public static void registerInstalledPluginPackage(
0226: PluginPackage pluginPackage) {
0227:
0228: _instance._registerInstalledPluginPackage(pluginPackage);
0229: }
0230:
0231: public static void registerPluginPackageInstallation(
0232: String preliminaryContext) {
0233:
0234: _instance
0235: ._registerPluginPackageInstallation(preliminaryContext);
0236: }
0237:
0238: public static Hits search(String keywords, String type, String tag,
0239: String license, String repositoryURL, String status)
0240: throws SystemException {
0241:
0242: return _instance._search(keywords, type, tag, license,
0243: repositoryURL, status);
0244: }
0245:
0246: public static void unregisterInstalledPluginPackage(
0247: PluginPackage pluginPackage) {
0248:
0249: _instance._unregisterInstalledPluginPackage(pluginPackage);
0250: }
0251:
0252: public static void updateInstallingPluginPackage(
0253: String preliminaryContext, PluginPackage pluginPackage) {
0254:
0255: _instance._updateInstallingPluginPackage(preliminaryContext,
0256: pluginPackage);
0257: }
0258:
0259: private PluginPackageUtil() {
0260: _installedPluginPackages = new LocalPluginPackageRepository();
0261: _repositoryCache = new HashMap();
0262: _availableTagsCache = new TreeSet();
0263: }
0264:
0265: private void _checkRepositories(String repositoryURL)
0266: throws PluginPackageException {
0267:
0268: String[] repositoryURLs = null;
0269:
0270: if (Validator.isNotNull(repositoryURL)) {
0271: repositoryURLs = new String[] { repositoryURL };
0272: } else {
0273: repositoryURLs = _getRepositoryURLs();
0274: }
0275:
0276: for (int i = 0; i < repositoryURLs.length; i++) {
0277: _getRepository(repositoryURLs[i]);
0278: }
0279: }
0280:
0281: private void _endPluginPackageInstallation(String preliminaryContext) {
0282: _installedPluginPackages
0283: .unregisterPluginPackageInstallation(preliminaryContext);
0284: }
0285:
0286: private PluginPackage _findLatestVersion(List pluginPackages) {
0287: PluginPackage pluginPackage = null;
0288:
0289: Iterator itr = pluginPackages.iterator();
0290:
0291: while (itr.hasNext()) {
0292: PluginPackage curPluginPackage = (PluginPackage) itr.next();
0293:
0294: if ((pluginPackage == null)
0295: || (curPluginPackage
0296: .isLaterVersionThan(pluginPackage))) {
0297:
0298: pluginPackage = curPluginPackage;
0299: }
0300: }
0301:
0302: return pluginPackage;
0303: }
0304:
0305: private List _getAllAvailablePluginPackages()
0306: throws PluginPackageException {
0307:
0308: List plugins = new ArrayList();
0309:
0310: String[] repositoryURLs = _getRepositoryURLs();
0311:
0312: for (int i = 0; i < repositoryURLs.length; i++) {
0313: try {
0314: RemotePluginPackageRepository repository = _getRepository(repositoryURLs[i]);
0315:
0316: plugins.addAll(repository.getPluginPackages());
0317: } catch (PluginPackageException ppe) {
0318: String message = ppe.getMessage();
0319:
0320: if (message.startsWith("Unable to communicate")) {
0321: if (_log.isWarnEnabled()) {
0322: _log.warn(message);
0323: }
0324: } else {
0325: _log.error(message);
0326: }
0327: }
0328: }
0329:
0330: return plugins;
0331: }
0332:
0333: private List _getAvailablePluginPackages(String groupId,
0334: String artifactId) throws PluginPackageException {
0335:
0336: List pluginPackages = new ArrayList();
0337:
0338: String[] repositoryURLs = _getRepositoryURLs();
0339:
0340: for (int i = 0; i < repositoryURLs.length; i++) {
0341: RemotePluginPackageRepository repository = _getRepository(repositoryURLs[i]);
0342:
0343: List curPluginPackages = repository
0344: .findPluginsByGroupIdAndArtifactId(groupId,
0345: artifactId);
0346:
0347: if (curPluginPackages != null) {
0348: pluginPackages.addAll(curPluginPackages);
0349: }
0350: }
0351:
0352: return pluginPackages;
0353: }
0354:
0355: private Collection _getAvailableTags() {
0356: return _availableTagsCache;
0357: }
0358:
0359: private List _getInstalledPluginPackages() {
0360: return _installedPluginPackages.getSortedPluginPackages();
0361: }
0362:
0363: private PluginPackage _getLatestAvailablePluginPackage(
0364: String groupId, String artifactId) throws SystemException {
0365:
0366: List pluginPackages = _getAvailablePluginPackages(groupId,
0367: artifactId);
0368:
0369: return _findLatestVersion(pluginPackages);
0370: }
0371:
0372: private PluginPackage _getLatestInstalledPluginPackage(
0373: String groupId, String artifactId) {
0374:
0375: return _installedPluginPackages.getLatestPluginPackage(groupId,
0376: artifactId);
0377: }
0378:
0379: private Date _getLastUpdateDate() {
0380: return _lastUpdateDate;
0381: }
0382:
0383: private PluginPackage _getPluginPackageByModuleId(String moduleId,
0384: String repositoryURL) throws DocumentException,
0385: IOException, PluginPackageException {
0386:
0387: RemotePluginPackageRepository repository = _getRepository(repositoryURL);
0388:
0389: return repository.findPluginPackageByModuleId(moduleId);
0390: }
0391:
0392: private PluginPackage _getPluginPackageByURL(String url)
0393: throws PluginPackageException {
0394:
0395: String[] repositoryURLs = _getRepositoryURLs();
0396:
0397: for (int i = 0; i < repositoryURLs.length; i++) {
0398: String repositoryURL = repositoryURLs[i];
0399:
0400: try {
0401: RemotePluginPackageRepository repository = _getRepository(repositoryURL);
0402:
0403: return repository.findPluginByArtifactURL(url);
0404: } catch (PluginPackageException pe) {
0405: _log.error(
0406: "Unable to load repository " + repositoryURL,
0407: pe);
0408: }
0409: }
0410:
0411: return null;
0412: }
0413:
0414: private RemotePluginPackageRepository _getRepository(
0415: String repositoryURL) throws PluginPackageException {
0416:
0417: RemotePluginPackageRepository repository = (RemotePluginPackageRepository) _repositoryCache
0418: .get(repositoryURL);
0419:
0420: if (repository != null) {
0421: return repository;
0422: }
0423:
0424: return _loadRepository(repositoryURL);
0425: }
0426:
0427: private String[] _getRepositoryURLs() throws PluginPackageException {
0428: try {
0429: String[] trusted = PrefsPropsUtil.getStringArray(
0430: PropsUtil.PLUGIN_REPOSITORIES_TRUSTED,
0431: StringPool.NEW_LINE,
0432: PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
0433: String[] untrusted = PrefsPropsUtil.getStringArray(
0434: PropsUtil.PLUGIN_REPOSITORIES_UNTRUSTED,
0435: StringPool.NEW_LINE,
0436: PropsValues.PLUGIN_REPOSITORIES_UNTRUSTED);
0437:
0438: return ArrayUtil.append(trusted, untrusted);
0439: } catch (Exception e) {
0440: throw new PluginPackageException(
0441: "Unable to read repository list", e);
0442: }
0443: }
0444:
0445: private String[] _getStatusAndInstalledVersion(
0446: PluginPackage pluginPackage) {
0447:
0448: PluginPackage installedPluginPackage = _installedPluginPackages
0449: .getLatestPluginPackage(pluginPackage.getGroupId(),
0450: pluginPackage.getArtifactId());
0451:
0452: String status = null;
0453: String installedVersion = null;
0454:
0455: if (installedPluginPackage == null) {
0456: status = PluginPackageImpl.STATUS_NOT_INSTALLED;
0457: } else {
0458: installedVersion = installedPluginPackage.getVersion();
0459:
0460: if (installedPluginPackage
0461: .isLaterVersionThan(pluginPackage)) {
0462: status = PluginPackageImpl.STATUS_NEWER_VERSION_INSTALLED;
0463: } else if (installedPluginPackage
0464: .isPreviousVersionThan(pluginPackage)) {
0465:
0466: status = PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED;
0467: } else {
0468: status = PluginPackageImpl.STATUS_SAME_VERSION_INSTALLED;
0469: }
0470: }
0471:
0472: return new String[] { status, installedVersion };
0473: }
0474:
0475: private String[] _getSupportedTypes() {
0476: return PropsValues.PLUGIN_TYPES;
0477: }
0478:
0479: private void _indexPluginPackage(PluginPackage pluginPackage) {
0480: String[] statusAndInstalledVersion = _getStatusAndInstalledVersion(pluginPackage);
0481:
0482: String status = statusAndInstalledVersion[0];
0483: String installedVersion = statusAndInstalledVersion[1];
0484:
0485: try {
0486: PluginPackageIndexer.updatePluginPackage(pluginPackage
0487: .getModuleId(), pluginPackage.getName(),
0488: pluginPackage.getVersion(), pluginPackage
0489: .getModifiedDate(), pluginPackage
0490: .getAuthor(), pluginPackage.getTypes(),
0491: pluginPackage.getTags(), pluginPackage
0492: .getLicenses(), pluginPackage
0493: .getLiferayVersions(), pluginPackage
0494: .getShortDescription(), pluginPackage
0495: .getLongDescription(), pluginPackage
0496: .getChangeLog(),
0497: pluginPackage.getPageURL(), pluginPackage
0498: .getRepositoryURL(), status,
0499: installedVersion);
0500: } catch (Exception e) {
0501: _log.error("Error reindexing "
0502: + pluginPackage.getModuleId(), e);
0503: }
0504: }
0505:
0506: private boolean _isCurrentVersionSupported(List versions) {
0507: Version currentVersion = Version.getInstance(ReleaseInfo
0508: .getVersion());
0509:
0510: for (int i = 0; i < versions.size(); i++) {
0511: Version supportedVersion = Version
0512: .getInstance((String) versions.get(i));
0513:
0514: if (supportedVersion.includes(currentVersion)) {
0515: return true;
0516: }
0517: }
0518:
0519: return false;
0520: }
0521:
0522: private boolean _isIgnored(PluginPackage pluginPackage)
0523: throws PortalException, SystemException {
0524:
0525: String packageId = pluginPackage.getPackageId();
0526:
0527: String[] pluginPackagesIgnored = PrefsPropsUtil.getStringArray(
0528: PropsUtil.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED,
0529: StringPool.NEW_LINE,
0530: PropsValues.PLUGIN_NOTIFICATIONS_PACKAGES_IGNORED);
0531:
0532: for (int i = 0; i < pluginPackagesIgnored.length; i++) {
0533: String curPluginPackagesIgnored = pluginPackagesIgnored[i];
0534:
0535: if (curPluginPackagesIgnored.endsWith(StringPool.STAR)) {
0536: String prefix = curPluginPackagesIgnored.substring(0,
0537: curPluginPackagesIgnored.length() - 2);
0538:
0539: if (packageId.startsWith(prefix)) {
0540: return true;
0541: }
0542: } else {
0543: if (packageId.equals(curPluginPackagesIgnored)) {
0544: return true;
0545: }
0546: }
0547: }
0548:
0549: return false;
0550: }
0551:
0552: private boolean _isInstallationInProcess(String context) {
0553: if (_installedPluginPackages
0554: .getInstallingPluginPackage(context) != null) {
0555:
0556: return true;
0557: } else {
0558: return false;
0559: }
0560: }
0561:
0562: private boolean _isTrusted(String repositoryURL)
0563: throws PluginPackageException {
0564:
0565: try {
0566: String[] trusted = PrefsPropsUtil.getStringArray(
0567: PropsUtil.PLUGIN_REPOSITORIES_TRUSTED,
0568: StringPool.NEW_LINE,
0569: PropsValues.PLUGIN_REPOSITORIES_TRUSTED);
0570:
0571: if (ArrayUtil.contains(trusted, repositoryURL)) {
0572: return true;
0573: } else {
0574: return false;
0575: }
0576: } catch (Exception e) {
0577: throw new PluginPackageException(
0578: "Unable to read repository list", e);
0579: }
0580: }
0581:
0582: private boolean _isUpdateAvailable() throws PortalException,
0583: SystemException {
0584:
0585: if (!PrefsPropsUtil.getBoolean(
0586: PropsUtil.PLUGIN_NOTIFICATIONS_ENABLED,
0587: PropsValues.PLUGIN_NOTIFICATIONS_ENABLED)) {
0588:
0589: return false;
0590: }
0591:
0592: if (_updateAvailable != null) {
0593: return _updateAvailable.booleanValue();
0594: } else if (!_settingUpdateAvailable) {
0595: _settingUpdateAvailable = true;
0596:
0597: Thread indexerThread = new Thread(
0598: new UpdateAvailableRunner(),
0599: PluginPackageUtil.class.getName());
0600:
0601: indexerThread.setPriority(Thread.MIN_PRIORITY);
0602:
0603: indexerThread.start();
0604: }
0605:
0606: return false;
0607: }
0608:
0609: private RemotePluginPackageRepository _loadRepository(
0610: String repositoryURL) throws PluginPackageException {
0611:
0612: RemotePluginPackageRepository repository = null;
0613:
0614: StringMaker sm = new StringMaker();
0615:
0616: sm.append(repositoryURL);
0617: sm.append(StringPool.SLASH);
0618: sm.append(REPOSITORY_XML_FILENAME_PREFIX);
0619: sm.append(StringPool.DASH);
0620: sm.append(ReleaseInfo.getVersion());
0621: sm.append(StringPool.PERIOD);
0622: sm.append(REPOSITORY_XML_FILENAME_EXTENSION);
0623:
0624: String pluginsXmlURL = sm.toString();
0625:
0626: try {
0627: HostConfiguration hostConfig = Http
0628: .getHostConfig(pluginsXmlURL);
0629:
0630: HttpClient client = Http.getClient(hostConfig);
0631:
0632: GetMethod getFileMethod = new GetMethod(pluginsXmlURL);
0633:
0634: byte[] bytes = null;
0635:
0636: try {
0637: int responseCode = client.executeMethod(hostConfig,
0638: getFileMethod);
0639:
0640: if (responseCode != 200) {
0641: if (_log.isDebugEnabled()) {
0642: _log.debug("A repository for version "
0643: + ReleaseInfo.getVersion()
0644: + " was not found. "
0645: + "Checking general repository");
0646: }
0647:
0648: sm = new StringMaker();
0649:
0650: sm.append(repositoryURL);
0651: sm.append(StringPool.SLASH);
0652: sm.append(REPOSITORY_XML_FILENAME_PREFIX);
0653: sm.append(StringPool.PERIOD);
0654: sm.append(REPOSITORY_XML_FILENAME_EXTENSION);
0655:
0656: pluginsXmlURL = sm.toString();
0657:
0658: getFileMethod = new GetMethod(pluginsXmlURL);
0659:
0660: responseCode = client.executeMethod(hostConfig,
0661: getFileMethod);
0662:
0663: if (responseCode != 200) {
0664: throw new PluginPackageException(
0665: "Unable to download file "
0666: + pluginsXmlURL
0667: + " because of response code "
0668: + responseCode);
0669: }
0670: }
0671:
0672: bytes = getFileMethod.getResponseBody();
0673: } finally {
0674: getFileMethod.releaseConnection();
0675: }
0676:
0677: if ((bytes != null) && (bytes.length > 0)) {
0678: repository = _parseRepositoryXml(new String(bytes),
0679: repositoryURL);
0680:
0681: _repositoryCache.put(repositoryURL, repository);
0682: _availableTagsCache.addAll(repository.getTags());
0683: _lastUpdateDate = new Date();
0684: _updateAvailable = null;
0685:
0686: return repository;
0687: } else {
0688: _lastUpdateDate = new Date();
0689:
0690: throw new PluginPackageException(
0691: "Download returned 0 bytes");
0692: }
0693: } catch (MalformedURLException mue) {
0694: _repositoryCache.remove(repositoryURL);
0695:
0696: throw new PluginPackageException("Invalid URL "
0697: + pluginsXmlURL, mue);
0698: } catch (IOException ioe) {
0699: _repositoryCache.remove(repositoryURL);
0700:
0701: throw new PluginPackageException(
0702: "Unable to communicate with repository "
0703: + repositoryURL, ioe);
0704: } catch (DocumentException de) {
0705: _repositoryCache.remove(repositoryURL);
0706:
0707: throw new PluginPackageException(
0708: "Unable to parse plugin list for repository "
0709: + repositoryURL, de);
0710: }
0711: }
0712:
0713: private RemotePluginPackageRepository _parseRepositoryXml(
0714: String xml, String repositoryURL) throws DocumentException,
0715: IOException {
0716:
0717: List supportedPluginTypes = Arrays.asList(getSupportedTypes());
0718:
0719: if (_log.isDebugEnabled()) {
0720: _log.debug("Loading plugin repository " + repositoryURL
0721: + ":\n" + xml);
0722: }
0723:
0724: RemotePluginPackageRepository pluginPackageRepository = new RemotePluginPackageRepository(
0725: repositoryURL);
0726:
0727: if (xml == null) {
0728: return pluginPackageRepository;
0729: }
0730:
0731: Document doc = PortalUtil.readDocumentFromXML(xml);
0732:
0733: Element root = doc.getRootElement();
0734:
0735: Properties settings = _readProperties(root.element("settings"),
0736: "setting");
0737:
0738: pluginPackageRepository.setSettings(settings);
0739:
0740: Iterator itr1 = root.elements("plugin-package").iterator();
0741:
0742: while (itr1.hasNext()) {
0743: Element pluginPackageEl = (Element) itr1.next();
0744:
0745: PluginPackage pluginPackage = _readPluginPackageXml(pluginPackageEl);
0746:
0747: if (!_isCurrentVersionSupported(pluginPackage
0748: .getLiferayVersions())) {
0749:
0750: continue;
0751: }
0752:
0753: Iterator itr2 = pluginPackage.getTypes().iterator();
0754:
0755: boolean containsSupportedTypes = false;
0756:
0757: while (itr2.hasNext()) {
0758: String type = (String) itr2.next();
0759:
0760: if (supportedPluginTypes.contains(type)) {
0761: containsSupportedTypes = true;
0762:
0763: break;
0764: }
0765: }
0766:
0767: if (!containsSupportedTypes) {
0768: continue;
0769: }
0770:
0771: pluginPackage.setRepository(pluginPackageRepository);
0772:
0773: pluginPackageRepository.addPluginPackage(pluginPackage);
0774:
0775: _indexPluginPackage(pluginPackage);
0776: }
0777:
0778: return pluginPackageRepository;
0779: }
0780:
0781: private Date _readDate(String text) {
0782: if (Validator.isNotNull(text)) {
0783: DateFormat dateFormat = new SimpleDateFormat(
0784: Time.RFC822_FORMAT, Locale.US);
0785:
0786: try {
0787: return dateFormat.parse(text);
0788: } catch (Exception e) {
0789: if (_log.isWarnEnabled()) {
0790: _log.warn("Unable to parse date " + text);
0791: }
0792: }
0793: }
0794:
0795: return new Date();
0796: }
0797:
0798: private String _readHtml(String text) {
0799: return GetterUtil.getString(text);
0800: }
0801:
0802: private List _readLicenseList(Element parent, String childTagName) {
0803: List result = new ArrayList();
0804:
0805: Iterator itr = parent.elements(childTagName).iterator();
0806:
0807: while (itr.hasNext()) {
0808: Element tagEl = (Element) itr.next();
0809:
0810: License license = new License();
0811:
0812: license.setName(tagEl.getText());
0813:
0814: Attribute osiApproved = tagEl.attribute("osi-approved");
0815:
0816: if (osiApproved != null) {
0817: license.setOsiApproved(GetterUtil
0818: .getBoolean(osiApproved.getText()));
0819: }
0820:
0821: Attribute url = tagEl.attribute("url");
0822:
0823: if (url != null) {
0824: license.setUrl(url.getText());
0825: }
0826:
0827: result.add(license);
0828: }
0829:
0830: return result;
0831: }
0832:
0833: private List _readList(Element parent, String childTagName) {
0834: List result = new ArrayList();
0835:
0836: if (parent != null) {
0837: Iterator itr = parent.elements(childTagName).iterator();
0838:
0839: while (itr.hasNext()) {
0840: Element element = (Element) itr.next();
0841:
0842: String text = element.getText().trim().toLowerCase();
0843:
0844: result.add(text);
0845: }
0846: }
0847:
0848: return result;
0849: }
0850:
0851: private PluginPackage _readPluginPackageProps(String displayName,
0852: Properties props) {
0853:
0854: int pos = displayName.indexOf("-portlet");
0855:
0856: String pluginType = "portlet";
0857:
0858: if (pos == -1) {
0859: pos = displayName.indexOf("-theme");
0860:
0861: pluginType = "theme";
0862: }
0863:
0864: if (pos == -1) {
0865: return null;
0866: }
0867:
0868: String displayPrefix = displayName.substring(0, pos);
0869:
0870: String moduleGroupId = GetterUtil.getString(props
0871: .getProperty("module-group-id"));
0872: String moduleArtifactId = displayPrefix + "-" + pluginType;
0873: String moduleVersion = displayName.substring(pos
0874: + pluginType.length() + 2);
0875: String moduleId = moduleGroupId + "/" + moduleArtifactId + "/"
0876: + moduleVersion + "/war";
0877:
0878: String pluginName = GetterUtil.getString(props
0879: .getProperty("name"));
0880:
0881: String deploymentContext = GetterUtil.getString(props
0882: .getProperty("recommended-deployment-context"),
0883: moduleArtifactId);
0884:
0885: String author = GetterUtil.getString(props
0886: .getProperty("author"));
0887:
0888: List types = new ArrayList();
0889:
0890: types.add(pluginType);
0891:
0892: List licenses = new ArrayList();
0893:
0894: String[] licensesArray = StringUtil.split(props
0895: .getProperty("licenses"));
0896:
0897: for (int i = 0; i < licensesArray.length; i++) {
0898: License license = new License();
0899:
0900: license.setName(licensesArray[i].trim());
0901: license.setOsiApproved(true);
0902:
0903: licenses.add(license);
0904: }
0905:
0906: List liferayVersions = new ArrayList();
0907:
0908: String[] liferayVersionsArray = StringUtil.split(props
0909: .getProperty("liferay-versions"));
0910:
0911: for (int i = 0; i < liferayVersionsArray.length; i++) {
0912: liferayVersions.add(liferayVersionsArray[i].trim());
0913: }
0914:
0915: if (liferayVersions.size() == 0) {
0916: liferayVersions.add(ReleaseInfo.getVersion() + "+");
0917: }
0918:
0919: List tags = new ArrayList();
0920:
0921: String[] tagsArray = StringUtil
0922: .split(props.getProperty("tags"));
0923:
0924: for (int i = 0; i < tagsArray.length; i++) {
0925: tags.add(tagsArray[i].trim());
0926: }
0927:
0928: String shortDescription = GetterUtil.getString(props
0929: .getProperty("short-description"));
0930: String longDescription = GetterUtil.getString(props
0931: .getProperty("long-description"));
0932: String changeLog = GetterUtil.getString(props
0933: .getProperty("change-log"));
0934: String pageURL = GetterUtil.getString(props
0935: .getProperty("page-url"));
0936: String downloadURL = GetterUtil.getString(props
0937: .getProperty("download-url"));
0938:
0939: PluginPackage pluginPackage = new PluginPackageImpl(moduleId);
0940:
0941: pluginPackage.setName(pluginName);
0942: pluginPackage
0943: .setRecommendedDeploymentContext(deploymentContext);
0944: //pluginPackage.setModifiedDate(null);
0945: pluginPackage.setAuthor(author);
0946: pluginPackage.setTypes(types);
0947: pluginPackage.setLicenses(licenses);
0948: pluginPackage.setLiferayVersions(liferayVersions);
0949: pluginPackage.setTags(tags);
0950: pluginPackage.setShortDescription(shortDescription);
0951: pluginPackage.setLongDescription(longDescription);
0952: pluginPackage.setChangeLog(changeLog);
0953: //pluginPackage.setScreenshots(null);
0954: pluginPackage.setPageURL(pageURL);
0955: pluginPackage.setDownloadURL(downloadURL);
0956: //pluginPackage.setDeploymentSettings(null);
0957:
0958: return pluginPackage;
0959: }
0960:
0961: private PluginPackage _readPluginPackageXml(String xml)
0962: throws DocumentException {
0963:
0964: Document doc = PortalUtil.readDocumentFromXML(xml);
0965:
0966: Element root = doc.getRootElement();
0967:
0968: return _readPluginPackageXml(root);
0969: }
0970:
0971: private PluginPackage _readPluginPackageXml(Element pluginPackageEl) {
0972: String name = pluginPackageEl.elementText("name");
0973:
0974: if (_log.isDebugEnabled()) {
0975: _log.debug("Reading pluginPackage definition " + name);
0976: }
0977:
0978: PluginPackage pluginPackage = new PluginPackageImpl(GetterUtil
0979: .getString(pluginPackageEl.elementText("module-id")));
0980:
0981: List liferayVersions = _readList(pluginPackageEl
0982: .element("liferay-versions"), "liferay-version");
0983:
0984: List types = _readList(pluginPackageEl.element("types"), "type");
0985:
0986: pluginPackage.setName(_readText(name));
0987: pluginPackage
0988: .setRecommendedDeploymentContext(_readText(pluginPackageEl
0989: .elementText("recommended-deployment-context")));
0990: pluginPackage.setModifiedDate(_readDate(pluginPackageEl
0991: .elementText("modified-date")));
0992: pluginPackage.setAuthor(_readText(pluginPackageEl
0993: .elementText("author")));
0994: pluginPackage.setTypes(types);
0995: pluginPackage.setLicenses(_readLicenseList(pluginPackageEl
0996: .element("licenses"), "license"));
0997: pluginPackage.setLiferayVersions(liferayVersions);
0998: pluginPackage.setTags(_readList(
0999: pluginPackageEl.element("tags"), "tag"));
1000: pluginPackage.setShortDescription(_readText(pluginPackageEl
1001: .elementText("short-description")));
1002: pluginPackage.setLongDescription(_readHtml(pluginPackageEl
1003: .elementText("long-description")));
1004: pluginPackage.setChangeLog(_readHtml(pluginPackageEl
1005: .elementText("change-log")));
1006: pluginPackage.setScreenshots(_readScreenshots(pluginPackageEl
1007: .element("screenshots")));
1008: pluginPackage.setPageURL(_readText(pluginPackageEl
1009: .elementText("page-url")));
1010: pluginPackage.setDownloadURL(_readText(pluginPackageEl
1011: .elementText("download-url")));
1012: pluginPackage.setDeploymentSettings(_readProperties(
1013: pluginPackageEl.element("deployment-settings"),
1014: "setting"));
1015:
1016: return pluginPackage;
1017: }
1018:
1019: private Properties _readProperties(Element parent,
1020: String childTagName) {
1021: Properties result = new Properties();
1022:
1023: if (parent != null) {
1024: Iterator itr = parent.elements(childTagName).iterator();
1025:
1026: while (itr.hasNext()) {
1027: Element tagEl = (Element) itr.next();
1028:
1029: result.setProperty(tagEl.attribute("name").getValue(),
1030: tagEl.attribute("value").getValue());
1031: }
1032: }
1033:
1034: return result;
1035: }
1036:
1037: private List _readScreenshots(Element parent) {
1038: List result = new ArrayList();
1039:
1040: if (parent != null) {
1041: List screenshots = parent.elements("screenshot");
1042:
1043: Iterator itr = screenshots.iterator();
1044:
1045: while (itr.hasNext()) {
1046: Element screenshotEl = (Element) itr.next();
1047:
1048: Screenshot screenshot = new Screenshot();
1049:
1050: screenshot.setThumbnailURL(screenshotEl.element(
1051: "thumbnail-url").getText());
1052: screenshot.setLargeImageURL(screenshotEl.element(
1053: "large-image-url").getText());
1054:
1055: result.add(screenshot);
1056: }
1057: }
1058:
1059: return result;
1060: }
1061:
1062: private String _readText(String text) {
1063: return Html.stripHtml(GetterUtil.getString(text));
1064: }
1065:
1066: private void _refreshUpdatesAvailableCache() {
1067: _updateAvailable = null;
1068: }
1069:
1070: private void _reIndex() throws SystemException {
1071: if (LuceneUtil.INDEX_READ_ONLY) {
1072: return;
1073: }
1074:
1075: IndexWriter writer = null;
1076:
1077: try {
1078: PluginPackageIndexer.cleanIndex();
1079:
1080: writer = LuceneUtil.getWriter(CompanyImpl.SYSTEM);
1081:
1082: Iterator itr = _getAllAvailablePluginPackages().iterator();
1083:
1084: while (itr.hasNext()) {
1085: PluginPackage pluginPackage = (PluginPackage) itr
1086: .next();
1087:
1088: String[] statusAndInstalledVersion = _getStatusAndInstalledVersion(pluginPackage);
1089:
1090: String status = statusAndInstalledVersion[0];
1091: String installedVersion = statusAndInstalledVersion[1];
1092:
1093: org.apache.lucene.document.Document doc = PluginPackageIndexer
1094: .getAddPluginPackageDocument(pluginPackage
1095: .getModuleId(),
1096: pluginPackage.getName(), pluginPackage
1097: .getVersion(), pluginPackage
1098: .getModifiedDate(),
1099: pluginPackage.getAuthor(),
1100: pluginPackage.getTypes(), pluginPackage
1101: .getTags(), pluginPackage
1102: .getLicenses(), pluginPackage
1103: .getLiferayVersions(),
1104: pluginPackage.getShortDescription(),
1105: pluginPackage.getLongDescription(),
1106: pluginPackage.getChangeLog(),
1107: pluginPackage.getPageURL(),
1108: pluginPackage.getRepositoryURL(),
1109: status, installedVersion);
1110:
1111: writer.addDocument(doc);
1112: }
1113: } catch (SystemException se) {
1114: throw se;
1115: } catch (Exception e) {
1116: throw new SystemException(e);
1117: } finally {
1118: try {
1119: if (writer != null) {
1120: LuceneUtil.write(CompanyImpl.SYSTEM);
1121: }
1122: } catch (Exception e) {
1123: _log.error(e);
1124: }
1125: }
1126: }
1127:
1128: private RepositoryReport _reloadRepositories()
1129: throws SystemException {
1130: if (_log.isInfoEnabled()) {
1131: _log.info("Reloading repositories");
1132: }
1133:
1134: RepositoryReport report = new RepositoryReport();
1135:
1136: String[] repositoryURLs = _getRepositoryURLs();
1137:
1138: for (int i = 0; i < repositoryURLs.length; i++) {
1139: String repositoryURL = repositoryURLs[i];
1140:
1141: try {
1142: _loadRepository(repositoryURL);
1143:
1144: report.addSuccess(repositoryURL);
1145: } catch (PluginPackageException pe) {
1146: report.addError(repositoryURL, pe);
1147:
1148: _log.error("Unable to load repository " + repositoryURL
1149: + " " + pe.toString());
1150: }
1151:
1152: }
1153:
1154: _reIndex();
1155:
1156: return report;
1157: }
1158:
1159: private void _registerInstalledPluginPackage(
1160: PluginPackage pluginPackage) {
1161:
1162: _installedPluginPackages.addPluginPackage(pluginPackage);
1163:
1164: _updateAvailable = null;
1165:
1166: _indexPluginPackage(pluginPackage);
1167: }
1168:
1169: private void _registerPluginPackageInstallation(
1170: String preliminaryContext) {
1171:
1172: _installedPluginPackages
1173: .registerPluginPackageInstallation(preliminaryContext);
1174: }
1175:
1176: private Hits _search(String keywords, String type, String tag,
1177: String license, String repositoryURL, String status)
1178: throws SystemException {
1179:
1180: _checkRepositories(repositoryURL);
1181:
1182: Searcher searcher = null;
1183:
1184: try {
1185: HitsImpl hits = new HitsImpl();
1186:
1187: BooleanQuery contextQuery = new BooleanQuery();
1188:
1189: LuceneUtil.addRequiredTerm(contextQuery,
1190: LuceneFields.PORTLET_ID,
1191: PluginPackageIndexer.PORTLET_ID);
1192:
1193: BooleanQuery fullQuery = new BooleanQuery();
1194:
1195: fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
1196:
1197: if (Validator.isNotNull(keywords)) {
1198: BooleanQuery searchQuery = new BooleanQuery();
1199:
1200: LuceneUtil.addTerm(searchQuery, LuceneFields.TITLE,
1201: keywords);
1202: LuceneUtil.addTerm(searchQuery, LuceneFields.CONTENT,
1203: keywords);
1204:
1205: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1206: }
1207:
1208: if (Validator.isNotNull(type)) {
1209: BooleanQuery searchQuery = new BooleanQuery();
1210:
1211: LuceneUtil.addExactTerm(searchQuery, "type", type);
1212:
1213: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1214: }
1215:
1216: if (Validator.isNotNull(tag)) {
1217: BooleanQuery searchQuery = new BooleanQuery();
1218:
1219: LuceneUtil.addExactTerm(searchQuery, "tag", tag);
1220:
1221: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1222: }
1223:
1224: if (Validator.isNotNull(repositoryURL)) {
1225: BooleanQuery searchQuery = new BooleanQuery();
1226:
1227: Query query = new TermQuery(new Term("repositoryURL",
1228: repositoryURL));
1229:
1230: searchQuery.add(query, BooleanClause.Occur.SHOULD);
1231:
1232: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1233: }
1234:
1235: if (Validator.isNotNull(license)) {
1236: BooleanQuery searchQuery = new BooleanQuery();
1237:
1238: LuceneUtil
1239: .addExactTerm(searchQuery, "license", license);
1240:
1241: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1242: }
1243:
1244: if (Validator.isNotNull(status) && !status.equals("all")) {
1245: BooleanQuery searchQuery = new BooleanQuery();
1246:
1247: if (status
1248: .equals(PluginPackageImpl.STATUS_NOT_INSTALLED_OR_OLDER_VERSION_INSTALLED)) {
1249:
1250: LuceneUtil.addExactTerm(searchQuery, "status",
1251: PluginPackageImpl.STATUS_NOT_INSTALLED);
1252: LuceneUtil
1253: .addExactTerm(
1254: searchQuery,
1255: "status",
1256: PluginPackageImpl.STATUS_OLDER_VERSION_INSTALLED);
1257: } else {
1258: LuceneUtil.addExactTerm(searchQuery, "status",
1259: status);
1260: }
1261:
1262: fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
1263: }
1264:
1265: searcher = LuceneUtil.getSearcher(CompanyImpl.SYSTEM);
1266:
1267: hits.recordHits(searcher.search(fullQuery), searcher);
1268:
1269: return hits;
1270: } catch (Exception e) {
1271: return LuceneUtil.closeSearcher(searcher, keywords, e);
1272: }
1273: }
1274:
1275: private void _unregisterInstalledPluginPackage(
1276: PluginPackage pluginPackage) {
1277:
1278: _installedPluginPackages.removePluginPackage(pluginPackage);
1279:
1280: try {
1281: List pluginPackages = _getAvailablePluginPackages(
1282: pluginPackage.getGroupId(), pluginPackage
1283: .getArtifactId());
1284:
1285: Iterator itr = pluginPackages.iterator();
1286:
1287: while (itr.hasNext()) {
1288: PluginPackage availablePackage = (PluginPackage) itr
1289: .next();
1290:
1291: _indexPluginPackage(availablePackage);
1292: }
1293: } catch (PluginPackageException ppe) {
1294: if (_log.isWarnEnabled()) {
1295: _log.warn("Unable to reindex unistalled package "
1296: + pluginPackage.getContext(), ppe);
1297: }
1298: }
1299: }
1300:
1301: private void _updateInstallingPluginPackage(
1302: String preliminaryContext, PluginPackage pluginPackage) {
1303:
1304: _installedPluginPackages
1305: .unregisterPluginPackageInstallation(preliminaryContext);
1306: _installedPluginPackages
1307: .registerPluginPackageInstallation(pluginPackage);
1308: }
1309:
1310: private static Log _log = LogFactory
1311: .getLog(PluginPackageUtil.class);
1312:
1313: private static PluginPackageUtil _instance = new PluginPackageUtil();
1314:
1315: private LocalPluginPackageRepository _installedPluginPackages;
1316: private Map _repositoryCache;
1317: private Set _availableTagsCache;
1318: private Date _lastUpdateDate;
1319: private Boolean _updateAvailable;
1320: private boolean _settingUpdateAvailable;
1321:
1322: private class UpdateAvailableRunner implements Runnable {
1323:
1324: public void run() {
1325: try {
1326: setUpdateAvailable();
1327: } catch (Exception e) {
1328: _log.error(e, e);
1329: }
1330: }
1331:
1332: protected void setUpdateAvailable() throws Exception {
1333: StopWatch stopWatch = null;
1334:
1335: if (_log.isInfoEnabled()) {
1336: _log.info("Checking for available updates");
1337:
1338: stopWatch = new StopWatch();
1339:
1340: stopWatch.start();
1341: }
1342:
1343: Iterator itr = _installedPluginPackages.getPluginPackages()
1344: .iterator();
1345:
1346: while (itr.hasNext()) {
1347: PluginPackage pluginPackage = (PluginPackage) itr
1348: .next();
1349:
1350: PluginPackage availablePluginPackage = null;
1351:
1352: if (_isIgnored(pluginPackage)) {
1353: continue;
1354: }
1355:
1356: availablePluginPackage = PluginPackageUtil
1357: .getLatestAvailablePluginPackage(pluginPackage
1358: .getGroupId(), pluginPackage
1359: .getArtifactId());
1360:
1361: if (availablePluginPackage == null) {
1362: continue;
1363: }
1364:
1365: Version availablePluginPackageVersion = Version
1366: .getInstance(availablePluginPackage
1367: .getVersion());
1368:
1369: if (availablePluginPackageVersion
1370: .isLaterVersionThan(pluginPackage.getVersion())) {
1371:
1372: _updateAvailable = Boolean.TRUE;
1373:
1374: break;
1375: }
1376: }
1377:
1378: if (_updateAvailable == null) {
1379: _updateAvailable = Boolean.FALSE;
1380: }
1381:
1382: _settingUpdateAvailable = false;
1383:
1384: if (_log.isInfoEnabled()) {
1385: _log.info("Finished checking for available updates in "
1386: + stopWatch.getTime() + " ms");
1387: }
1388: }
1389: }
1390:
1391: }
|