com.liferay.marketplace.service.impl.AppLocalServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.marketplace.service.impl.AppLocalServiceImpl.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.marketplace.service.impl;

import com.liferay.marketplace.AppPropertiesException;
import com.liferay.marketplace.AppTitleException;
import com.liferay.marketplace.AppVersionException;
import com.liferay.marketplace.model.App;
import com.liferay.marketplace.model.Module;
import com.liferay.marketplace.service.base.AppLocalServiceBaseImpl;
import com.liferay.marketplace.util.BundleUtil;
import com.liferay.marketplace.util.comparator.AppTitleComparator;
import com.liferay.portal.kernel.deploy.DeployManagerUtil;
import com.liferay.portal.kernel.deploy.auto.context.AutoDeploymentContext;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.plugin.PluginPackage;
import com.liferay.portal.kernel.servlet.ServletContextPool;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.ListUtil;
import com.liferay.portal.kernel.util.PropertiesUtil;
import com.liferay.portal.kernel.util.ReleaseInfo;
import com.liferay.portal.kernel.util.StreamUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.model.CompanyConstants;
import com.liferay.portal.model.User;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portlet.documentlibrary.NoSuchFileException;
import com.liferay.portlet.documentlibrary.store.DLStoreUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import javax.servlet.ServletContext;

/**
 * @author Ryan Park
 * @author Joan Kim
 */
public class AppLocalServiceImpl extends AppLocalServiceBaseImpl {

    @Override
    public void clearInstalledAppsCache() {
        _bundledApps = null;
        _installedApps = null;
    }

    @Override
    public App deleteApp(App app) {

        // App

        clearInstalledAppsCache();

        appPersistence.remove(app);

        // Module

        List<Module> modules = modulePersistence.findByAppId(app.getAppId());

        for (Module module : modules) {
            moduleLocalService.deleteModule(module);
        }

        // File

        try {
            DLStoreUtil.deleteFile(app.getCompanyId(), CompanyConstants.SYSTEM, app.getFilePath());
        } catch (Exception e) {
            if (_log.isWarnEnabled()) {
                _log.warn(e, e);
            }
        }

        return app;
    }

    @Override
    public App deleteApp(long appId) throws PortalException {
        App app = appPersistence.findByPrimaryKey(appId);

        return deleteApp(app);
    }

    @Override
    public App fetchRemoteApp(long remoteAppId) {
        return appPersistence.fetchByRemoteAppId(remoteAppId);
    }

    @Override
    public List<App> getApps(String category) {
        return appPersistence.findByCategory(category);
    }

    @Override
    public Map<String, String> getBundledApps() {
        if (_bundledApps != null) {
            return _bundledApps;
        }

        Map<String, String> bundledApps = new HashMap<String, String>();

        List<PluginPackage> pluginPackages = DeployManagerUtil.getInstalledPluginPackages();

        for (PluginPackage pluginPackage : pluginPackages) {
            ServletContext servletContext = ServletContextPool.get(pluginPackage.getContext());

            InputStream inputStream = null;

            try {
                inputStream = servletContext.getResourceAsStream("/WEB-INF/liferay-releng.changelog.md5");

                if (inputStream == null) {
                    continue;
                }

                String relengHash = StringUtil.read(inputStream);

                if (Validator.isNotNull(relengHash)) {
                    bundledApps.put(pluginPackage.getContext(), relengHash);
                }
            } catch (Exception e) {
                if (_log.isWarnEnabled()) {
                    _log.warn("Unable to read plugin package MD5 checksum for " + pluginPackage.getContext());
                }
            } finally {
                StreamUtil.cleanUp(inputStream);
            }
        }

        _bundledApps = bundledApps;

        return _bundledApps;
    }

    @Override
    public List<App> getInstalledApps() {
        if (_installedApps != null) {
            return _installedApps;
        }

        List<App> installedApps = new ArrayList<App>();

        // Core app

        App coreApp = appPersistence.create(0);

        coreApp.setTitle("Liferay Core");
        coreApp.setDescription("Plugins bundled with Liferay Portal.");
        coreApp.setVersion(ReleaseInfo.getVersion());

        coreApp.addContextName(PortalUtil.getPathContext());

        installedApps.add(coreApp);

        // Deployed apps

        List<PluginPackage> pluginPackages = DeployManagerUtil.getInstalledPluginPackages();

        for (PluginPackage pluginPackage : pluginPackages) {
            List<Module> modules = modulePersistence.findByContextName(pluginPackage.getContext());

            boolean installedApp = false;

            for (Module module : modules) {
                App app = appPersistence.fetchByPrimaryKey(module.getAppId());

                if ((app != null) && app.isInstalled()) {
                    installedApp = true;

                    break;
                }
            }

            if (installedApp) {
                continue;
            }

            App app = appPersistence.create(0);

            app.setTitle(pluginPackage.getName());
            app.setDescription(pluginPackage.getLongDescription());
            app.setVersion(pluginPackage.getVersion());

            app.addContextName(pluginPackage.getContext());

            installedApps.add(app);
        }

        // Marketplace apps

        List<App> apps = appPersistence.findAll();

        for (App app : apps) {
            if (app.isInstalled()) {
                installedApps.add(app);
            }
        }

        installedApps = ListUtil.sort(installedApps, new AppTitleComparator());

        _installedApps = installedApps;

        return _installedApps;
    }

