Commit be2d294f authored by Adrien's avatar Adrien Committed by Romain Bioteau

feat(la) deploy application menu (#852)

* A deploy menu is now available in all Bonita editions
* In community & teamwork, it doesn't deploy dependencies
* Files with xsd errors can't be deployed

closes [BS-17478](https://bonitasoft.atlassian.net/browse/BS-17478)
parent 3eb95a80
......@@ -24,13 +24,20 @@ Require-Bundle: org.bonitasoft.studio.common.repository;bundle-version="7.5.0",
assertj-core;bundle-version="3.6.1";resolution:=optional,
org.mockito;bundle-version="1.10.19";resolution:=optional,
org.eclipse.jface.text,
org.bonitasoft.studio.actors
org.bonitasoft.studio.actors,
org.bonitasoft.studio.engine
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.bonitasoft.engine.business.application,
Import-Package: org.bonitasoft.engine.api,
org.bonitasoft.engine.bpm,
org.bonitasoft.engine.business.application,
org.bonitasoft.engine.business.application.exporter,
org.bonitasoft.engine.business.application.xml,
org.bonitasoft.engine.exception,
org.bonitasoft.engine.profile,
org.bonitasoft.engine.profile.xml,
org.bonitasoft.engine.search,
org.bonitasoft.engine.search.impl,
org.bonitasoft.engine.session,
org.eclipse.ui.forms.editor
Bundle-ActivationPolicy: lazy
Export-Package: org.bonitasoft.studio.la,
......
<?xml version="1.0" encoding="ASCII"?>
<fragment:ModelFragments xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:commands="http://www.eclipse.org/ui/2010/UIModel/application/commands" xmlns:fragment="http://www.eclipse.org/ui/2010/UIModel/fragment" xmi:id="_jKdtYNKdEeaEE_Umqe0dXA">
<fragments xsi:type="fragment:StringModelFragment" xmi:id="_tWbyINKdEeaEE_Umqe0dXA" featurename="commands" parentElementId="org.eclipse.e4.legacy.ide.application">
<elements xsi:type="commands:Command" xmi:id="_0n838NKdEeaEE_Umqe0dXA" elementId="org.bonitasoft.studio.la.new.command" commandName="%newApplication"/>
<elements xsi:type="commands:Command" xmi:id="_pL3WsPnPEea-3Os5NcIV0g" elementId="org.bonitasoft.studio.la.deploy.command" commandName="%deployApplication"/>
<elements xsi:type="commands:Command" xmi:id="_dHtcoP3SEeanhv23kWy-6w" elementId="org.bonitasoft.studio.la.open.command" commandName="%openApplication"/>
<elements xsi:type="commands:Command" xmi:id="_2helYP6PEeaqYIbFhsSGFw" elementId="org.bonitasoft.studio.la.delete.command" commandName="%deleteApplication"/>
<elements xsi:type="commands:Command" xmi:id="_YHf6AAomEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.export.command" commandName="%exportApplication"/>
<elements xsi:type="commands:Command" xmi:id="_g4OJ8ApAEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.import.command" commandName="%importApplication"/>
</fragments>
<fragments xsi:type="fragment:StringModelFragment" xmi:id="_--2aUNKdEeaEE_Umqe0dXA" featurename="handlers" parentElementId="org.eclipse.e4.legacy.ide.application">
<elements xsi:type="commands:Handler" xmi:id="_BKi10NKeEeaEE_Umqe0dXA" elementId="org.bonitasoft.studio.la.newHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.NewApplicationHandler" command="_0n838NKdEeaEE_Umqe0dXA"/>
<elements xsi:type="commands:Handler" xmi:id="_jUDDEP3SEeanhv23kWy-6w" elementId="org.bonitasoft.studio.la.openHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.OpenApplicationHandler" command="_dHtcoP3SEeanhv23kWy-6w"/>
<elements xsi:type="commands:Handler" xmi:id="_57EXYP6PEeaqYIbFhsSGFw" elementId="org.bonitasoft.studio.la.deleteHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.DeleteApplicationHandler" command="_2helYP6PEeaqYIbFhsSGFw"/>
<elements xsi:type="commands:Handler" xmi:id="_cIN9cAomEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.exportHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.ExportApplicationHandler" command="_YHf6AAomEeekfeZYiUbzLg"/>
<elements xsi:type="commands:Handler" xmi:id="_kWFX8ApAEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.importHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.ImportApplicationhandler" command="_g4OJ8ApAEeekfeZYiUbzLg"/>
</fragments>
</fragment:ModelFragments>
<?xml version="1.0" encoding="ASCII"?>
<fragment:ModelFragments xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:commands="http://www.eclipse.org/ui/2010/UIModel/application/commands" xmlns:fragment="http://www.eclipse.org/ui/2010/UIModel/fragment" xmi:id="_jKdtYNKdEeaEE_Umqe0dXA">
<fragments xsi:type="fragment:StringModelFragment" xmi:id="_tWbyINKdEeaEE_Umqe0dXA" featurename="commands" parentElementId="org.eclipse.e4.legacy.ide.application">
<elements xsi:type="commands:Command" xmi:id="_0n838NKdEeaEE_Umqe0dXA" elementId="org.bonitasoft.studio.la.new.command" commandName="%newApplication"/>
<elements xsi:type="commands:Command" xmi:id="_dHtcoP3SEeanhv23kWy-6w" elementId="org.bonitasoft.studio.la.open.command" commandName="%openApplication"/>
<elements xsi:type="commands:Command" xmi:id="_2helYP6PEeaqYIbFhsSGFw" elementId="org.bonitasoft.studio.la.delete.command" commandName="%deleteApplication"/>
<elements xsi:type="commands:Command" xmi:id="_YHf6AAomEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.export.command" commandName="%exportApplication"/>
<elements xsi:type="commands:Command" xmi:id="_g4OJ8ApAEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.import.command" commandName="%importApplication"/>
<elements xsi:type="commands:Command" xmi:id="_pL3WsPnPEea-3Os5NcIV0g" elementId="org.bonitasoft.studio.la.deploy.command" commandName="%deployApplication"/>
</fragments>
<fragments xsi:type="fragment:StringModelFragment" xmi:id="_--2aUNKdEeaEE_Umqe0dXA" featurename="handlers" parentElementId="org.eclipse.e4.legacy.ide.application">
<elements xsi:type="commands:Handler" xmi:id="_BKi10NKeEeaEE_Umqe0dXA" elementId="org.bonitasoft.studio.la.newHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.NewApplicationHandler" command="_0n838NKdEeaEE_Umqe0dXA"/>
<elements xsi:type="commands:Handler" xmi:id="_jUDDEP3SEeanhv23kWy-6w" elementId="org.bonitasoft.studio.la.openHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.OpenApplicationHandler" command="_dHtcoP3SEeanhv23kWy-6w"/>
<elements xsi:type="commands:Handler" xmi:id="_57EXYP6PEeaqYIbFhsSGFw" elementId="org.bonitasoft.studio.la.deleteHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.DeleteApplicationHandler" command="_2helYP6PEeaqYIbFhsSGFw"/>
<elements xsi:type="commands:Handler" xmi:id="_cIN9cAomEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.exportHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.ExportApplicationHandler" command="_YHf6AAomEeekfeZYiUbzLg"/>
<elements xsi:type="commands:Handler" xmi:id="_kWFX8ApAEeekfeZYiUbzLg" elementId="org.bonitasoft.studio.la.importHandler" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.ImportApplicationhandler" command="_g4OJ8ApAEeekfeZYiUbzLg"/>
<elements xsi:type="commands:Handler" xmi:id="_JVGowM6fEee2rb_HhIZr1w" elementId="org.bonitasoft.studio.la.handler.deployapplication" contributionURI="bundleclass://org.bonitasoft.studio.la/org.bonitasoft.studio.la.application.handler.DeployApplicationHandler" command="_pL3WsPnPEea-3Os5NcIV0g"/>
</fragments>
</fragment:ModelFragments>
......@@ -33,4 +33,12 @@ applicationInfo=An application file contains one or several application descript
applicationDetails=Application descriptors hold meta data about the application (url token, name, version, user profile), but also its navigation,\nas well as links to the pages it needs to access.\nThey were created in the Portal prior to Bonita 7.5 and are now handled in the Studio to ease packaging and deployment.\nThe Studio is not aware of what is created in the Portal, so deploying an application descriptor may overwrite some Portal content.
exportApplicationDescriptorTitle=Export
exportApplicationDescriptorMessage=You are about to export an application descriptor file.\nApplication(s) REST API extensions, pages and profiles are not part of the file. \nMake sure they are already installed before you import this file in the Portal.
menuLevelWarning=Level 2+ menus are not supported by the default layout page
\ No newline at end of file
unparsableXmlFile=Unable to parse xml
menuLevelWarning=Level 2+ menus are not supported by the default layout page
applicationDescriptorDeployed='%s' Application Descriptor deployed
deployExistingApplication=Deploy an existing application descriptor
selectApplicationToDeploy=Select an application descriptor to deploy.
deployDoneTitle=Deploy status
deployDoneMessage=Deploy status below:
deployFailedTitle=Deploy failed
deploy=Deploy
\ No newline at end of file
......@@ -4,4 +4,5 @@ applicationMenuLabel=Application Descriptor
ApplicationPerspective=Application Development Perspective
deleteApplication=Delete...
exportApplication=Export...
importApplication=Import...
\ No newline at end of file
importApplication=Import...
deployApplication=Deploy...
\ No newline at end of file
......@@ -46,6 +46,14 @@
commandId="org.bonitasoft.studio.la.import.command"
style="push">
</command>
<separator
name="org.bonitasoft.studio.la.separator.deploy"
visible="true">
</separator>
<command
commandId="org.bonitasoft.studio.la.deploy.command"
style="push">
</command>
</menu>
</menuContribution>
......
/**
* Copyright (C) 2017 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
import static org.bonitasoft.engine.business.application.xml.ApplicationNodeBuilder.newApplication;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.bonitasoft.engine.api.ApplicationAPI;
import org.bonitasoft.engine.business.application.Application;
import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.search.SearchOptions;
import org.bonitasoft.engine.search.SearchOptionsBuilder;
import org.bonitasoft.engine.search.SearchResult;
import org.bonitasoft.engine.search.impl.SearchResultImpl;
import org.bonitasoft.studio.assertions.StatusAssert;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class DeleteApplicationRunnableTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void should_delete_application_by_token() throws Exception {
final ApplicationAPI applicationAPI = mock(ApplicationAPI.class);
final Application application1 = applicationWithId(1);
final Application application2 = applicationWithId(2);
when(applicationAPI.searchApplications(notNull(SearchOptions.class)))
.thenReturn(searchResult(Collections.emptyList()));
when(applicationAPI.searchApplications(eq(withToken("myApp1"))))
.thenReturn(searchResult(Arrays.asList(application1)));
when(applicationAPI.searchApplications(eq(withToken("myApp2"))))
.thenReturn(searchResult(Arrays.asList(application2)));
final DeleteApplicationRunnable operation = new DeleteApplicationRunnable(applicationAPI,
newApplication("myApp1", "My App", "1.0").create());
operation.run(new NullProgressMonitor());
verify(applicationAPI).deleteApplication(1);
StatusAssert.assertThat(operation.getStatus()).isOK();
}
@Test
public void should_fail_if_application_not_found() throws Exception {
final ApplicationAPI applicationAPI = mock(ApplicationAPI.class);
when(applicationAPI.searchApplications(notNull(SearchOptions.class)))
.thenReturn(searchResult(Collections.emptyList()));
final DeleteApplicationRunnable operation = new DeleteApplicationRunnable(applicationAPI,
newApplication("unknownToken", "My App 2", "1.0").create());
operation.run(new NullProgressMonitor());
verify(applicationAPI, never()).deleteApplication(anyInt());
StatusAssert.assertThat(operation.getStatus()).isNotOK();
}
@Test
public void should_not_fail_if_application_not_found_with_ignore_option() throws Exception {
final ApplicationAPI applicationAPI = mock(ApplicationAPI.class);
when(applicationAPI.searchApplications(notNull(SearchOptions.class)))
.thenReturn(searchResult(Collections.emptyList()));
final DeleteApplicationRunnable operation = new DeleteApplicationRunnable(applicationAPI,
newApplication("unknownToken", "My App 2", "1.0").create())
.ignoreErrors();
operation.run(new NullProgressMonitor());
verify(applicationAPI, never()).deleteApplication(anyInt());
StatusAssert.assertThat(operation.getStatus()).isOK();
}
@Test
public void should_fail_if_application_deletion_failed() throws Exception {
final ApplicationAPI applicationAPI = mock(ApplicationAPI.class);
doThrow(DeletionException.class).when(applicationAPI).deleteApplication(1);
final Application application1 = applicationWithId(1);
when(applicationAPI.searchApplications(notNull(SearchOptions.class)))
.thenReturn(searchResult(Collections.emptyList()));
when(applicationAPI.searchApplications(eq(withToken("myApp1"))))
.thenReturn(searchResult(Arrays.asList(application1)));
final DeleteApplicationRunnable operation = new DeleteApplicationRunnable(applicationAPI,
newApplication("myApp1", "My App", "1.0").create());
operation.run(new NullProgressMonitor());
verify(applicationAPI).deleteApplication(1);
StatusAssert.assertThat(operation.getStatus()).isNotOK();
}
private SearchResult<Application> searchResult(List<Application> resultAsList) {
return new SearchResultImpl<>(resultAsList.size(), resultAsList);
}
protected SearchOptions withToken(String token) {
return new SearchOptionsBuilder(0, 1).filter(ApplicationSearchDescriptor.TOKEN, token).done();
}
protected Application applicationWithId(long id) {
final Application app = mock(Application.class);
when(app.getId()).thenReturn(Long.valueOf(id));
return app;
}
}
/**
* Copyright (C) 2017 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
import static org.mockito.Mockito.mock;
......@@ -9,7 +23,6 @@ import java.util.ArrayList;
import java.util.List;
import org.bonitasoft.studio.common.repository.model.IRepositoryFileStore;
import org.bonitasoft.studio.la.application.core.ExportApplicationRunnable;
import org.bonitasoft.studio.la.application.repository.ApplicationFileStore;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.junit.Rule;
......
/*******************************************************************************
* Copyright (C) 2017 BonitaSoft S.A.
* BonitaSoft is a trademark of BonitaSoft SA.
* This software file is BONITASOFT CONFIDENTIAL. Not For Distribution.
* For commercial licensing information, contact:
* BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
* or BonitaSoft US, 51 Federal Street, Suite 305, San Francisco, CA 94107
*******************************************************************************/
/**
* Copyright (C) 2017 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
import java.io.ByteArrayInputStream;
......@@ -32,7 +38,8 @@ public class ApplicationContentDescriber extends XMLContentDescriber implements
/*
* (non-Javadoc)
* @see org.eclipse.core.runtime.content.XMLContentDescriber#describe(java.io.Reader, org.eclipse.core.runtime.content.IContentDescription)
* @see org.eclipse.core.runtime.content.XMLContentDescriber#describe(java.io.Reader,
* org.eclipse.core.runtime.content.IContentDescription)
*/
@Override
public int describe(Reader input, IContentDescription description) throws IOException {
......@@ -44,7 +51,8 @@ public class ApplicationContentDescriber extends XMLContentDescriber implements
/*
* (non-Javadoc)
* @see org.eclipse.core.runtime.content.XMLContentDescriber#describe(java.io.InputStream, org.eclipse.core.runtime.content.IContentDescription)
* @see org.eclipse.core.runtime.content.XMLContentDescriber#describe(java.io.InputStream,
* org.eclipse.core.runtime.content.IContentDescription)
*/
@Override
public int describe(InputStream input, IContentDescription description) throws IOException {
......
/**
* Copyright (C) 2016 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
public class ApplicationDescriptorNotFoundException extends Exception {
public ApplicationDescriptorNotFoundException() {
super();
}
}
/**
* Copyright (C) 2017 BonitaSoft S.A.
* BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
import static java.util.Objects.requireNonNull;
import java.lang.reflect.InvocationTargetException;
import org.bonitasoft.engine.api.ApplicationAPI;
import org.bonitasoft.engine.business.application.Application;
import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor;
import org.bonitasoft.engine.business.application.xml.ApplicationNode;
import org.bonitasoft.engine.business.application.xml.ApplicationNodeContainer;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.exception.SearchException;
import org.bonitasoft.engine.search.SearchOptions;
import org.bonitasoft.engine.search.SearchOptionsBuilder;
import org.bonitasoft.studio.la.LivingApplicationPlugin;
import org.bonitasoft.studio.la.i18n.Messages;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.operation.IRunnableWithProgress;
public class DeleteApplicationContainerRunnable implements IRunnableWithProgress {
private final ApplicationAPI applicationAPI;
private final ApplicationNodeContainer applicationNodeContainer;
private IStatus status;
private boolean ignoreErrors = false;
public DeleteApplicationContainerRunnable(ApplicationAPI applicationAPI,
ApplicationNodeContainer applicationNodeContainer) {
this.applicationAPI = requireNonNull(applicationAPI);
this.applicationNodeContainer = requireNonNull(applicationNodeContainer);
}
public DeleteApplicationContainerRunnable ignoreErrors() {
this.ignoreErrors = true;
return this;
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
applicationNodeContainer.getApplications().stream().forEach(applicationNode -> {
monitor.setTaskName(String.format(Messages.deletingApplication, applicationNode.getDisplayName()));
status = delete(applicationNode);
monitor.worked(1);
});
}
public IStatus getStatus() {
return status;
}
private SearchOptions withToken(String token) {
return new SearchOptionsBuilder(0, 1).filter(ApplicationSearchDescriptor.TOKEN, token).done();
}
private IStatus delete(ApplicationNode applicationNode) {
try {
final long applicationId = applicationAPI.searchApplications(withToken(applicationNode.getToken()))
.getResult().stream()
.mapToLong(Application::getId)
.findFirst()
.orElseThrow(ApplicationDescriptorNotFoundException::new);
applicationAPI.deleteApplication(applicationId);
} catch (final SearchException | ApplicationDescriptorNotFoundException e) {
return ignoreErrors ? Status.OK_STATUS : new Status(IStatus.ERROR, LivingApplicationPlugin.PLUGIN_ID,
String.format("Cannot find application descriptor with token '%s'", applicationNode.getToken()), e);
} catch (final DeletionException e) {
return new Status(IStatus.ERROR, LivingApplicationPlugin.PLUGIN_ID,
String.format("Failed to delete application descriptor: '%s'", e.getContext()), e);
}
return Status.OK_STATUS;
}
}
/**
* Copyright (C) 2017 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
import static java.util.Objects.requireNonNull;
import java.lang.reflect.InvocationTargetException;
import org.bonitasoft.engine.api.ApplicationAPI;
import org.bonitasoft.engine.business.application.Application;
import org.bonitasoft.engine.business.application.ApplicationSearchDescriptor;
import org.bonitasoft.engine.business.application.xml.ApplicationNode;
import org.bonitasoft.engine.exception.DeletionException;
import org.bonitasoft.engine.exception.SearchException;
import org.bonitasoft.engine.search.SearchOptions;
import org.bonitasoft.engine.search.SearchOptionsBuilder;
import org.bonitasoft.studio.la.LivingApplicationPlugin;
import org.bonitasoft.studio.la.i18n.Messages;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.operation.IRunnableWithProgress;
public class DeleteApplicationRunnable implements IRunnableWithProgress {
private final ApplicationAPI applicationAPI;
private final ApplicationNode applicationNode;
private IStatus status;
private boolean ignoreErrors = false;
public DeleteApplicationRunnable(ApplicationAPI applicationAPI, ApplicationNode applicationNode) {
this.applicationAPI = requireNonNull(applicationAPI);
this.applicationNode = requireNonNull(applicationNode);
}
public DeleteApplicationRunnable ignoreErrors() {
this.ignoreErrors = true;
return this;
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
monitor.setTaskName(String.format(Messages.deletingApplication, applicationNode.getDisplayName()));
status = delete(applicationNode);
monitor.worked(1);
}
public IStatus getStatus() {
return status;
}
private SearchOptions withToken(String token) {
return new SearchOptionsBuilder(0, 1).filter(ApplicationSearchDescriptor.TOKEN, token).done();
}
private IStatus delete(ApplicationNode applicationNode) {
try {
final long applicationId = applicationAPI.searchApplications(withToken(applicationNode.getToken()))
.getResult().stream()
.mapToLong(Application::getId)
.findFirst()
.orElseThrow(ApplicationDescriptorNotFoundException::new);
applicationAPI.deleteApplication(applicationId);
} catch (final SearchException | ApplicationDescriptorNotFoundException e) {
return ignoreErrors ? Status.OK_STATUS : new Status(IStatus.ERROR, LivingApplicationPlugin.PLUGIN_ID,
String.format("Cannot find application descriptor with token '%s'", applicationNode.getToken()), e);
} catch (final DeletionException e) {
return new Status(IStatus.ERROR, LivingApplicationPlugin.PLUGIN_ID,
String.format("Failed to delete application descriptor: '%s'", e.getContext()), e);
}
return Status.OK_STATUS;
}
}
/**
* Copyright (C) 2017 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2.0 of the License, or
* (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.bonitasoft.studio.la.application.core;
import static org.bonitasoft.studio.ui.wizard.WizardBuilder.newWizard;
import static org.bonitasoft.studio.ui.wizard.WizardPageBuilder.newPage;
import java.lang.reflect.InvocationTargetException;
import java.util.Optional;
import java.util.stream.Collectors;
import org.bonitasoft.engine.api.ApplicationAPI;
import org.bonitasoft.engine.business.application.exporter.ApplicationNodeContainerConverter;
import org.bonitasoft.engine.business.application.xml.ApplicationNodeContainer;
import org.bonitasoft.engine.exception.BonitaHomeNotSetException;
import org.bonitasoft.engine.exception.ServerAPIException;
import org.bonitasoft.engine.exception.UnknownAPITypeException;
import org.bonitasoft.engine.session.APISession;
import org.bonitasoft.studio.common.repository.RepositoryAccessor;
import org.bonitasoft.studio.common.repository.model.IRepositoryFileStore;
import org.bonitasoft.studio.common.repository.model.ReadFileStoreException;
import org.bonitasoft.studio.engine.BOSEngineManager;
import org.bonitasoft.studio.engine.operation.GetApiSessionOperation;
import org.bonitasoft.studio.la.application.repository.ApplicationFileStore;
import org.bonitasoft.studio.la.application.repository.ApplicationRepositoryStore;
import org.bonitasoft.studio.la.application.ui.control.DeployApplicationStatusDialog;
import org.bonitasoft.studio.la.application.ui.provider.DeployApplicationFileStoreLabelProvider;
import org.bonitasoft.studio.la.i18n.Messages;
import org.bonitasoft.studio.ui.dialog.ExceptionDialogHandler;
import org.bonitasoft.studio.ui.page.SelectionSinglePage;
import org.bonitasoft.studio.ui.wizard.WizardBuilder;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.progress.IProgressService;
public class DeployApplicationAction {
protected RepositoryAccessor repositoryAccessor;
public DeployApplicationAction(RepositoryAccessor repositoryAccessor) {
this.repositoryAccessor = repositoryAccessor;
}
/**
* Open a wizard to select an unique application descriptor to deploy, and then deploy this application descriptor
*/
public void selectAndDeploy(Shell shell) {
createWizard(newWizard())
.open(shell, Messages.deploy)
.ifPresent(applicationNodeContainer -> deployApplicationNodeContainer(shell, applicationNodeContainer,
new String[] { IDialogConstants.OK_LABEL }));
}
private WizardBuilder<ApplicationNodeContainer> createWizard(WizardBuilder<ApplicationNodeContainer> builder) {
SelectionSinglePage<ApplicationRepositoryStore> selectApplicationDescriptorPage = new SelectionSinglePage<>(
repositoryAccessor, ApplicationRepositoryStore.class, new DeployApplicationFileStoreLabelProvider());
selectApplicationDescriptorPage.addUnselectableElements(getUnparsableFiles());
return builder.withTitle(Messages.deployExistingApplication)
.havingPage(newPage()
.withTitle(Messages.deployExistingApplication)
.withDescription(Messages.selectApplicationToDeploy)
.withControl(selectApplicationDescriptorPage))
.onFinish(wizardContainer -> getApplicationNodeContainer(selectApplicationDescriptorPage));
}
private IRepositoryFileStore[] getUnparsableFiles() {
return repositoryAccessor.getRepositoryStore(ApplicationRepositoryStore.class).getChildren()
.stream()
.filter(this::isUnparsable)
.collect(Collectors.toList())
.toArray(new IRepositoryFileStore[0]);
}
private boolean isUnparsable(ApplicationFileStore fileStore) {
try {
fileStore.getContent();
return false;
} catch (ReadFileStoreException e) {
return true;
}
}
private Optional<ApplicationNodeContainer> getApplicationNodeContainer(
SelectionSinglePage<ApplicationRepositoryStore> page) {
ApplicationFileStore singleSelection = (ApplicationFileStore) page.getSingleSelection();
if (singleSelection != null) {
try {
return Optional.ofNullable(singleSelection.getContent());
} catch (ReadFileStoreException e) {
throw new RuntimeException("Unable to retrieve application file store content", e);
}
}
return Optional.empty();
}
public int deployApplicationNodeContainer(Shell shell, ApplicationNodeContainer applicationNodeContainer,
String[] onFinishButtons) {
final GetApiSessionOperation apiSessionOperation = new GetApiSessionOperation();
try {
final APISession apiSession = apiSessionOperation.execute();
final ApplicationAPI applicationAPI = BOSEngineManager.getInstance().getApplicationAPI(apiSession);
final IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
final DeployApplicationDescriptorRunnable deployOperation = getDeployOperation(apiSession, applicationAPI,
applicationNodeContainer);
progressService.run(true, false, deployOperation);
return openStatusDialog(shell, deployOperation, onFinishButtons);
} catch (InvocationTargetException | InterruptedException | BonitaHomeNotSetException | ServerAPIException
| UnknownAPITypeException e) {
new ExceptionDialogHandler().openErrorDialog(shell, Messages.deployFailedTitle, e);
return Dialog.CANCEL;
} finally {
apiSessionOperation.logout();
}
}