PageRenderTime 36ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/apps/marketplace/marketplace-service/src/main/java/com/liferay/marketplace/service/impl/AppLocalServiceImpl.java

http://github.com/liferay/liferay-portal
Java | 540 lines | 384 code | 125 blank | 31 comment | 45 complexity | f53f738b74a5772f5af062b04d6dd38d MD5 | raw file
Possible License(s): LGPL-2.0
  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. package com.liferay.marketplace.service.impl;
  15. import com.liferay.document.library.kernel.exception.NoSuchFileException;
  16. import com.liferay.document.library.kernel.store.DLStoreRequest;
  17. import com.liferay.document.library.kernel.store.DLStoreUtil;
  18. import com.liferay.marketplace.exception.AppPropertiesException;
  19. import com.liferay.marketplace.exception.AppTitleException;
  20. import com.liferay.marketplace.exception.AppVersionException;
  21. import com.liferay.marketplace.internal.bundle.BundleManagerUtil;
  22. import com.liferay.marketplace.model.App;
  23. import com.liferay.marketplace.model.Module;
  24. import com.liferay.marketplace.service.ModuleLocalService;
  25. import com.liferay.marketplace.service.base.AppLocalServiceBaseImpl;
  26. import com.liferay.marketplace.util.comparator.AppTitleComparator;
  27. import com.liferay.petra.string.StringBundler;
  28. import com.liferay.petra.string.StringPool;
  29. import com.liferay.portal.aop.AopService;
  30. import com.liferay.portal.kernel.deploy.DeployManagerUtil;
  31. import com.liferay.portal.kernel.exception.PortalException;
  32. import com.liferay.portal.kernel.log.Log;
  33. import com.liferay.portal.kernel.log.LogFactoryUtil;
  34. import com.liferay.portal.kernel.model.CompanyConstants;
  35. import com.liferay.portal.kernel.model.SystemEventConstants;
  36. import com.liferay.portal.kernel.model.User;
  37. import com.liferay.portal.kernel.plugin.PluginPackage;
  38. import com.liferay.portal.kernel.systemevent.SystemEvent;
  39. import com.liferay.portal.kernel.util.FileUtil;
  40. import com.liferay.portal.kernel.util.GetterUtil;
  41. import com.liferay.portal.kernel.util.ListUtil;
  42. import com.liferay.portal.kernel.util.Portal;
  43. import com.liferay.portal.kernel.util.PropertiesUtil;
  44. import com.liferay.portal.kernel.util.ReleaseInfo;
  45. import com.liferay.portal.kernel.util.StringUtil;
  46. import com.liferay.portal.kernel.util.SystemProperties;
  47. import com.liferay.portal.kernel.util.Validator;
  48. import java.io.File;
  49. import java.io.IOException;
  50. import java.io.InputStream;
  51. import java.nio.file.Files;
  52. import java.util.ArrayList;
  53. import java.util.Date;
  54. import java.util.Dictionary;
  55. import java.util.Enumeration;
  56. import java.util.HashMap;
  57. import java.util.List;
  58. import java.util.Map;
  59. import java.util.Properties;
  60. import java.util.zip.ZipEntry;
  61. import java.util.zip.ZipFile;
  62. import org.osgi.framework.Bundle;
  63. import org.osgi.service.component.annotations.Component;
  64. import org.osgi.service.component.annotations.Reference;
  65. /**
  66. * @author Ryan Park
  67. * @author Joan Kim
  68. */
  69. @Component(
  70. property = "model.class.name=com.liferay.marketplace.model.App",
  71. service = AopService.class
  72. )
  73. public class AppLocalServiceImpl extends AppLocalServiceBaseImpl {
  74. @Override
  75. public void clearInstalledAppsCache() {
  76. _installedApps = null;
  77. _prepackagedApps = null;
  78. }
  79. @Override
  80. @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
  81. public App deleteApp(App app) {
  82. // App
  83. clearInstalledAppsCache();
  84. appPersistence.remove(app);
  85. // Module
  86. List<Module> modules = modulePersistence.findByAppId(app.getAppId());
  87. for (Module module : modules) {
  88. _moduleLocalService.deleteModule(module);
  89. }
  90. // File
  91. try {
  92. DLStoreUtil.deleteFile(
  93. app.getCompanyId(), CompanyConstants.SYSTEM, app.getFilePath());
  94. }
  95. catch (Exception exception) {
  96. if (_log.isWarnEnabled()) {
  97. _log.warn(exception, exception);
  98. }
  99. }
  100. return app;
  101. }
  102. @Override
  103. public App deleteApp(long appId) throws PortalException {
  104. App app = appPersistence.findByPrimaryKey(appId);
  105. return deleteApp(app);
  106. }
  107. @Override
  108. public App fetchRemoteApp(long remoteAppId) {
  109. return appPersistence.fetchByRemoteAppId(remoteAppId);
  110. }
  111. @Override
  112. public List<App> getApps(String category) {
  113. return appPersistence.findByCategory(category);
  114. }
  115. @Override
  116. public List<App> getInstalledApps() {
  117. if (_installedApps != null) {
  118. return _installedApps;
  119. }
  120. List<App> installedApps = new ArrayList<>();
  121. // Core app
  122. App coreApp = appPersistence.create(0);
  123. coreApp.setTitle("Liferay Core");
  124. coreApp.setDescription("Plugins bundled with Liferay Portal.");
  125. coreApp.setVersion(ReleaseInfo.getVersion());
  126. coreApp.addContextName(_portal.getServletContextName());
  127. installedApps.add(coreApp);
  128. // Deployed apps
  129. List<PluginPackage> pluginPackages =
  130. DeployManagerUtil.getInstalledPluginPackages();
  131. for (PluginPackage pluginPackage : pluginPackages) {
  132. List<Module> modules = modulePersistence.findByContextName(
  133. pluginPackage.getContext());
  134. boolean installedApp = false;
  135. for (Module module : modules) {
  136. App app = appPersistence.fetchByPrimaryKey(module.getAppId());
  137. if ((app != null) && app.isInstalled()) {
  138. installedApp = true;
  139. break;
  140. }
  141. }
  142. if (installedApp) {
  143. continue;
  144. }
  145. App app = appPersistence.create(0);
  146. app.setTitle(pluginPackage.getName());
  147. app.setDescription(pluginPackage.getLongDescription());
  148. app.setVersion(pluginPackage.getVersion());
  149. app.setRequired(true);
  150. app.addContextName(pluginPackage.getContext());
  151. installedApps.add(app);
  152. }
  153. // Marketplace apps
  154. List<App> apps = appPersistence.findAll();
  155. for (App app : apps) {
  156. if (app.isInstalled()) {
  157. installedApps.add(app);
  158. }
  159. }
  160. installedApps = ListUtil.sort(installedApps, new AppTitleComparator());
  161. _installedApps = installedApps;
  162. return _installedApps;
  163. }
  164. @Override
  165. public List<App> getInstalledApps(String category) {
  166. List<App> apps = appPersistence.findByCategory(category);
  167. List<App> installedApps = new ArrayList<>(apps.size());
  168. for (App app : apps) {
  169. if (app.isInstalled()) {
  170. installedApps.add(app);
  171. }
  172. }
  173. return installedApps;
  174. }
  175. @Override
  176. public Map<String, String> getPrepackagedApps() {
  177. if (_prepackagedApps != null) {
  178. return _prepackagedApps;
  179. }
  180. Map<String, String> prepackagedApps = new HashMap<>();
  181. List<Bundle> bundles = BundleManagerUtil.getInstalledBundles();
  182. for (Bundle bundle : bundles) {
  183. Dictionary<String, String> headers = bundle.getHeaders(
  184. StringPool.BLANK);
  185. boolean liferayRelengBundle = GetterUtil.getBoolean(
  186. headers.get("Liferay-Releng-Bundle"));
  187. if (!liferayRelengBundle) {
  188. continue;
  189. }
  190. prepackagedApps.put(
  191. bundle.getSymbolicName(), String.valueOf(bundle.getVersion()));
  192. }
  193. _prepackagedApps = prepackagedApps;
  194. return _prepackagedApps;
  195. }
  196. @Override
  197. public void installApp(long remoteAppId) throws PortalException {
  198. App app = appPersistence.findByRemoteAppId(remoteAppId);
  199. if (!DLStoreUtil.hasFile(
  200. app.getCompanyId(), CompanyConstants.SYSTEM,
  201. app.getFilePath())) {
  202. throw new NoSuchFileException();
  203. }
  204. try (InputStream inputStream = DLStoreUtil.getFileAsStream(
  205. app.getCompanyId(), CompanyConstants.SYSTEM,
  206. app.getFilePath())) {
  207. if (inputStream == null) {
  208. throw new IOException(
  209. "Unable to open file at " + app.getFilePath());
  210. }
  211. File file = new File(
  212. StringBundler.concat(
  213. SystemProperties.get(SystemProperties.TMP_DIR),
  214. StringPool.SLASH, encodeSafeFileName(app.getTitle()),
  215. StringPool.PERIOD,
  216. FileUtil.getExtension(app.getFileName())));
  217. FileUtil.write(file, inputStream);
  218. BundleManagerUtil.installLPKG(file);
  219. }
  220. catch (IOException ioException) {
  221. throw new PortalException(ioException);
  222. }
  223. catch (Exception exception) {
  224. _log.error(exception, exception);
  225. }
  226. finally {
  227. clearInstalledAppsCache();
  228. }
  229. }
  230. @Override
  231. public void uninstallApp(long remoteAppId) throws PortalException {
  232. clearInstalledAppsCache();
  233. App app = appPersistence.findByRemoteAppId(remoteAppId);
  234. List<Module> modules = modulePersistence.findByAppId(app.getAppId());
  235. for (Module module : modules) {
  236. _moduleLocalService.deleteModule(module.getModuleId());
  237. if (module.isBundle()) {
  238. BundleManagerUtil.uninstallBundle(
  239. module.getBundleSymbolicName(), module.getBundleVersion());
  240. continue;
  241. }
  242. if (hasDependentApp(module)) {
  243. continue;
  244. }
  245. try {
  246. DeployManagerUtil.undeploy(module.getContextName());
  247. }
  248. catch (Exception exception) {
  249. _log.error(exception, exception);
  250. }
  251. }
  252. }
  253. @Override
  254. public App updateApp(long userId, File file) throws PortalException {
  255. Properties properties = getMarketplaceProperties(file);
  256. if (properties == null) {
  257. throw new AppPropertiesException(
  258. "Unable to read liferay-marketplace.properties");
  259. }
  260. long remoteAppId = GetterUtil.getLong(
  261. properties.getProperty("remote-app-id"));
  262. String title = properties.getProperty("title");
  263. String description = properties.getProperty("description");
  264. String category = properties.getProperty("category");
  265. String iconURL = properties.getProperty("icon-url");
  266. String version = properties.getProperty("version");
  267. boolean required = GetterUtil.getBoolean(
  268. properties.getProperty("required"));
  269. return updateApp(
  270. userId, remoteAppId, title, description, category, iconURL, version,
  271. required, file);
  272. }
  273. @Override
  274. public App updateApp(
  275. long userId, long remoteAppId, String title, String description,
  276. String category, String iconURL, String version, boolean required,
  277. File file)
  278. throws PortalException {
  279. // App
  280. User user = userLocalService.fetchUser(userId);
  281. Date date = new Date();
  282. validate(title, version);
  283. App app = appPersistence.fetchByRemoteAppId(remoteAppId);
  284. if (app == null) {
  285. long appId = counterLocalService.increment();
  286. app = appPersistence.create(appId);
  287. }
  288. if (user != null) {
  289. app.setCompanyId(user.getCompanyId());
  290. app.setUserId(user.getUserId());
  291. app.setUserName(user.getFullName());
  292. }
  293. app.setCreateDate(date);
  294. app.setModifiedDate(date);
  295. app.setRemoteAppId(remoteAppId);
  296. app.setTitle(title);
  297. app.setDescription(description);
  298. app.setCategory(category);
  299. app.setIconURL(iconURL);
  300. app.setVersion(version);
  301. app.setRequired(required);
  302. app = appPersistence.update(app);
  303. // File
  304. if (file != null) {
  305. try {
  306. DLStoreUtil.deleteFile(
  307. app.getCompanyId(), CompanyConstants.SYSTEM,
  308. app.getFilePath());
  309. DLStoreUtil.addFile(
  310. DLStoreRequest.builder(
  311. app.getCompanyId(), CompanyConstants.SYSTEM,
  312. app.getFilePath()
  313. ).className(
  314. this
  315. ).size(
  316. Files.size(file.toPath())
  317. ).build(),
  318. file);
  319. }
  320. catch (Exception exception) {
  321. if (_log.isDebugEnabled()) {
  322. _log.debug(exception, exception);
  323. }
  324. }
  325. }
  326. clearInstalledAppsCache();
  327. return app;
  328. }
  329. protected String encodeSafeFileName(String fileName) {
  330. if (fileName == null) {
  331. return StringPool.BLANK;
  332. }
  333. fileName = FileUtil.encodeSafeFileName(fileName);
  334. return StringUtil.replace(
  335. fileName, _SAFE_FILE_NAME_1, _SAFE_FILE_NAME_2);
  336. }
  337. protected Properties getMarketplaceProperties(File liferayPackageFile) {
  338. try (ZipFile zipFile = new ZipFile(liferayPackageFile)) {
  339. ZipEntry zipEntry = zipFile.getEntry(
  340. "liferay-marketplace.properties");
  341. if (zipEntry == null) {
  342. Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
  343. ZipEntry subsystemZipEntry = enumeration.nextElement();
  344. if (StringUtil.endsWith(subsystemZipEntry.getName(), ".lpkg")) {
  345. File file = null;
  346. try (InputStream subsystemInputStream =
  347. zipFile.getInputStream(subsystemZipEntry)) {
  348. file = FileUtil.createTempFile(subsystemInputStream);
  349. return getMarketplaceProperties(file);
  350. }
  351. finally {
  352. FileUtil.delete(file);
  353. }
  354. }
  355. return null;
  356. }
  357. try (InputStream inputStream = zipFile.getInputStream(zipEntry)) {
  358. String propertiesString = StringUtil.read(inputStream);
  359. return PropertiesUtil.load(propertiesString);
  360. }
  361. }
  362. catch (IOException ioException) {
  363. if (_log.isDebugEnabled()) {
  364. _log.debug(ioException, ioException);
  365. }
  366. return null;
  367. }
  368. }
  369. protected boolean hasDependentApp(Module module) throws PortalException {
  370. List<Module> modules = modulePersistence.findByContextName(
  371. module.getContextName());
  372. for (Module curModule : modules) {
  373. if (curModule.getAppId() == module.getAppId()) {
  374. continue;
  375. }
  376. App app = appPersistence.findByPrimaryKey(curModule.getAppId());
  377. if (app.isInstalled()) {
  378. return true;
  379. }
  380. }
  381. return false;
  382. }
  383. protected void validate(String title, String version)
  384. throws PortalException {
  385. if (Validator.isNull(title)) {
  386. throw new AppTitleException();
  387. }
  388. if (Validator.isNull(version)) {
  389. throw new AppVersionException();
  390. }
  391. }
  392. /**
  393. * @see com.liferay.portal.util.FileImpl#_SAFE_FILE_NAME_1
  394. */
  395. private static final String[] _SAFE_FILE_NAME_1 = {
  396. StringPool.BACK_SLASH, StringPool.COLON, StringPool.GREATER_THAN,
  397. StringPool.LESS_THAN, StringPool.PIPE, StringPool.QUESTION,
  398. StringPool.QUOTE, StringPool.SLASH, StringPool.STAR
  399. };
  400. /**
  401. * @see com.liferay.portal.util.FileImpl#_SAFE_FILE_NAME_2
  402. */
  403. private static final String[] _SAFE_FILE_NAME_2 = {
  404. "_BSL_", "_COL_", "_GT_", "_LT_", "_PIP_", "_QUE_", "_QUO_", "_SL_",
  405. "_ST_"
  406. };
  407. private static final Log _log = LogFactoryUtil.getLog(
  408. AppLocalServiceImpl.class);
  409. private List<App> _installedApps;
  410. @Reference
  411. private ModuleLocalService _moduleLocalService;
  412. @Reference
  413. private Portal _portal;
  414. private Map<String, String> _prepackagedApps;
  415. }