Commit bea80a6f authored by Romain Bioteau's avatar Romain Bioteau

feat(la-plugin) Add la plugin (#247)

parent f458deb7
......@@ -595,4 +595,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
version="0.0.0"
unpack="false"/>
<plugin
id="org.bonitasoft.studio.la"
download-size="0"
install-size="0"
version="0.0.0"
unpack="false"/>
</feature>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="src-test/java"/>
<classpathentry kind="src" path="src-test/resources"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.bonitasoft.studio.la</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Living application support plugin-in
Bundle-SymbolicName: org.bonitasoft.studio.la;singleton:=true
Bundle-Version: 7.5.0.qualifier
Bundle-Activator: org.bonitasoft.studio.la.LivingApplicationPlugin
Bundle-Vendor: BonitaSoft S.A.
Bundle-Localization: plugin
Require-Bundle: org.mockito;bundle-version="1.9.5";resolution:=optional,
org.junit;bundle-version="4.11.0";resolution:=optional,
assertj-core;bundle-version="1.5.0";resolution:=optional,
org.bonitasoft.studio.tests-utils;bundle-version="6.4.1";resolution:=optional,
org.eclipse.core.runtime,
org.bonitasoft.studio.common.repository;bundle-version="7.5.0",
org.eclipse.ui.workbench,
org.eclipse.ui;bundle-version="3.106.0",
org.bonitasoft.studio.common,
org.eclipse.e4.ui.model.workbench;bundle-version="1.1.0.v20140512-1820",
org.eclipse.e4.core.di,
org.bonitasoft.studio.ui;bundle-version="7.5.0"
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.bonitasoft.engine.business.application,
org.bonitasoft.engine.business.application.exporter,
org.bonitasoft.engine.business.application.xml
Bundle-ActivationPolicy: lazy
src.excludes = src-test/java/,\
src-test/resources/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin*.properties,\
messages*.properties,\
plugin.xml,\
icons/,\
fragment.e4xmi
source.. = src/
<?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"/>
</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.handler.NewApplicationHandler" command="_0n838NKdEeaEE_Umqe0dXA"/>
</fragments>
</fragment:ModelFragments>
applicationStoreName=Applications
createNewApplication=Create
\ No newline at end of file
newApplication=New...
applicationMenuLabel=Application
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<extension
point="org.bonitasoft.studio.repositoryStore">
<repositoryStore
class="org.bonitasoft.studio.la.repository.ApplicationRepositoryStore">
</repositoryStore>
</extension>
<extension
id="org.bonitasoft.studio.la.fragment"
point="org.eclipse.e4.workbench.model">
<fragment
uri="fragment.e4xmi">
</fragment>
</extension>
<extension
point="org.eclipse.ui.menus">
<menuContribution
allPopups="false"
locationURI="menu:org.bonitasoft.studio.development?after=org.bonitasoft.studio.menu.filter">
<menu
icon="icons/applicationStore.gif"
label="%applicationMenuLabel">
<command
commandId="org.bonitasoft.studio.la.new.command"
style="push">
</command>
</menu>
</menuContribution>
</extension>
</plugin>
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.bonitasoft.studio.bundles</groupId>
<artifactId>plugins</artifactId>
<version>7.5.0-SNAPSHOT</version>
</parent>
<groupId>org.bonitasoft.studio.bundles.plugins</groupId>
<artifactId>org.bonitasoft.studio.la</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
/**
* 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.repository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.bonitasoft.studio.fakes.IResourceFakesBuilder.anIFile;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.bonitasoft.engine.business.application.ApplicationState;
import org.bonitasoft.engine.business.application.xml.ApplicationNodeBuilder;
import org.bonitasoft.engine.business.application.xml.ApplicationNodeContainer;
import org.bonitasoft.studio.common.repository.Repository;
import org.bonitasoft.studio.common.repository.model.IRepositoryStore;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class ApplicationFileStoreTest {
private InputStream resourceAsStream;
@Before
public void openStreams() throws Exception {
resourceAsStream = ApplicationFileStoreTest.class.getResourceAsStream("/myApp.xml");
}
@After
public void closeStreams() throws Exception {
resourceAsStream.close();
}
@Test
public void should_retrieve_model_from_application_xml_file() throws Exception {
ApplicationFileStore applicationFileStore = spy(new ApplicationFileStore("myApp.xml", mock(IRepositoryStore.class)));
doReturn(anIFile().withName("myApp.xml")
.withContent(resourceAsStream).build())
.when(applicationFileStore)
.getResource();
ApplicationNodeContainer applicationNodeContainer = applicationFileStore.getContent();
assertThat(applicationNodeContainer.getApplications())
.extracting("displayName", "token", "version", "state")
.containsExactly(tuple("My App", "myAppHome", "1.0", ApplicationState.ACTIVATED.name()));
}
@Test
public void should_create_a_new_application_xml_file_from_model() throws Exception {
ApplicationFileStore applicationFileStore = spy(new ApplicationFileStore("myApp.xml", mock(IRepositoryStore.class)));
IFile resource = anIFile().withName("myApp.xml").build();
doReturn(resource)
.when(applicationFileStore)
.getResource();
applicationFileStore
.save(ApplicationNodeBuilder.newApplicationContainer()
.havingApplications(ApplicationNodeBuilder.newApplication("anAppToken", "A Display Name", "2.0"))
.create());
verify(resource).create(notNull(ByteArrayInputStream.class), eq(IResource.FORCE),
eq(Repository.NULL_PROGRESS_MONITOR));
}
@Test
public void should_update_application_xml_file_from_model() throws Exception {
ApplicationFileStore applicationFileStore = spy(new ApplicationFileStore("myApp.xml", mock(IRepositoryStore.class)));
IFile resource = anIFile().withName("myApp.xml").exists().build();
doReturn(resource)
.when(applicationFileStore)
.getResource();
applicationFileStore
.save(ApplicationNodeBuilder.newApplicationContainer()
.havingApplications(ApplicationNodeBuilder.newApplication("anAppToken", "A Display Name", "2.0"))
.create());
verify(resource).setContents(notNull(ByteArrayInputStream.class), eq(IResource.FORCE | IResource.KEEP_HISTORY),
eq(Repository.NULL_PROGRESS_MONITOR));
}
@Test(expected = IllegalArgumentException.class)
public void should_fail_when_saving_unsupported_content() throws Exception {
ApplicationFileStore applicationFileStore = new ApplicationFileStore("myApp.xml", null);
applicationFileStore.doSave(null);
}
}
/**
* 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.repository;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
public class ApplicationRepositoryStoreTest {
@Test
public void should_only_accept_xml_files() throws Exception {
final ApplicationRepositoryStore store = new ApplicationRepositoryStore();
assertThat(store.getCompatibleExtensions()).containsOnly("xml");
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<applications xmlns="http://documentation.bonitasoft.com/application-xml-schema/1.0">
<application token="myAppHome" version="1.0" profile="User" homePage="home" state="ACTIVATED" layout="custompage_defaultlayout" theme="custompage_bootstrapdefaulttheme">
<displayName>My App</displayName>
<description>SOme description for my app</description>
<applicationPages>
<applicationPage customPage="custompage_home" token="home"/>
</applicationPages>
</application>
</applications>
package org.bonitasoft.studio.la;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class LivingApplicationPlugin extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "org.bonitasoft.studio.la"; //$NON-NLS-1$
// The shared instance
private static LivingApplicationPlugin plugin;
/**
* The constructor
*/
public LivingApplicationPlugin() {
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
*/
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
}
/*
* (non-Javadoc)
* @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
*/
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static LivingApplicationPlugin getDefault() {
return plugin;
}
public static Image getImage(final String imageName) {
final ImageRegistry reg = getDefault().getImageRegistry();
Image result = reg.get(imageName);
if (result != null && !result.isDisposed()) {//prevent from bad dispose
return result;
}
final ImageDescriptor descriptor = ImageDescriptor.createFromURL(getDefault().getBundle().getResource(imageName));
if (descriptor != null) {
result = descriptor.createImage();
}
reg.remove(imageName);
if (result != null) {
reg.put(imageName, result);
}
return result;
}
}
/**
* 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.handler;
import static org.bonitasoft.studio.ui.wizard.WizardBuilder.newWizard;
import org.bonitasoft.engine.business.application.xml.ApplicationNodeBuilder;
import org.bonitasoft.studio.common.repository.RepositoryAccessor;
import org.bonitasoft.studio.la.i18n.Messages;
import org.bonitasoft.studio.la.repository.ApplicationFileStore;
import org.bonitasoft.studio.la.repository.ApplicationRepositoryStore;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
public class NewApplicationHandler {
@Execute
public void newApplication(Shell activeShell, RepositoryAccessor repositoryAccessor) {
MessageDialog.openInformation(activeShell, "Not implemented", "Wait & See");
}
}
/**
* 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.i18n;
import org.eclipse.osgi.util.NLS;
public class Messages extends NLS {
public static String applicationStoreName;
public static String createNewApplication;
static {
NLS.initializeMessages("messages", Messages.class);
}
}
/**
* 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.repository;
import static com.google.common.base.Preconditions.checkArgument;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.bind.JAXBException;
import org.bonitasoft.engine.business.application.exporter.ApplicationNodeContainerConverter;
import org.bonitasoft.engine.business.application.xml.ApplicationNodeContainer;
import org.bonitasoft.studio.common.log.BonitaStudioLog;
import org.bonitasoft.studio.common.repository.Repository;
import org.bonitasoft.studio.common.repository.filestore.AbstractFileStore;
import org.bonitasoft.studio.common.repository.model.IRepositoryFileStore;
import org.bonitasoft.studio.common.repository.model.IRepositoryStore;
import org.bonitasoft.studio.common.repository.model.ReadFileStoreException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IWorkbenchPart;
import org.xml.sax.SAXException;
import com.google.common.io.ByteStreams;
public class ApplicationFileStore extends AbstractFileStore {
private final ApplicationNodeContainerConverter applicationNodeContainerConverter = new ApplicationNodeContainerConverter();
public ApplicationFileStore(String fileName, IRepositoryStore<? extends IRepositoryFileStore> parentStore) {
super(fileName, parentStore);
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.model.IRepositoryFileStore#getContent()
*/
@Override
public ApplicationNodeContainer getContent() throws ReadFileStoreException {
try (InputStream inputStream = getResource().getContents()) {
return applicationNodeContainerConverter.unmarshallFromXML(ByteStreams.toByteArray(inputStream));
} catch (CoreException | JAXBException | IOException | SAXException e) {
throw new ReadFileStoreException("Failed to load application model", e);
}
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.filestore.AbstractFileStore#doSave(java.lang.Object)
*/
@Override
protected void doSave(Object content) {
checkArgument(content instanceof ApplicationNodeContainer,
String.format("Only instance of %s are supported",
ApplicationNodeContainer.class));
try {
final byte[] xmlContent = applicationNodeContainerConverter
.marshallToXML((ApplicationNodeContainer) content);
try (ByteArrayInputStream is = new ByteArrayInputStream(xmlContent)) {
final IFile resource = getResource();
if (!resource.exists()) {
resource.create(is, IResource.FORCE,
Repository.NULL_PROGRESS_MONITOR);
} else {
resource.setContents(is, IResource.KEEP_HISTORY | IResource.FORCE,
Repository.NULL_PROGRESS_MONITOR);
}
}
} catch (JAXBException | IOException | SAXException | CoreException e) {
BonitaStudioLog.error("Failed to save application model", e);
}
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.filestore.AbstractFileStore#getResource()
*/
@Override
public IFile getResource() {
return (IFile) super.getResource();
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.filestore.AbstractFileStore#doClose()
*/
@Override
protected void doClose() {
//Nothing to do here
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.model.IDisplayable#getIcon()
*/
@Override
public Image getIcon() {
return getParentStore().getIcon();
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.filestore.AbstractFileStore#doOpen()
*/
@Override
protected IWorkbenchPart doOpen() {
throw new RuntimeException("Not implemeted yet");
}
}
/**
* 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.repository;
import static com.google.common.collect.Sets.newHashSet;
import java.util.Collections;
import java.util.Set;
import org.bonitasoft.studio.common.repository.store.AbstractRepositoryStore;
import org.bonitasoft.studio.la.LivingApplicationPlugin;
import org.bonitasoft.studio.la.i18n.Messages;
import org.eclipse.swt.graphics.Image;
public class ApplicationRepositoryStore extends AbstractRepositoryStore<ApplicationFileStore> {
private static final String XML_EXTENSION = "xml";
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.model.IRepositoryStore#getName()
*/
@Override
public String getName() {
return "applications"; //$NON-NLS-N$
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.model.IDisplayable#getDisplayName()
*/
@Override
public String getDisplayName() {
return Messages.applicationStoreName;
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.model.IDisplayable#getIcon()
*/
@Override
public Image getIcon() {
return LivingApplicationPlugin.getImage("icons/applicationStore.gif");
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.store.AbstractRepositoryStore#createRepositoryFileStore(java.lang.String)
*/
@Override
public ApplicationFileStore createRepositoryFileStore(String fileName) {
return new ApplicationFileStore(fileName, this);
}
/*
* (non-Javadoc)
* @see org.bonitasoft.studio.common.repository.store.AbstractRepositoryStore#getCompatibleExtensions()
*/
@Override
public Set<String> getCompatibleExtensions() {
return Collections.unmodifiableSet(newHashSet(XML_EXTENSION));
}
}