    @Override
    public void installApp(long remoteAppId) throws PortalException {
        App app = appPersistence.findByRemoteAppId(remoteAppId);

        if (!DLStoreUtil.hasFile(app.getCompanyId(), CompanyConstants.SYSTEM, app.getFilePath())) {

            throw new NoSuchFileException();
        }

        String tmpDir = SystemProperties.get(SystemProperties.TMP_DIR) + StringPool.SLASH + Time.getTimestamp();

        InputStream inputStream = null;

        ZipFile zipFile = null;

        try {
            inputStream = DLStoreUtil.getFileAsStream(app.getCompanyId(), CompanyConstants.SYSTEM,
                    app.getFilePath());

            if (inputStream == null) {
                throw new IOException("Unable to open file at " + app.getFilePath());
            }

            File liferayPackageFile = FileUtil.createTempFile(inputStream);

            zipFile = new ZipFile(liferayPackageFile);

            Enumeration<ZipEntry> enu = (Enumeration<ZipEntry>) zipFile.entries();

            while (enu.hasMoreElements()) {
                ZipEntry zipEntry = enu.nextElement();

                String fileName = zipEntry.getName();

                if (!fileName.endsWith(".jar") && !fileName.endsWith(".war") && !fileName.endsWith(".xml")
                        && !fileName.endsWith(".zip") && !fileName.equals("liferay-marketplace.properties")) {

                    continue;
                }

                if (_log.isInfoEnabled()) {
                    _log.info("Extracting " + fileName + " from app " + app.getAppId());
                }

                InputStream zipInputStream = null;

                try {
                    zipInputStream = zipFile.getInputStream(zipEntry);

                    if (fileName.equals("liferay-marketplace.properties")) {
                        String propertiesString = StringUtil.read(zipInputStream);

                        Properties properties = PropertiesUtil.load(propertiesString);

                        processMarketplaceProperties(properties);
                    } else {
                        File pluginPackageFile = new File(tmpDir + StringPool.SLASH + fileName);

                        FileUtil.write(pluginPackageFile, zipInputStream);

                        String bundleSymbolicName = StringPool.BLANK;
                        String bundleVersion = StringPool.BLANK;
                        String contextName = StringPool.BLANK;

                        AutoDeploymentContext autoDeploymentContext = new AutoDeploymentContext();

                        if (fileName.endsWith(".jar")) {
                            Manifest manifest = BundleUtil.getManifest(pluginPackageFile);

                            Attributes attributes = manifest.getMainAttributes();

                            bundleSymbolicName = GetterUtil.getString(attributes.getValue("Bundle-SymbolicName"));
                            bundleVersion = GetterUtil.getString(attributes.getValue("Bundle-Version"));
                            contextName = GetterUtil.getString(attributes.getValue("Web-ContextPath"));
                        } else {
                            contextName = getContextName(fileName);

                            autoDeploymentContext.setContext(contextName);
                        }

                        autoDeploymentContext.setFile(pluginPackageFile);

                        DeployManagerUtil.deploy(autoDeploymentContext);

                        if (Validator.isNotNull(bundleSymbolicName) || Validator.isNotNull(contextName)) {

                            moduleLocalService.addModule(app.getUserId(), app.getAppId(), bundleSymbolicName,
                                    bundleVersion, contextName);
                        }
                    }
                } finally {
                    StreamUtil.cleanUp(zipInputStream);
                }
            }
        } catch (ZipException ze) {
            if (_log.isInfoEnabled()) {
                _log.info("Deleting corrupt package from app " + app.getAppId(), ze);
            }

            deleteApp(app);
        } catch (IOException ioe) {
            throw new PortalException(ioe.getMessage());
        } catch (Exception e) {
            _log.error(e, e);
        } finally {
            FileUtil.deltree(tmpDir);

            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException ioe) {
                }
            }

            StreamUtil.cleanUp(inputStream);

