OSDN Git Service

first commit
[japandigitalstudio/build-jds.git] / bundles.plugins.engine.src.org.bonitasoft.studio.engine.BOSEngineManager.java
1 /**
2  * Copyright (C) 2012-2015 Bonitasoft S.A.
3  * Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2.0 of the License, or
7  * (at your option) any later version.
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  */
15 package org.bonitasoft.studio.engine;
16
17 import static java.util.Objects.requireNonNull;
18
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.Optional;
24
25 import org.bonitasoft.engine.api.ApplicationAPI;
26 import org.bonitasoft.engine.api.CommandAPI;
27 import org.bonitasoft.engine.api.IdentityAPI;
28 import org.bonitasoft.engine.api.LoginAPI;
29 import org.bonitasoft.engine.api.PageAPI;
30 import org.bonitasoft.engine.api.PlatformAPI;
31 import org.bonitasoft.engine.api.PlatformAPIAccessor;
32 import org.bonitasoft.engine.api.ProcessAPI;
33 import org.bonitasoft.engine.api.ProfileAPI;
34 import org.bonitasoft.engine.api.TenantAPIAccessor;
35 import org.bonitasoft.engine.api.TenantAdministrationAPI;
36 import org.bonitasoft.engine.exception.BonitaHomeNotSetException;
37 import org.bonitasoft.engine.exception.ServerAPIException;
38 import org.bonitasoft.engine.exception.UnknownAPITypeException;
39 import org.bonitasoft.engine.exception.UpdateException;
40 import org.bonitasoft.engine.platform.LoginException;
41 import org.bonitasoft.engine.platform.PlatformLoginException;
42 import org.bonitasoft.engine.platform.PlatformLogoutException;
43 import org.bonitasoft.engine.session.APISession;
44 import org.bonitasoft.engine.session.PlatformSession;
45 import org.bonitasoft.engine.session.SessionNotFoundException;
46 import org.bonitasoft.studio.common.CommandExecutor;
47 import org.bonitasoft.studio.common.extension.BonitaStudioExtensionRegistryManager;
48 import org.bonitasoft.studio.common.log.BonitaStudioLog;
49 import org.bonitasoft.studio.common.repository.AbstractRepository;
50 import org.bonitasoft.studio.common.repository.RepositoryManager;
51 import org.bonitasoft.studio.common.repository.extension.IEngineAction;
52 import org.bonitasoft.studio.common.repository.model.IRepository;
53 import org.bonitasoft.studio.engine.export.BarExporter;
54 import org.bonitasoft.studio.engine.i18n.Messages;
55 import org.bonitasoft.studio.engine.preferences.EnginePreferenceConstants;
56 import org.bonitasoft.studio.model.configuration.Configuration;
57 import org.bonitasoft.studio.model.process.AbstractProcess;
58 import org.bonitasoft.studio.preferences.dialog.BonitaPreferenceDialog;
59 import org.bonitasoft.studio.ui.notification.BonitaNotificator;
60 import org.eclipse.core.runtime.CoreException;
61 import org.eclipse.core.runtime.IConfigurationElement;
62 import org.eclipse.core.runtime.IProgressMonitor;
63 import org.eclipse.jface.preference.IPreferenceStore;
64 import org.eclipse.swt.widgets.Display;
65 import org.eclipse.swt.widgets.Shell;
66
67 /**
68  * @author Romain Bioteau
69  */
70 public class BOSEngineManager {
71
72     public static final String CUSTOM_PERMISSIONS_MAPPING_PROPERTIES = "custom-permissions-mapping.properties";
73
74     public static final String CONSOLE_CONFIG_PROPERTIES = "console-config.properties";
75
76     private static final String POSTSTARTUP_CONTIBUTION_ID = "org.bonitasoft.studio.engine.postEngineAction";
77
78     public static final String PLATFORM_PASSWORD = "platform";
79
80     public static final String PLATFORM_USER = "platformAdmin";
81
82     public static final String BONITA_TECHNICAL_USER = "install";
83
84     public static final String BONITA_TECHNICAL_USER_PASSWORD = "install";
85
86     public static final String API_TYPE_PROPERTY_NAME = "org.bonitasoft.engine.api-type";
87
88     public static final String DEFAULT_TENANT_NAME = "default";
89
90     public static final String DEFAULT_TENANT_DESC = "The default tenant created by the Studio";
91
92     private static final String ENGINESERVERMANAGER_EXTENSION_D = "org.bonitasoft.studio.engine.bonitaEngineManager";
93
94     private static final long DEFAULT_TENANT_ID = 1;
95
96     public static final String SECURITY_CONFIG_PROPERTIES = "security-config.properties";
97
98     private static final String FIND_USER_PASSWORD_COMMAND = "org.bonitasoft.studio.actors.command.userPassword";
99
100     private static BOSEngineManager INSTANCE;
101
102     private boolean isRunning = false;
103
104     private IProgressMonitor monitor;
105
106     private CommandExecutor commandExecutor = new CommandExecutor();
107
108     protected BOSEngineManager(final IProgressMonitor monitor) {
109         if (monitor == null) {
110             this.monitor = AbstractRepository.NULL_PROGRESS_MONITOR;
111         } else {
112             this.monitor = monitor;
113         }
114     }
115
116     public static BOSEngineManager getInstance() {
117         return getInstance(null);
118     }
119
120     public static synchronized BOSEngineManager getInstance(final IProgressMonitor monitor) {
121         if (INSTANCE == null) {
122             INSTANCE = createInstance(monitor);
123         }
124         return INSTANCE;
125     }
126
127     protected static BOSEngineManager createInstance(final IProgressMonitor monitor) {
128         for (final IConfigurationElement element : BonitaStudioExtensionRegistryManager.getInstance()
129                 .getConfigurationElements(ENGINESERVERMANAGER_EXTENSION_D)) {
130             try {
131                 return (BOSEngineManager) element.createExecutableExtension("class");
132             } catch (final CoreException e) {
133                 BonitaStudioLog.error(e, EnginePlugin.PLUGIN_ID);
134             }
135         }
136
137         return new BOSEngineManager(monitor);
138     }
139
140     public synchronized void start(AbstractRepository repository) {
141         if (!isRunning() || !BOSWebServerManager.getInstance().serverIsStarted()) {
142 //            boolean notifying = notifyStartServer();
143 //            monitor.beginTask(Messages.initializingProcessEngine, IProgressMonitor.UNKNOWN);
144 //            BOSWebServerManager.getInstance().startServer(repository, monitor);
145 //            isRunning = postEngineStart(repository);
146 //            if (notifying) {
147 //                notifyServerStarted();
148 //            }
149         }
150     }
151
152     private boolean notifyStartServer() {
153         if (EngineNotificationSemaphore.getInstance().tryAcquire()) {
154             if (!isLazyModeEnabled(EnginePlugin.getDefault().getPreferenceStore())) {
155                 BonitaNotificator.openNotification(Messages.startServerNotificationTitle,
156                         Messages.engineLazyModeNotificationLink, e -> {
157                             BonitaPreferenceDialog dialog = new BonitaPreferenceDialog(new Shell(Display.getDefault()));
158                             dialog.create();
159                             dialog.setSelectedPreferencePage(BonitaPreferenceDialog.SERVER_SETTINGS_PAGE_ID);
160                             dialog.open();
161                         });
162             }
163             return true;
164         }
165         return false;
166     }
167
168     private boolean isLazyModeEnabled(IPreferenceStore preferenceStore) {
169         return preferenceStore.getBoolean(EnginePreferenceConstants.LAZYLOAD_ENGINE)
170                 || System.getProperty(EnginePreferenceConstants.LAZYLOAD_ENGINE) != null;
171     }
172
173     public synchronized void start() {
174         start(RepositoryManager.getInstance().getCurrentRepository());
175     }
176
177     protected boolean postEngineStart(IRepository repository) {
178         //RESUME ENGINE IF PAUSED AT STARTUP
179         try {
180             final APISession apiSession = getLoginAPI().login(BONITA_TECHNICAL_USER, BONITA_TECHNICAL_USER_PASSWORD);
181             final TenantAdministrationAPI tenantManagementAPI = getTenantAdministrationAPI(apiSession);
182             if (tenantManagementAPI.isPaused()) {
183                 tenantManagementAPI.resume();
184             }
185             executePostStartupContributions(repository);
186         } catch (final Exception e) {
187             return handlePostEngineStartException(e);
188         }
189         return true;
190     }
191
192     private void notifyServerStarted() {
193         BonitaNotificator.openNotification(Messages.startServerCompletedNotificationTitle,
194                 Messages.serverRunningNotificationMessage);
195         EngineNotificationSemaphore.getInstance().release();
196     }
197
198     private boolean handlePostEngineStartException(final Exception e) {
199         if (tomcatServerIsRunning()) {
200             BonitaStudioLog.error(e);
201         } else {
202             BonitaStudioLog.warning("Tomcat server has been shutdown before first start ended.", EnginePlugin.PLUGIN_ID);
203         }
204         return false;
205     }
206
207     protected boolean tomcatServerIsRunning() {
208         return BOSWebServerManager.getInstance().serverIsStarted();
209     }
210
211     public synchronized void stop() {
212         APISession session = null;
213         TenantAdministrationAPI tenantManagementAPI = null;
214         try {
215             session = loginDefaultTenant(null);
216             tenantManagementAPI = getTenantAdministrationAPI(session);
217             tenantManagementAPI.pause();
218             if (dropBusinessDataDBOnExit()) {
219                 tenantManagementAPI.cleanAndUninstallBusinessDataModel();
220             } else {
221                 tenantManagementAPI.uninstallBusinessDataModel();
222             }
223             tenantManagementAPI.resume();
224         } catch (final Exception e) {
225             BonitaStudioLog.error(e);
226         } finally {
227             if (tenantManagementAPI != null && tenantManagementAPI.isPaused()) {
228                 try {
229                     tenantManagementAPI.resume();
230                 } catch (final UpdateException e) {
231                     BonitaStudioLog.error(e);
232                 }
233             }
234             if (session != null) {
235                 logoutDefaultTenant(session);
236             }
237         }
238         if (BOSWebServerManager.getInstance().serverIsStarted()) {
239             BOSWebServerManager.getInstance().stopServer(monitor);
240         }
241         isRunning = false;
242         try {
243             BOSWebServerManager.getInstance().cleanBeforeShutdown();
244         } catch (final IOException e) {
245             BonitaStudioLog.error(e);
246         }
247     }
248
249     private boolean dropBusinessDataDBOnExit() {
250         final IPreferenceStore preferenceStore = EnginePlugin.getDefault().getPreferenceStore();
251         return preferenceStore.getBoolean(EnginePreferenceConstants.DROP_BUSINESS_DATA_DB_ON_EXIT_PREF);
252     }
253
254     protected void executePostStartupContributions(IRepository repository) throws Exception {
255         final IConfigurationElement[] elements = BonitaStudioExtensionRegistryManager.getInstance()
256                 .getConfigurationElements(POSTSTARTUP_CONTIBUTION_ID);
257         IEngineAction contrib = null;
258         for (final IConfigurationElement elem : elements) {
259             try {
260                 contrib = (IEngineAction) elem.createExecutableExtension("class"); //$NON-NLS-1$
261             } catch (final CoreException e) {
262                 BonitaStudioLog.error(e);
263             }
264             if (contrib != null && contrib.shouldRun(repository)) {
265                 final APISession session = getLoginAPI().login(BONITA_TECHNICAL_USER, BONITA_TECHNICAL_USER_PASSWORD);
266                 try {
267                     contrib.run(session,repository);
268                 } finally {
269                     if (session != null) {
270                         logoutDefaultTenant(session);
271                     }
272                 }
273             }
274         }
275
276     }
277
278     public boolean isRunning() {
279         return isRunning;
280     }
281
282     public ProcessAPI getProcessAPI(final APISession session) {
283         try {
284             return TenantAPIAccessor.getProcessAPI(session);
285         } catch (final Exception e) {
286             BonitaStudioLog.error(e);
287         }
288         return null;
289     }
290
291     protected LoginAPI getLoginAPI() throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
292         return TenantAPIAccessor.getLoginAPI();
293     }
294
295     public APISession loginDefaultTenant(final IProgressMonitor monitor)
296             throws LoginException, BonitaHomeNotSetException, ServerAPIException,
297             UnknownAPITypeException {
298         return loginTenant(BONITA_TECHNICAL_USER, BONITA_TECHNICAL_USER_PASSWORD, monitor);
299     }
300
301     public APISession loginTenant(final String login, final String password, final IProgressMonitor monitor)
302             throws LoginException,
303             BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
304         if (!isRunning() && monitor != null) {
305             monitor.beginTask(Messages.waitingForEngineToStart, IProgressMonitor.UNKNOWN);
306         }
307         start();
308         BonitaStudioLog.debug("Attempt to login as " + login, EnginePlugin.PLUGIN_ID);
309         final APISession session = getLoginAPI().login(requireNonNull(login), requireNonNull(password));
310         if (session != null) {
311             BonitaStudioLog.debug("Login successful.", EnginePlugin.PLUGIN_ID);
312         }
313         return session;
314     }
315
316     public void logoutDefaultTenant(final APISession session) {
317         try {
318             getLoginAPI().logout(session);
319         } catch (final Exception e) {
320             BonitaStudioLog.error(e);
321         }
322     }
323
324     public IdentityAPI getIdentityAPI(final APISession session)
325             throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
326         return TenantAPIAccessor.getIdentityAPI(session);
327     }
328
329     public CommandAPI getCommandAPI(final APISession session)
330             throws BonitaHomeNotSetException, ServerAPIException,
331             UnknownAPITypeException {
332         return TenantAPIAccessor.getCommandAPI(session);
333     }
334
335     public ProfileAPI getProfileAPI(final APISession session)
336             throws BonitaHomeNotSetException, ServerAPIException,
337             UnknownAPITypeException {
338         return TenantAPIAccessor.getProfileAPI(session);
339     }
340
341     public PageAPI getPageAPI(final APISession session)
342             throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
343         return TenantAPIAccessor.getCustomPageAPI(session);
344     }
345
346     public ApplicationAPI getApplicationAPI(final APISession session)
347             throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
348         return TenantAPIAccessor.getLivingApplicationAPI(session);
349     }
350
351     public TenantAdministrationAPI getTenantAdministrationAPI(final APISession session)
352             throws BonitaHomeNotSetException,
353             ServerAPIException, UnknownAPITypeException {
354         return TenantAPIAccessor.getTenantAdministrationAPI(session);
355     }
356
357     public PlatformSession loginPlatform(IProgressMonitor monitor)
358             throws PlatformLoginException, BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
359         if (!isRunning() && monitor != null) {
360             monitor.beginTask(Messages.waitingForEngineToStart, IProgressMonitor.UNKNOWN);
361         }
362         start();
363         return PlatformAPIAccessor.getPlatformLoginAPI().login(PLATFORM_USER, PLATFORM_PASSWORD);
364     }
365
366     public void logoutPlatform(PlatformSession session)
367             throws PlatformLogoutException, SessionNotFoundException, BonitaHomeNotSetException, ServerAPIException,
368             UnknownAPITypeException {
369         PlatformAPIAccessor.getPlatformLoginAPI().logout(session);
370     }
371
372     public PlatformAPI getPlatformAPI(PlatformSession session)
373             throws BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException {
374         return PlatformAPIAccessor.getPlatformAPI(session);
375     }
376
377     public APISession createSession(final AbstractProcess process, final String configurationId,
378             final IProgressMonitor monitor) throws Exception {
379         final Configuration configuration = BarExporter.getInstance().getConfiguration(process, configurationId);
380         APISession session;
381         String username = configuration.getUsername();
382         String password = retrieveUserPasswordFromActiveOrga(username)
383                 .orElseThrow(() -> new Exception(
384                         String.format("Unable to retrieve the password of %s in the active organization.",
385                                 username)));
386         try {
387             session = BOSEngineManager.getInstance().loginTenant(username, password,
388                     monitor);
389         } catch (final Exception e1) {
390             throw new Exception(Messages.bind(Messages.loginFailed,
391                     new String[] { username, process.getName(),
392                             process.getVersion() }),
393                     e1);
394         }
395         if (session == null) {
396             throw new Exception(Messages.bind(Messages.loginFailed,
397                     new String[] { username, process.getName(),
398                             process.getVersion() }));
399         }
400         return session;
401     }
402
403     private Optional<String> retrieveUserPasswordFromActiveOrga(String user) {
404         Map<String, Object> parameters = new HashMap<>();
405         parameters.put("userName", user);
406         Object result = commandExecutor.executeCommand(FIND_USER_PASSWORD_COMMAND, parameters);
407         return result instanceof Optional ? (Optional<String>) result : Optional.empty();
408     }
409
410     public byte[] getTenantConfigResourceContent(String resourceName, IProgressMonitor monitor)
411             throws PlatformLoginException, BonitaHomeNotSetException, ServerAPIException, UnknownAPITypeException,
412             PlatformLogoutException, SessionNotFoundException, FileNotFoundException {
413         PlatformSession loginPlatform = null;
414         try {
415             loginPlatform = loginPlatform(monitor);
416             final PlatformAPI platformAPI = getPlatformAPI(loginPlatform);
417             final Map<Long, Map<String, byte[]>> clientTenantConfigurations = platformAPI.getClientTenantConfigurations();
418             final Map<String, byte[]> resources = clientTenantConfigurations.get(DEFAULT_TENANT_ID);
419             if (!resources.containsKey(resourceName)) {
420                 throw new FileNotFoundException(String.format("Resource %s does not exist in database.", resourceName));
421             }
422             return resources.get(resourceName);
423         } finally {
424             if (loginPlatform != null) {
425                 logoutPlatform(loginPlatform);
426             }
427         }
428     }
429
430     public void updateTenantConfigResourceContent(String resourceName, byte[] content)
431             throws PlatformLoginException, BonitaHomeNotSetException,
432             ServerAPIException, UnknownAPITypeException,
433             UpdateException, PlatformLogoutException, SessionNotFoundException {
434         PlatformSession loginPlatform = null;
435         try {
436             loginPlatform = loginPlatform(null);
437             final PlatformAPI platformAPI = getPlatformAPI(loginPlatform);
438             platformAPI.updateClientTenantConfigurationFile(DEFAULT_TENANT_ID, resourceName, content);
439         } finally {
440             if (loginPlatform != null) {
441                 logoutPlatform(loginPlatform);
442             }
443         }
444     }
445
446 }