            clearInstalledAppsCache();
        }
    }

    @Override
    public void processMarketplaceProperties(Properties properties) throws PortalException {

        long[] supersedesRemoteAppIds = StringUtil.split(properties.getProperty("supersedes-remote-app-ids"), 0L);

        for (long supersedesRemoteAppId : supersedesRemoteAppIds) {
            App supersedesApp = appPersistence.fetchByRemoteAppId(supersedesRemoteAppId);

            if ((supersedesApp != null) && supersedesApp.isInstalled()) {
                uninstallApp(supersedesRemoteAppId);
            }
        }
    }

    @Override
    public void uninstallApp(long remoteAppId) throws PortalException {
        clearInstalledAppsCache();

        App app = appPersistence.findByRemoteAppId(remoteAppId);

        List<Module> modules = modulePersistence.findByAppId(app.getAppId());

        for (Module module : modules) {
            moduleLocalService.deleteModule(module.getModuleId());

            if (Validator.isNotNull(module.getBundleSymbolicName())
                    && Validator.isNotNull(module.getBundleVersion())) {

                BundleUtil.uninstallBundle(module.getBundleSymbolicName(), module.getBundleVersion());

                continue;
            }

            if (hasDependentApp(module)) {
                continue;
            }

            try {
                DeployManagerUtil.undeploy(module.getContextName());
            } catch (Exception e) {
                _log.error(e, e);
            }
        }
    }

    @Override
    public App updateApp(long userId, long remoteAppId, String version, File file) throws PortalException {

        Properties properties = getMarketplaceProperties(file);

        if (properties == null) {
            throw new AppPropertiesException("Unable to read liferay-marketplace.properties");
        }

        String title = properties.getProperty("title");
        String description = properties.getProperty("description");
        String category = properties.getProperty("category");
        String iconURL = properties.getProperty("icon-url");

        return updateApp(userId, remoteAppId, title, description, category, iconURL, version, file);
    }

    @Override
    public App updateApp(long userId, long remoteAppId, String title, String description, String category,
            String iconURL, String version, File file) throws PortalException {

        // App

        User user = userPersistence.fetchByPrimaryKey(userId);
        Date now = new Date();

        validate(title, version);

        App app = appPersistence.fetchByRemoteAppId(remoteAppId);

        if (app == null) {
            long appId = counterLocalService.increment();

            app = appPersistence.create(appId);
        }

        if (user != null) {
            app.setCompanyId(user.getCompanyId());
            app.setUserId(user.getUserId());
            app.setUserName(user.getFullName());
        }

        app.setCreateDate(now);
        app.setModifiedDate(now);
        app.setRemoteAppId(remoteAppId);
        app.setTitle(title);
        app.setDescription(description);
        app.setCategory(category);
        app.setIconURL(iconURL);
        app.setVersion(version);

        appPersistence.update(app);

        // File

        if (file != null) {
            try {
                DLStoreUtil.deleteFile(app.getCompanyId(), CompanyConstants.SYSTEM, app.getFilePath());
            } catch (Exception e) {
            }

            DLStoreUtil.addFile(app.getCompanyId(), CompanyConstants.SYSTEM, app.getFilePath(), false, file);
        }

        clearInstalledAppsCache();

        return app;
    }

    protected String getContextName(String fileName) {
        String context = fileName;

        while (context.contains(StringPool.DASH)) {
            if (context.endsWith("-ext") || context.endsWith("-hook") || context.endsWith("-layouttpl")
                    || context.endsWith("-portlet") || context.endsWith("-theme") || context.endsWith("-web")) {

                return context;
            }

            int pos = context.lastIndexOf(StringPool.DASH);

            if (pos > 0) {
                context = context.substring(0, pos);
            } else {
                break;
            }
        }

        return fileName;
    }

    protected Properties getMarketplaceProperties(File liferayPackageFile) {
        InputStream inputStream = null;
        ZipFile zipFile = null;

        try {
            zipFile = new ZipFile(liferayPackageFile);

            ZipEntry zipEntry = zipFile.getEntry("liferay-marketplace.properties");

            inputStream = zipFile.getInputStream(zipEntry);

            String propertiesString = StringUtil.read(inputStream);

            return PropertiesUtil.load(propertiesString);
        } catch (IOException ioe) {
            return null;
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException ioe) {
                }
            }

            StreamUtil.cleanUp(inputStream);
        }
    }

    protected boolean hasDependentApp(Module module) throws PortalException {
        List<Module> modules = modulePersistence.findByContextName(module.getContextName());

        for (Module curModule : modules) {
            App app = appPersistence.findByPrimaryKey(curModule.getAppId());

            if (curModule.getAppId() == module.getAppId()) {
                continue;
            }

            if (app.isInstalled()) {
                return true;
            }
        }

        return false;
    }

    protected void validate(String title, String version) throws PortalException {

        if (Validator.isNull(title)) {
            throw new AppTitleException();
        }

        if (Validator.isNull(version)) {
            throw new AppVersionException();
        }
    }

    private static Log _log = LogFactoryUtil.getLog(AppLocalServiceImpl.class);

    private Map<String, String> _bundledApps;
    private List<App> _installedApps;

}