CHE-1790: Consolidate databases

6.19.x
Anton Korneta 2016-09-15 16:57:30 +03:00
parent 4ba7ffd2ae
commit d5fe8aed73
266 changed files with 14894 additions and 4490 deletions

View File

@ -608,7 +608,7 @@ call_catalina () {
### Cannot add this in setenv.sh.
### We do the port mapping here, and this gets inserted into server.xml when tomcat boots
export JAVA_OPTS="${JAVA_OPTS} -Dport.http=${CHE_PORT} -Dche.home=${CHE_HOME}"
export JAVA_OPTS="${JAVA_OPTS} -Dport.http=${CHE_PORT} -Dche.home=${CHE_HOME} -Dh2.baseDir=${CHE_HOME}/db/"
export SERVER_PORT=${CHE_PORT}
# Launch the Che application server, passing in command line parameters

View File

@ -46,6 +46,14 @@
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" /-->
<Resource name="che" auth="Container"
type="javax.sql.DataSource"
driverClassName="org.h2.Driver"
url="jdbc:h2:che"
username="" password=""
maxTotal="8"
maxIdle="4"/>
</GlobalNamingResources>
<!-- A "Service" is a collection of one or more "Connectors" that share

View File

@ -50,6 +50,10 @@
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
@ -66,6 +70,14 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc-vendor-h2</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-machine</artifactId>
@ -82,6 +94,10 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-ssh</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-ssh-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-user</artifactId>
@ -126,6 +142,10 @@
<groupId>org.eclipse.che.plugin</groupId>
<artifactId>che-plugin-ssh-machine</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
</dependency>
<dependency>
<groupId>org.everrest</groupId>
<artifactId>everrest-core</artifactId>
@ -148,6 +168,26 @@
<artifactId>tomcat-catalina</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-factory</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>

View File

@ -13,14 +13,25 @@ package org.eclipse.che.api.deploy;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import com.google.inject.persist.jpa.JpaPersistModule;
import org.eclipse.che.api.agent.server.launcher.AgentLauncher;
import org.eclipse.che.api.core.rest.CheJsonProvider;
import org.eclipse.che.api.core.rest.MessageBodyAdapter;
import org.eclipse.che.api.core.rest.MessageBodyAdapterInterceptor;
import org.eclipse.che.account.api.AccountModule;
import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer;
import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer;
import org.eclipse.che.api.machine.server.jpa.MachineJpaModule;
import org.eclipse.che.api.machine.shared.Constants;
import org.eclipse.che.api.workspace.server.WorkspaceConfigMessageBodyAdapter;
import org.eclipse.che.api.workspace.server.WorkspaceMessageBodyAdapter;
import org.eclipse.che.api.ssh.server.jpa.SshJpaModule;
import org.eclipse.che.api.user.server.CheUserCreator;
import org.eclipse.che.api.user.server.TokenValidator;
import org.eclipse.che.api.user.server.jpa.UserJpaModule;
import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule;
import org.eclipse.che.api.workspace.server.stack.StackMessageBodyAdapter;
import org.eclipse.che.inject.DynaModule;
@ -32,6 +43,19 @@ import static org.eclipse.che.inject.Matchers.names;
public class WsMasterModule extends AbstractModule {
@Override
protected void configure() {
install(new JpaPersistModule("main"));
bind(CheUserCreator.class);
bind(JpaInitializer.class).asEagerSingleton();
bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton();
install(new UserJpaModule());
install(new SshJpaModule());
install(new WorkspaceJpaModule());
install(new AccountModule());
install(new MachineJpaModule());
bind(TokenValidator.class).to(org.eclipse.che.api.local.DummyTokenValidator.class);
bind(org.eclipse.che.api.local.LocalDataMigrator.class).asEagerSingleton();
bind(org.eclipse.che.api.core.rest.ApiInfoService.class);
bind(org.eclipse.che.api.project.server.template.ProjectTemplateDescriptionLoader.class).asEagerSingleton();
bind(org.eclipse.che.api.project.server.template.ProjectTemplateRegistry.class);
@ -99,7 +123,6 @@ public class WsMasterModule extends AbstractModule {
install(new org.eclipse.che.api.core.util.FileCleaner.FileCleanerModule());
install(new org.eclipse.che.plugin.docker.machine.local.LocalDockerModule());
install(new org.eclipse.che.api.machine.server.MachineModule());
install(new org.eclipse.che.api.local.LocalInfrastructureModule());
install(new org.eclipse.che.plugin.docker.machine.ext.DockerExtServerModule());
install(new org.eclipse.che.plugin.docker.machine.ext.DockerTerminalModule());
install(new org.eclipse.che.swagger.deploy.DocsModule());

View File

@ -0,0 +1,53 @@
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0">
<persistence-unit name="main" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>java:/comp/env/jdbc/che</non-jta-data-source>
<class>org.eclipse.che.account.spi.AccountImpl</class>
<class>org.eclipse.che.api.user.server.model.impl.UserImpl</class>
<class>org.eclipse.che.api.user.server.model.impl.ProfileImpl</class>
<class>org.eclipse.che.api.user.server.jpa.PreferenceEntity</class>
<class>org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.EnvironmentRecipeImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute</class>
<class>org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl</class>
<class>org.eclipse.che.api.machine.server.model.impl.CommandImpl</class>
<class>org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl</class>
<class>org.eclipse.che.api.machine.server.model.impl.SnapshotImpl</class>
<class>org.eclipse.che.api.machine.server.recipe.RecipeImpl</class>
<class>org.eclipse.che.api.ssh.server.model.impl.SshPairImpl</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.exception-handler" value="org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink.H2ExceptionHandler"/>
<property name="eclipselink.target-server" value="None"/>
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.logging.level" value="SEVERE"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -13,4 +13,8 @@
-->
<Context allowCasualMultipartParsing="true">
<Valve className="org.apache.catalina.valves.rewrite.RewriteValve"/>
</Context>
<ResourceLink global="che"
name="jdbc/che"
type="javax.sql.DataSource"/>
</Context>

View File

@ -172,7 +172,7 @@ workspace.runtime.auto_snapshot=true
workspace.runtime.auto_restore=true
# Reserved user names
user.reserved_names=
che.account.reserved_names=
# java opts for dev machine
che.machine.java_opts=-Xms256m -Xmx2048m -Djava.security.egd=file:/dev/./urandom

View File

@ -68,4 +68,10 @@
<role-name>developer</role-name>
</security-role>
<resource-ref>
<res-ref-name>jdbc/che</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>

View File

@ -0,0 +1,133 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api;
import com.google.common.collect.ImmutableMap;
import org.eclipse.che.account.shared.model.Account;
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
import org.eclipse.che.api.factory.server.model.impl.AuthorImpl;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl;
import org.eclipse.che.api.machine.server.recipe.RecipeImpl;
import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.model.impl.stack.StackComponentImpl;
import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl;
import org.eclipse.che.api.workspace.server.model.impl.stack.StackSourceImpl;
import org.eclipse.che.api.workspace.server.stack.image.StackIcon;
import java.util.HashMap;
import java.util.Map;
import static java.util.Arrays.asList;
/**
* Defines method for creating tests object instances.
*
* @author Yevhenii Voevodin
*/
public final class TestObjectsFactory {
public static UserImpl createUser(String id) {
return new UserImpl(id,
id + "@eclipse.org",
id + "_name",
"password",
asList(id + "_alias1", id + "_alias2"));
}
public static ProfileImpl createProfile(String userId) {
return new ProfileImpl(userId, new HashMap<>(ImmutableMap.of("attribute1", "value1",
"attribute2", "value2",
"attribute3", "value3")));
}
public static Map<String, String> createPreferences() {
return new HashMap<>(ImmutableMap.of("preference1", "value1",
"preference2", "value2",
"preference3", "value3"));
}
public static WorkspaceConfigImpl createWorkspaceConfig(String id) {
return new WorkspaceConfigImpl(id + "_name",
id + "description",
"default-env",
null,
null,
null);
}
public static WorkspaceImpl createWorkspace(String id, Account account) {
return new WorkspaceImpl(id, account, createWorkspaceConfig(id));
}
public static SshPairImpl createSshPair(String owner, String service, String name) {
return new SshPairImpl(owner, service, name, "public-key", "private-key");
}
public static FactoryImpl createFactory(String id, String creator) {
return new FactoryImpl(id,
id + "-name",
"4.0",
createWorkspaceConfig(id),
new AuthorImpl(creator, System.currentTimeMillis()),
null,
null,
null,
null);
}
public static SnapshotImpl createSnapshot(String snapshotId, String workspaceId) {
return new SnapshotImpl(snapshotId,
"type",
null,
System.currentTimeMillis(),
workspaceId,
snapshotId + "_description",
true,
"dev-machine",
snapshotId + "env-name");
}
public static RecipeImpl createRecipe(String id) {
return new RecipeImpl(id,
"recipe-name-" + id,
"recipe-creator",
"recipe-type",
"recipe-script",
asList("recipe-tag1", "recipe-tag2"),
"recipe-description");
}
public static StackImpl createStack(String id, String name) {
return StackImpl.builder()
.setId(id)
.setName(name)
.setCreator("user123")
.setDescription(id + "-description")
.setScope(id + "-scope")
.setWorkspaceConfig(createWorkspaceConfig("test"))
.setTags(asList(id + "-tag1", id + "-tag2"))
.setComponents(asList(new StackComponentImpl(id + "-component1", id + "-component1-version"),
new StackComponentImpl(id + "-component2", id + "-component2-version")))
.setSource(new StackSourceImpl(id + "-type", id + "-origin"))
.setStackIcon(new StackIcon(id + "-icon",
id + "-media-type",
"0x1234567890abcdef".getBytes()))
.build();
}
private TestObjectsFactory() {}
}

View File

@ -0,0 +1,261 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.jdbc.jpa;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.google.inject.persist.jpa.JpaPersistModule;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer;
import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.notification.EventSubscriber;
import org.eclipse.che.api.factory.server.jpa.FactoryJpaModule;
import org.eclipse.che.api.factory.server.jpa.JpaFactoryDao.RemoveFactoriesBeforeUserRemovedEventSubscriber;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
import org.eclipse.che.api.factory.server.spi.FactoryDao;
import org.eclipse.che.api.machine.server.jpa.MachineJpaModule;
import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl;
import org.eclipse.che.api.machine.server.spi.SnapshotDao;
import org.eclipse.che.api.ssh.server.jpa.JpaSshDao.RemoveSshKeysBeforeUserRemovedEventSubscriber;
import org.eclipse.che.api.ssh.server.jpa.SshJpaModule;
import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl;
import org.eclipse.che.api.ssh.server.spi.SshDao;
import org.eclipse.che.api.user.server.jpa.JpaPreferenceDao.RemovePreferencesBeforeUserRemovedEventSubscriber;
import org.eclipse.che.api.user.server.jpa.JpaProfileDao.RemoveProfileBeforeUserRemovedEventSubscriber;
import org.eclipse.che.api.user.server.jpa.UserJpaModule;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.server.jpa.JpaWorkspaceDao;
import org.eclipse.che.api.workspace.server.jpa.JpaWorkspaceDao.RemoveSnapshotsBeforeWorkspaceRemovedEventSubscriber;
import org.eclipse.che.api.workspace.server.jpa.JpaWorkspaceDao.RemoveWorkspaceBeforeAccountRemovedEventSubscriber;
import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.spi.WorkspaceDao;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.inject.lifecycle.InitModule;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import javax.persistence.EntityManagerFactory;
import java.util.Map;
import java.util.concurrent.Callable;
import static java.util.Collections.singletonList;
import static org.eclipse.che.api.TestObjectsFactory.createFactory;
import static org.eclipse.che.api.TestObjectsFactory.createPreferences;
import static org.eclipse.che.api.TestObjectsFactory.createProfile;
import static org.eclipse.che.api.TestObjectsFactory.createSnapshot;
import static org.eclipse.che.api.TestObjectsFactory.createSshPair;
import static org.eclipse.che.api.TestObjectsFactory.createUser;
import static org.eclipse.che.api.TestObjectsFactory.createWorkspace;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* Tests top-level entities cascade removals.
*
* @author Yevhenii Voevodin
*/
public class JpaEntitiesCascadeRemovalTest {
private Injector injector;
private EventService eventService;
private PreferenceDao preferenceDao;
private UserDao userDao;
private ProfileDao profileDao;
private WorkspaceDao workspaceDao;
private SnapshotDao snapshotDao;
private SshDao sshDao;
private FactoryDao factoryDao;
/** User is a root of dependency tree. */
private UserImpl user;
/** Profile depends on user. */
private ProfileImpl profile;
/** Preferences depend on user. */
private Map<String, String> preferences;
/** Workspaces depend on user. */
private WorkspaceImpl workspace1;
private WorkspaceImpl workspace2;
/** SshPairs depend on user. */
private SshPairImpl sshPair1;
private SshPairImpl sshPair2;
/** Factories depend on user. */
private FactoryImpl factory1;
private FactoryImpl factory2;
/** Snapshots depend on workspace. */
private SnapshotImpl snapshot1;
private SnapshotImpl snapshot2;
private SnapshotImpl snapshot3;
private SnapshotImpl snapshot4;
@BeforeMethod
public void setUp() throws Exception {
injector = Guice.createInjector(Stage.PRODUCTION, new AbstractModule() {
@Override
protected void configure() {
bind(EventService.class).in(Singleton.class);
bind(JpaInitializer.class).asEagerSingleton();
bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton();
install(new InitModule(PostConstruct.class));
install(new JpaPersistModule("test"));
install(new UserJpaModule());
install(new SshJpaModule());
install(new WorkspaceJpaModule());
install(new MachineJpaModule());
install(new FactoryJpaModule());
}
});
eventService = injector.getInstance(EventService.class);
userDao = injector.getInstance(UserDao.class);
preferenceDao = injector.getInstance(PreferenceDao.class);
profileDao = injector.getInstance(ProfileDao.class);
sshDao = injector.getInstance(SshDao.class);
snapshotDao = injector.getInstance(SnapshotDao.class);
workspaceDao = injector.getInstance(WorkspaceDao.class);
factoryDao = injector.getInstance(FactoryDao.class);
}
@AfterMethod
public void cleanup() {
injector.getInstance(EntityManagerFactory.class).close();
}
@Test
public void shouldDeleteAllTheEntitiesWhenUserIsDeleted() throws Exception {
createTestData();
// Remove the user, all entries must be removed along with the user
userDao.remove(user.getId());
// Check all the entities are removed
assertNull(notFoundToNull(() -> userDao.getById(user.getId())));
assertNull(notFoundToNull(() -> profileDao.getById(user.getId())));
assertTrue(preferenceDao.getPreferences(user.getId()).isEmpty());
assertTrue(sshDao.get(user.getId()).isEmpty());
assertTrue(workspaceDao.getByNamespace(user.getId()).isEmpty());
assertTrue(factoryDao.getByAttribute(0, 0, singletonList(Pair.of("creator.userId", user.getId()))).isEmpty());
assertTrue(snapshotDao.findSnapshots(workspace1.getId()).isEmpty());
assertTrue(snapshotDao.findSnapshots(workspace2.getId()).isEmpty());
}
@Test(dataProvider = "beforeRemoveRollbackActions")
public void shouldRollbackTransactionWhenFailedToRemoveAnyOfEntries(Class<EventSubscriber> eventSubscriber) throws Exception {
createTestData();
eventService.unsubscribe(injector.getInstance(eventSubscriber));
// Remove the user, all entries must be rolled back after fail
try {
userDao.remove(user.getId());
fail("UserDao#remove had to throw exception");
} catch (Exception ignored) {
}
// Check all the data rolled back
assertNotNull(userDao.getById(user.getId()));
assertNotNull(profileDao.getById(user.getId()));
assertFalse(preferenceDao.getPreferences(user.getId()).isEmpty());
assertFalse(sshDao.get(user.getId()).isEmpty());
assertFalse(workspaceDao.getByNamespace(user.getName()).isEmpty());
assertFalse(factoryDao.getByAttribute(0, 0, singletonList(Pair.of("creator.userId", user.getId()))).isEmpty());
assertFalse(snapshotDao.findSnapshots(workspace1.getId()).isEmpty());
assertFalse(snapshotDao.findSnapshots(workspace2.getId()).isEmpty());
wipeTestData();
}
@DataProvider(name = "beforeRemoveRollbackActions")
public Object[][] beforeRemoveActions() {
return new Class[][] {
{RemovePreferencesBeforeUserRemovedEventSubscriber.class},
{RemoveProfileBeforeUserRemovedEventSubscriber.class},
{RemoveWorkspaceBeforeAccountRemovedEventSubscriber.class},
{RemoveSnapshotsBeforeWorkspaceRemovedEventSubscriber.class},
{RemoveSshKeysBeforeUserRemovedEventSubscriber.class},
{RemoveFactoriesBeforeUserRemovedEventSubscriber.class}
};
}
private void createTestData() throws ConflictException, ServerException {
userDao.create(user = createUser("bobby"));
profileDao.create(profile = createProfile(user.getId()));
preferenceDao.setPreferences(user.getId(), preferences = createPreferences());
workspaceDao.create(workspace1 = createWorkspace("workspace1", user.getAccount()));
workspaceDao.create(workspace2 = createWorkspace("workspace2", user.getAccount()));
sshDao.create(sshPair1 = createSshPair(user.getId(), "service", "name1"));
sshDao.create(sshPair2 = createSshPair(user.getId(), "service", "name2"));
factoryDao.create(factory1 = createFactory("factory1", user.getId()));
factoryDao.create(factory2 = createFactory("factory2", user.getId()));
snapshotDao.saveSnapshot(snapshot1 = createSnapshot("snapshot1", workspace1.getId()));
snapshotDao.saveSnapshot(snapshot2 = createSnapshot("snapshot2", workspace1.getId()));
snapshotDao.saveSnapshot(snapshot3 = createSnapshot("snapshot3", workspace2.getId()));
snapshotDao.saveSnapshot(snapshot4 = createSnapshot("snapshot4", workspace2.getId()));
}
private void wipeTestData() throws ConflictException, ServerException, NotFoundException {
snapshotDao.removeSnapshot(snapshot1.getId());
snapshotDao.removeSnapshot(snapshot2.getId());
snapshotDao.removeSnapshot(snapshot3.getId());
snapshotDao.removeSnapshot(snapshot4.getId());
factoryDao.remove(factory1.getId());
factoryDao.remove(factory2.getId());
sshDao.remove(sshPair1.getOwner(), sshPair1.getService(), sshPair1.getName());
sshDao.remove(sshPair2.getOwner(), sshPair2.getService(), sshPair2.getName());
workspaceDao.remove(workspace1.getId());
workspaceDao.remove(workspace2.getId());
preferenceDao.remove(user.getId());
profileDao.remove(user.getId());
userDao.remove(user.getId());
}
private static <T> T notFoundToNull(Callable<T> action) throws Exception {
try {
return action.call();
} catch (NotFoundException x) {
return null;
}
}
}

View File

@ -0,0 +1,222 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.local;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Stage;
import com.google.inject.name.Names;
import com.google.inject.persist.jpa.JpaPersistModule;
import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer;
import org.eclipse.che.api.local.storage.LocalStorageFactory;
import org.eclipse.che.api.local.storage.stack.StackLocalStorage;
import org.eclipse.che.api.machine.server.jpa.MachineJpaModule;
import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl;
import org.eclipse.che.api.machine.server.recipe.RecipeImpl;
import org.eclipse.che.api.machine.server.spi.RecipeDao;
import org.eclipse.che.api.machine.server.spi.SnapshotDao;
import org.eclipse.che.api.ssh.server.jpa.SshJpaModule;
import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl;
import org.eclipse.che.api.ssh.server.spi.SshDao;
import org.eclipse.che.api.user.server.jpa.UserJpaModule;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.server.WorkspaceConfigJsonAdapter;
import org.eclipse.che.api.workspace.server.jpa.WorkspaceJpaModule;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl;
import org.eclipse.che.api.workspace.server.spi.StackDao;
import org.eclipse.che.api.workspace.server.spi.WorkspaceDao;
import org.eclipse.che.api.workspace.server.stack.StackJsonAdapter;
import org.eclipse.che.commons.lang.IoUtil;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import javax.persistence.EntityManagerFactory;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.eclipse.che.api.TestObjectsFactory.createPreferences;
import static org.eclipse.che.api.TestObjectsFactory.createProfile;
import static org.eclipse.che.api.TestObjectsFactory.createRecipe;
import static org.eclipse.che.api.TestObjectsFactory.createSnapshot;
import static org.eclipse.che.api.TestObjectsFactory.createSshPair;
import static org.eclipse.che.api.TestObjectsFactory.createStack;
import static org.eclipse.che.api.TestObjectsFactory.createUser;
import static org.eclipse.che.api.TestObjectsFactory.createWorkspace;
/**
* Tests migration from local json based storage to jpa.
*
* @author Yevhenii Voevodin
*/
public class LocalToJpaDataMigratorTest {
private Injector injector;
private LocalDataMigrator migrator;
private Path workingDir;
private UserDao userDao;
private ProfileDao profileDao;
private PreferenceDao preferenceDao;
private WorkspaceDao workspaceDao;
private SnapshotDao snapshotDao;
private SshDao sshDao;
private RecipeDao recipeDao;
private StackDao stackDao;
private LocalStorageFactory factory;
private StackJsonAdapter stackJsonAdapter;
private WorkspaceConfigJsonAdapter workspaceCfgJsonAdapter;
@BeforeMethod
private void setUp() throws Exception {
workingDir = Files.createTempDirectory(Paths.get("/tmp"), "test");
factory = new LocalStorageFactory(workingDir.toString());
injector = Guice.createInjector(Stage.PRODUCTION, new AbstractModule() {
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named("che.conf.storage")).to(workingDir.toString());
bind(JpaInitializer.class).asEagerSingleton();
install(new JpaPersistModule("test"));
install(new UserJpaModule());
install(new SshJpaModule());
install(new WorkspaceJpaModule());
install(new MachineJpaModule());
bind(StackJsonAdapter.class);
}
});
userDao = injector.getInstance(UserDao.class);
preferenceDao = injector.getInstance(PreferenceDao.class);
profileDao = injector.getInstance(ProfileDao.class);
sshDao = injector.getInstance(SshDao.class);
snapshotDao = injector.getInstance(SnapshotDao.class);
workspaceDao = injector.getInstance(WorkspaceDao.class);
recipeDao = injector.getInstance(RecipeDao.class);
stackDao = injector.getInstance(StackDao.class);
stackJsonAdapter = injector.getInstance(StackJsonAdapter.class);
workspaceCfgJsonAdapter = injector.getInstance(WorkspaceConfigJsonAdapter.class);
migrator = new LocalDataMigrator();
storeTestData();
}
@AfterMethod
public void cleanup() {
IoUtil.deleteRecursive(workingDir.toFile());
injector.getInstance(EntityManagerFactory.class).close();
}
@Test
public void shouldSuccessfullyPerformMigration() throws Exception {
migrator.performMigration(workingDir.toString(),
userDao,
profileDao,
preferenceDao,
sshDao,
workspaceDao,
snapshotDao,
recipeDao,
stackDao,
stackJsonAdapter,
workspaceCfgJsonAdapter);
}
@Test(expectedExceptions = Exception.class, dataProvider = "failFilenames")
public void shouldFailIfEntitiesAreInconsistent(String filename) throws Exception {
Files.delete(workingDir.resolve(filename));
migrator.performMigration(workingDir.toString(),
userDao,
profileDao,
preferenceDao,
sshDao,
workspaceDao,
snapshotDao,
recipeDao,
stackDao,
stackJsonAdapter,
workspaceCfgJsonAdapter);
}
@DataProvider(name = "failFilenames")
private Object[][] failFilenames() {
return new String[][] {
{LocalUserDaoImpl.FILENAME},
{LocalWorkspaceDaoImpl.FILENAME}
};
}
private void storeTestData() throws Exception {
final UserImpl user = createUser("user123");
final ProfileImpl profile = createProfile(user.getId());
final Map<String, String> preferences = createPreferences();
final SshPairImpl pair = createSshPair(user.getId(), "service", "name");
final WorkspaceImpl workspace = createWorkspace("id", user.getAccount());
final SnapshotImpl snapshot = createSnapshot("snapshot123", workspace.getId());
final RecipeImpl recipe = createRecipe("recipe123");
final StackImpl stack = createStack("stack123", "stack-name");
factory.create(LocalUserDaoImpl.FILENAME).store(singletonMap(user.getId(), user));
factory.create(LocalProfileDaoImpl.FILENAME).store(singletonMap(profile.getUserId(), profile));
factory.create(LocalPreferenceDaoImpl.FILENAME).store(singletonMap(user.getId(), preferences));
factory.create(LocalSshDaoImpl.FILENAME, singletonMap(SshPairImpl.class, new SshSerializer()))
.store(singletonMap(pair.getOwner(), singletonList(pair)));
factory.create(LocalWorkspaceDaoImpl.FILENAME, singletonMap(WorkspaceImpl.class, new WorkspaceSerializer()))
.store(singletonMap(workspace.getId(), workspace));
factory.create(LocalSnapshotDaoImpl.FILENAME).store(singletonMap(snapshot.getId(), snapshot));
factory.create(LocalRecipeDaoImpl.FILENAME).store(singletonMap(recipe.getId(), recipe));
factory.create(StackLocalStorage.STACK_STORAGE_FILE).store(singletonMap(stack.getId(), stack));
}
public static class WorkspaceSerializer implements JsonSerializer<WorkspaceImpl> {
@Override
public JsonElement serialize(WorkspaceImpl src, Type typeOfSrc, JsonSerializationContext context) {
JsonElement result = new Gson().toJsonTree(src, WorkspaceImpl.class);
result.getAsJsonObject().addProperty("namespace", src.getNamespace());
result.getAsJsonObject().remove("account");
return result;
}
}
public static class SshSerializer implements JsonSerializer<SshPairImpl> {
@Override
public JsonElement serialize(SshPairImpl sshPair, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject result = new JsonObject();
result.add("service", new JsonPrimitive(sshPair.getService()));
result.add("name", new JsonPrimitive(sshPair.getName()));
result.add("privateKey", new JsonPrimitive(sshPair.getPublicKey()));
result.add("publicKey", new JsonPrimitive(sshPair.getPrivateKey()));
return result;
}
}
}

View File

@ -0,0 +1,63 @@
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0">
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.eclipse.che.api.user.server.model.impl.UserImpl</class>
<class>org.eclipse.che.api.user.server.model.impl.ProfileImpl</class>
<class>org.eclipse.che.account.spi.AccountImpl</class>
<class>org.eclipse.che.api.user.server.jpa.PreferenceEntity</class>
<class>org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.EnvironmentRecipeImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute</class>
<class>org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl</class>
<class>org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl</class>
<class>org.eclipse.che.api.machine.server.model.impl.CommandImpl</class>
<class>org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl</class>
<class>org.eclipse.che.api.machine.server.model.impl.SnapshotImpl</class>
<class>org.eclipse.che.api.machine.server.recipe.RecipeImpl</class>
<class>org.eclipse.che.api.ssh.server.model.impl.SshPairImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.ActionImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.AuthorImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.ButtonAttributesImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.ButtonImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.FactoryImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.IdeImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.OnAppClosedImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.OnProjectsLoadedImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.OnAppLoadedImpl</class>
<class>org.eclipse.che.api.factory.server.model.impl.PoliciesImpl</class>
<class>org.eclipse.che.api.factory.server.FactoryImage</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="eclipselink.exception-handler" value="org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink.H2ExceptionHandler"/>
<property name="eclipselink.target-server" value="None"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.logging.level" value="SEVERE"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="stdout"/>
</root>
</configuration>

View File

@ -1,70 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.acl;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkArgument;
/**
* @author Sergii Leschenko
*/
public class AclEntryImpl implements AclEntry {
private final String user;
private final List<String> actions;
public AclEntryImpl(String user, List<String> actions) {
checkArgument(actions != null && !actions.isEmpty(), "Required at least one action");
this.user = user;
this.actions = new ArrayList<>(actions);
}
@Override
public String getUser() {
return user;
}
@Override
public List<String> getActions() {
return actions;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof AclEntryImpl)) {
return false;
}
final AclEntryImpl other = (AclEntryImpl)obj;
return Objects.equals(user, other.user)
&& actions.equals(other.actions);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hashCode(user);
hash = 31 * hash + actions.hashCode();
return hash;
}
@Override
public String toString() {
return "AclEntryImpl{" +
"user='" + user + "'" +
", actions=" + actions +
'}';
}
}

View File

@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.security;
import com.google.common.hash.HashCode;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.primitives.Ints.tryParse;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
/**
* Encrypts password using <a href="https://en.wikipedia.org/wiki/PBKDF2">Password-based-Key-Derivative-Function</a>
* with <b>SHA512</b> as pseudorandom function.
* See <a href="https://www.ietf.org/rfc/rfc2898.txt">rfc2898</a>.
*
* @author Yevhenii Voevodin
*/
public class PBKDF2PasswordEncryptor implements PasswordEncryptor {
private static final String PWD_FMT = "%s:%s:%d";
private static final Pattern PWD_REGEX = Pattern.compile("(?<pwdHash>\\w+):(?<saltHash>\\w+):(?<iterations>[0-9]+)");
private static final String SECRET_KEY_FACTORY_NAME = "PBKDF2WithHmacSHA512";
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
/**
* Minimum number of iterations required is 1_000(rfc2898),
* pick greater as potentially safer in the case of brute-force attacks .
*/
private static final int ITERATIONS_COUNT = 10_000;
/** 64bit salt length based on the rfc2898 spec . */
private static final int SALT_LENGTH = 64 / 8;
@Override
public String encrypt(String password) {
requireNonNull(password, "Required non-null password");
final byte[] salt = new byte[SALT_LENGTH];
SECURE_RANDOM.nextBytes(salt);
final HashCode hash = computeHash(password.toCharArray(), salt, ITERATIONS_COUNT);
final HashCode saltHash = HashCode.fromBytes(salt);
return format(PWD_FMT, hash, saltHash, ITERATIONS_COUNT);
}
@Override
public boolean test(String password, String encryptedPassword) {
requireNonNull(password, "Required non-null password");
requireNonNull(password, "Required non-null encrypted password");
final Matcher matcher = PWD_REGEX.matcher(encryptedPassword);
if (!matcher.matches()) {
return false;
}
// retrieve salt, password hash and iterations count from hash
final Integer iterations = tryParse(matcher.group("iterations"));
final String salt = matcher.group("saltHash");
final String pwdHash = matcher.group("pwdHash");
// compute password's hash and test whether it matches to given hash
final HashCode hash = computeHash(password.toCharArray(), HashCode.fromString(salt).asBytes(), iterations);
return hash.toString().equals(pwdHash);
}
private HashCode computeHash(char[] password, byte[] salt, int iterations) {
try {
final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY_NAME);
final KeySpec keySpec = new PBEKeySpec(password, salt, iterations, 512);
return HashCode.fromBytes(keyFactory.generateSecret(keySpec).getEncoded());
} catch (NoSuchAlgorithmException | InvalidKeySpecException x) {
throw new RuntimeException(x.getMessage(), x);
}
}
}

View File

@ -0,0 +1,47 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.security;
/**
* Encrypts password in implementation specific way.
*
* @author Yevhenii Voevodin
*/
public interface PasswordEncryptor {
/**
* Encrypts the given {@code password}.
*
* @param password
* the plain password to be encrypted
* @return the encrypted password
* @throws NullPointerException
* when the password is null
* @throws RuntimeException
* when any error occurs during password encryption
*/
String encrypt(String password);
/**
* Tests whether given {@code password} is {@code encryptedPassword}.
*
* @param encryptedPassword
* encrypted password
* @param password
* the password to check
* @return true if given {@code password} is {@code encryptedPassword}
* @throws NullPointerException
* when either of arguments is null
* @throws RuntimeException
* when any error occurs during test
*/
boolean test(String password, String encryptedPassword);
}

View File

@ -0,0 +1,64 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.security;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.primitives.Bytes;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import static java.util.Objects.requireNonNull;
/**
* SHA-512 based encryptor {@code hash = sha512(password + salt) + salt}.
*
* @author Yevhenii Voevodin
*/
public class SHA512PasswordEncryptor implements PasswordEncryptor {
/** 64 bit salt length is based on the <a href="https://www.ietf.org/rfc/rfc2898.txt">source</a>. */
private static final int SALT_BYTES_LENGTH = 64 / 8;
/** SHA-512 produces 512 bits. */
private static final int ENCRYPTED_PASSWORD_BYTES_LENGTH = 512 / 8;
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private static final Charset PWD_CHARSET = Charset.forName("UTF-8");
@Override
public String encrypt(String password) {
requireNonNull(password, "Required non-null password");
// generate salt
final byte[] salt = new byte[SALT_BYTES_LENGTH];
SECURE_RANDOM.nextBytes(salt);
// sha512(password + salt)
final HashCode hash = Hashing.sha512().hashBytes(Bytes.concat(password.getBytes(PWD_CHARSET), salt));
final HashCode saltHash = HashCode.fromBytes(salt);
// add salt to the hash, result length (512 / 8) * 2 + (64 / 8) * 2 = 144
return hash.toString() + saltHash.toString();
}
@Override
public boolean test(String password, String passwordHash) {
requireNonNull(password, "Required non-null password");
requireNonNull(passwordHash, "Required non-null password's hash");
// retrieve salt from the hash
final int passwordHashLength = ENCRYPTED_PASSWORD_BYTES_LENGTH * 2;
if (passwordHash.length() < passwordHashLength + SALT_BYTES_LENGTH * 2) {
return false;
}
final HashCode saltHash = HashCode.fromString(passwordHash.substring(passwordHashLength));
// sha1(password + salt)
final HashCode hash = Hashing.sha512().hashBytes(Bytes.concat(password.getBytes(PWD_CHARSET), saltHash.asBytes()));
// test sha1(password + salt) + salt == passwordHash
return (hash.toString() + saltHash.toString()).equals(passwordHash);
}
}

View File

@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.security;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
/**
* @author Yevhenii Voevodin
*/
public class PasswordEncryptorsTest {
@Test(dataProvider = "encryptorsProvider")
public void testEncryption(PasswordEncryptor encryptor) throws Exception {
final String password = "password";
final String hash = encryptor.encrypt(password);
assertNotNull(hash, "encrypted password's hash");
assertTrue(encryptor.test(password, hash), "password test");
}
@DataProvider(name = "encryptorsProvider")
public Object[][] encryptorsProvider() {
return new Object[][] {
{new SHA512PasswordEncryptor()},
{new PBKDF2PasswordEncryptor()}
};
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>5.0.0-M2-SNAPSHOT</version>
</parent>
<artifactId>che-core-api-jdbc-vendor-h2</artifactId>
<name>Che Core :: API :: JDBC Vendor H2</name>
<dependencies>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink;
import org.eclipse.che.api.core.jdbc.jpa.DuplicateKeyException;
import org.eclipse.che.api.core.jdbc.jpa.IntegrityConstraintViolationException;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.ExceptionHandler;
import java.sql.SQLException;
/**
* Rethrows vendor specific exceptions as common exceptions.
* See <a href="http://www.h2database.com/javadoc/org/h2/api/ErrorCode.html">H2 error codes</a>.
*
* @author Yevhenii Voevodin
*/
public class H2ExceptionHandler implements ExceptionHandler {
public Object handleException(RuntimeException exception) {
if (exception instanceof DatabaseException && exception.getCause() instanceof SQLException) {
final SQLException sqlEx = (SQLException)exception.getCause();
switch (sqlEx.getErrorCode()) {
case 23505:
throw new DuplicateKeyException(exception.getMessage(), exception);
case 23506:
throw new IntegrityConstraintViolationException(exception.getMessage(), exception);
}
}
throw exception;
}
}

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>5.0.0-M2-SNAPSHOT</version>
</parent>
<artifactId>che-core-api-jdbc</artifactId>
<name>Che Core :: API :: JDBC</name>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc;
/**
* Defines common database error codes which should
* be used throughout the application in preference to
* vendor specific error codes.
*
* @author Yevhenii Voevodin
*/
public enum DBErrorCode {
/**
* When database error can't be described with one
* of the other values of this enumeration.
*/
UNDEFINED(-1),
/**
* When any of the unique constraints is violated
* e.g. duplicate key or unique index violation.
*/
DUPLICATE_KEY(1),
/**
* When entity referenced foreign key does not exist
*/
INTEGRITY_CONSTRAINT_VIOLATION(2);
private final int code;
DBErrorCode(int code) {
this.code = code;
}
/**
* Returns the code of this error.
*/
public int getCode() {
return code;
}
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc.jpa;
import org.eclipse.che.api.core.jdbc.DBErrorCode;
import javax.persistence.RollbackException;
/**
* Extends the standard {@link RollbackException} with an error code from {@link DBErrorCode}.
*
* @author Yevhenii Voevodin
*/
public class DetailedRollbackException extends RollbackException {
private DBErrorCode code;
public DetailedRollbackException(String message, Throwable cause, DBErrorCode code) {
super(message, cause);
this.code = code;
}
public DBErrorCode getCode() {
return code;
}
}

View File

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc.jpa;
import org.eclipse.che.api.core.jdbc.DBErrorCode;
/**
* Thrown when data couldn't be updated/stored due to unique constrain violation.
*
* @author Yevhenii Voevodin
* @see DBErrorCode#DUPLICATE_KEY
*/
public class DuplicateKeyException extends DetailedRollbackException {
public DuplicateKeyException(String message, Throwable cause) {
super(message, cause, DBErrorCode.DUPLICATE_KEY);
}
}

View File

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc.jpa;
import org.eclipse.che.api.core.jdbc.DBErrorCode;
import static org.eclipse.che.api.core.jdbc.DBErrorCode.INTEGRITY_CONSTRAINT_VIOLATION;
/**
* Throws during inserts/updates entity that restricted by referential integrity
* and given insert/update refers to non-existing entity.
*
* @author Anton Korneta
* @see DBErrorCode#INTEGRITY_CONSTRAINT_VIOLATION
*/
public class IntegrityConstraintViolationException extends DetailedRollbackException {
public IntegrityConstraintViolationException(String message, Throwable cause) {
super(message, cause, INTEGRITY_CONSTRAINT_VIOLATION);
}
}

View File

@ -0,0 +1,33 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc.jpa.eclipselink;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.persistence.sessions.server.ServerSession;
import javax.persistence.EntityManagerFactory;
/**
* Sets up {@link GuiceEntityListenerInjectionManager}.
*
* @author Yevhenii Voevodin
*/
@Singleton
public class EntityListenerInjectionManagerInitializer {
@Inject
public EntityListenerInjectionManagerInitializer(GuiceEntityListenerInjectionManager injManager, EntityManagerFactory emFactory) {
final ServerSession session = emFactory.unwrap(ServerSession.class);
session.setEntityListenerInjectionManager(injManager);
}
}

View File

@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc.jpa.eclipselink;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.cdi.EntityListenerInjectionManager;
import javax.naming.NamingException;
/**
* Allows to use dependency injection in entity listeners.
*
* <p>Example:
* <pre>
* class WorkspaceEntityListener {
*
* &#064;Inject EventBus bus; <- EventBus will be injected by Guice
*
* &#064;PreRemove
* public void preRemove(Workspace workspace) {
* bus.post(new BeforeWorkspaceRemovedEvent(workspace));
* }
* }
*
* &#064;Entity
* &#064;EntityListeners(WorkspaceEntityListener.class)
* class Workspace {
* // ...
* }
* </pre>
*
* @author Yevhenii Voevodin
*/
@Singleton
public class GuiceEntityListenerInjectionManager implements EntityListenerInjectionManager {
@Inject
private Injector injector;
@Override
public Object createEntityListenerAndInjectDependancies(Class entityListenerClass) throws NamingException {
try {
return injector.getInstance(entityListenerClass);
} catch (RuntimeException x) {
throw new NamingException(x.getLocalizedMessage());
}
}
@Override
public void cleanUp(AbstractSession session) {
// EntityListener objects are managed by Guice, nothing to cleanup
}
}

View File

@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.jdbc.jpa.guice;
import com.google.inject.Inject;
import com.google.inject.persist.PersistService;
/**
* Should be bound as eager singleton.
* See <a href="https://github.com/google/guice/wiki/JPA">doc</a>
*
* @author Yevhenii Voevodin
*/
public class JpaInitializer {
@Inject
public JpaInitializer(PersistService persistService) {
persistService.start();
}
}

View File

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
import java.util.Map;
/**
* Defines the contract for the factory action instance.
*
* @author Anton Korneta
*/
public interface Action {
/**
* Returns the IDE specific identifier of action e.g. ('openFile', 'editFile')
*/
String getId();
/**
* Returns properties of this action instance
*/
Map<String, String> getProperties();
}

View File

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
/**
* Defines the contract for the factory creator instance.
*
* @author Anton Korneta
*/
public interface Author {
/**
* Identifier of the user who created factory, it is mandatory
*/
String getUserId();
/**
* Creation time of factory, set by the server (in milliseconds, from Unix epoch, no timezone)
*/
Long getCreated();
}

View File

@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
/**
* Defines factory button.
*
* @author Anton Korneta
*/
public interface Button {
enum Type {
LOGO {
@Override
public String toString() {
return "logo";
}
},
NOLOGO {
@Override
public String toString() {
return "nologo";
}
};
public static Type getIgnoreCase(String name) {
for (Type type : values()) {
if (name.equalsIgnoreCase(type.toString())) {
return type;
}
}
throw new IllegalArgumentException();
}
}
/**
* Returns type of this button instance
*/
Type getType();
/**
* Returns attributes of this button instance
*/
ButtonAttributes getAttributes();
}

View File

@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
/**
* Defines factory button attributes.
*
* @author Anton Korneta
*/
public interface ButtonAttributes {
/**
* Returns factory button color
*/
String getColor();
/**
* Returns factory button counter
*/
Boolean getCounter();
/**
* Returns factory button logo
*/
String getLogo();
/**
* Returns factory button style
*/
String getStyle();
}

View File

@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
/**
* Defines the contract for the factory instance.
*
* @author Anton Korneta
*/
public interface Factory {
/**
* Returns the identifier of this factory instance,
* it is mandatory and unique.
*/
String getId();
/**
* Returns the version of this factory instance,
* it is mandatory.
*/
String getV();
/**
* Returns a name of this factory instance,
* the name is unique for creator.
*/
String getName();
/**
* Returns creator of this factory instance.
*/
Author getCreator();
/**
* Returns a workspace configuration of this factory instance,
* it is mandatory for every factory instance.
*/
WorkspaceConfig getWorkspace();
/**
* Returns restrictions of this factory instance.
*/
Policies getPolicies();
/**
* Returns factory button for this instance.
*/
Button getButton();
/**
* Returns IDE for this factory instance.
*/
Ide getIde();
}

View File

@ -0,0 +1,34 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
/**
* Defines the contract for the factory IDE instance.
*
* @author Anton Korneta
*/
public interface Ide {
/**
* Returns configuration of IDE on application loaded event
*/
OnAppLoaded getOnAppLoaded();
/**
* Returns configuration of IDE on application closed event
*/
OnAppClosed getOnAppClosed();
/**
* Returns configuration of IDE on projects loaded event
*/
OnProjectsLoaded getOnProjectsLoaded();
}

View File

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
import java.util.List;
/**
* Defines IDE look and feel on application closed event.
*
* @author Anton Korneta
*/
public interface OnAppClosed {
/**
* Returns actions for current event.
*/
List<? extends Action> getActions();
}

View File

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
import java.util.List;
/**
* Defines IDE look and feel on application loaded event.
*
* @author Anton Korneta
*/
public interface OnAppLoaded {
/**
* Returns actions for current event.
*/
List<? extends Action> getActions();
}

View File

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
import java.util.List;
/**
* Defines IDE look and feel on project opened event.
*
* @author Anton Korneta
*/
public interface OnProjectsLoaded {
/**
* Returns actions for current event.
*/
List<? extends Action> getActions();
}

View File

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.factory;
/**
* Defines the contract for the factory restrictions.
*
* @author Anton Korneta
*/
public interface Policies {
/**
* Restrict access if referer header doesn't match this field
*/
String getReferer();
/**
* Restrict access for factories used earlier then author supposes
*/
Long getSince();
/**
* Restrict access for factories used later then author supposes
*/
Long getUntil();
/**
* Re-open projects on factory 2-nd click
*/
String getMatch();
/**
* Workspace creation strategy
*/
String getCreate();
}

View File

@ -28,12 +28,6 @@ public interface Snapshot {
*/
String getType();
/**
* Snapshot namespace, which allows snapshot to be
* related to the certain workspace machine.
*/
String getNamespace();
/**
* Creation date of the snapshot
*/

View File

@ -36,6 +36,12 @@ public interface Workspace {
*/
String getNamespace();
/**
* Returns the name of the current workspace instance.
* Workspace name is unique per namespace.
*/
String getName();
/**
* Returns the status of the current workspace instance.
*

View File

@ -26,7 +26,11 @@ import java.util.Map;
public interface WorkspaceConfig {
/**
* Returns workspace name.
* Optional.
* Returns possible name of the workspace created from this configuration.
* If name doesn't conflict then the target workspace
* will have exactly the same name, but if the name conflicts or it is absent
* then any other name will be chose for the workspace.
*/
String getName();

View File

@ -43,10 +43,20 @@
<artifactId>guice</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
/**
* Skeletal implementation of the {@link ITestListener}.
* In most cases only 2 methods are needed {@link #onStart(ITestContext)} and {@link #onFinish(ITestContext)}.
*
* @author Yevhenii Voevodin
*/
public abstract class AbstractTestListener implements ITestListener {
@Override
public void onTestStart(ITestResult result) {}
@Override
public void onTestSuccess(ITestResult result) {}
@Override
public void onTestFailure(ITestResult result) {}
@Override
public void onTestSkipped(ITestResult result) {}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {}
@Override
public void onStart(ITestContext context) {}
@Override
public void onFinish(ITestContext context) {}
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck.repository;
import com.google.inject.Inject;
import com.google.inject.persist.UnitOfWork;
import javax.inject.Provider;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import java.util.Collection;
import static java.lang.String.format;
/**
* Simplifies implementation for Jpa repository in general case.
*
* Expected usage:
* <pre>
* class MyTckModule extends TckModule {
* &#064;Override configure() {
* bind(new TypeLiteral&lt;TckRepository&lt;UserImpl&gt;&gt;() {})
* .toInstance(new JpaTckRepository(Concrete.class));
* }
* }
* </pre>
*
* @param <T>
* type of the entity
* @author Yevhenii Voevodin
*/
public class JpaTckRepository<T> implements TckRepository<T> {
@Inject
protected Provider<EntityManager> managerProvider;
@Inject
protected UnitOfWork uow;
private final Class<T> entityClass;
public JpaTckRepository(Class<T> entityClass) {
this.entityClass = entityClass;
}
@Override
public void createAll(Collection<? extends T> entities) throws TckRepositoryException {
uow.begin();
final EntityManager manager = managerProvider.get();
try {
manager.getTransaction().begin();
entities.forEach(manager::persist);
manager.getTransaction().commit();
} catch (RuntimeException x) {
if (manager.getTransaction().isActive()) {
manager.getTransaction().rollback();
}
throw new TckRepositoryException(x.getLocalizedMessage(), x);
} finally {
uow.end();
}
}
@Override
public void removeAll() throws TckRepositoryException {
uow.begin();
final EntityManager manager = managerProvider.get();
try {
manager.getTransaction().begin();
// The query 'DELETE FROM Entity' won't be correct as it will ignore orphanRemoval
// and may also ignore some configuration options, while EntityManager#remove won't
manager.createQuery(format("SELECT e FROM %s e", getEntityName(entityClass)), entityClass)
.getResultList()
.forEach(manager::remove);
manager.getTransaction().commit();
} catch (RuntimeException x) {
if (manager.getTransaction().isActive()) {
manager.getTransaction().rollback();
}
throw new TckRepositoryException(x.getLocalizedMessage(), x);
} finally {
uow.end();
}
}
private String getEntityName(Class<?> clazz) {
if (!clazz.isAnnotationPresent(Entity.class)) {
return clazz.getSimpleName();
}
final Entity entity = clazz.getAnnotation(Entity.class);
if (entity.name().isEmpty()) {
return clazz.getSimpleName();
}
return entity.name();
}
}

View File

@ -20,7 +20,7 @@ import org.testng.ITestResult;
*
* @author Yevhenii Voevodin
*/
public class DBServerListener implements ITestListener {
public class DBServerListener extends AbstractTestListener {
public static final String DB_SERVER_URL_ATTRIBUTE_NAME = "db_server_url";
public static final String DB_SERVER_URL = "localhost:12345";
@ -29,22 +29,4 @@ public class DBServerListener implements ITestListener {
public void onStart(ITestContext context) {
context.setAttribute(DB_SERVER_URL_ATTRIBUTE_NAME, DB_SERVER_URL);
}
@Override
public void onFinish(ITestContext context) {}
@Override
public void onTestStart(ITestResult result) {}
@Override
public void onTestSuccess(ITestResult result) {}
@Override
public void onTestFailure(ITestResult result) {}
@Override
public void onTestSkipped(ITestResult result) {}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {}
}

View File

@ -30,5 +30,7 @@
<module>che-core-api-dto-maven-plugin</module>
<module>che-core-api-core</module>
<module>che-core-api-model</module>
<module>che-core-api-jdbc</module>
<module>che-core-api-jdbc-vendor-h2</module>
</modules>
</project>

View File

@ -12,7 +12,8 @@ package org.eclipse.che.ide.api.app;
import com.google.common.annotations.Beta;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.ide.api.machine.DevMachine;
import org.eclipse.che.ide.api.resources.Container;
@ -175,12 +176,15 @@ public interface AppContext {
void setStartUpActions(List<StartUpAction> startUpActions);
/**
* Returns {@link Factory} instance which id was set on startup, or {@code null} if no factory was specified.
* Returns {@link Factory} instance which id was set on startup,
* or {@code null} if no factory was specified.
*
* @return loaded factory or {@code null}
*/
Factory getFactory();
FactoryDto getFactory();
void setFactory(FactoryDto factory);
String getWorkspaceId();
/* Deprecated methods */

View File

@ -12,7 +12,7 @@ package org.eclipse.che.ide.api.factory;
import com.google.gwt.event.shared.GwtEvent;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
/**
@ -22,9 +22,9 @@ import org.eclipse.che.api.factory.shared.dto.Factory;
*/
public class FactoryAcceptedEvent extends GwtEvent<FactoryAcceptedHandler> {
private Factory factory;
private FactoryDto factory;
public FactoryAcceptedEvent(Factory factory) {
public FactoryAcceptedEvent(FactoryDto factory) {
this.factory = factory;
}
@ -41,7 +41,7 @@ public class FactoryAcceptedEvent extends GwtEvent<FactoryAcceptedHandler> {
}
public Factory getFactory() {
public FactoryDto getFactory() {
return factory;
}
}

View File

@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.che.ide.api.factory;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
@ -36,7 +36,7 @@ public interface FactoryServiceClient {
* indicates whether or not factory should be validated by accept validator
* @return Factory through a Promise
*/
Promise<Factory> getFactory(@NotNull String factoryId, boolean validate);
Promise<FactoryDto> getFactory(@NotNull String factoryId, boolean validate);
/**
* @param factoryId
@ -58,7 +58,7 @@ public interface FactoryServiceClient {
* @param callback
* callback which returns snippet of the factory or exception if occurred
*/
void getFactoryJson(@NotNull String workspaceId, @NotNull String path, @NotNull AsyncRequestCallback<Factory> callback);
void getFactoryJson(@NotNull String workspaceId, @NotNull String path, @NotNull AsyncRequestCallback<FactoryDto> callback);
/**
* Get factory as JSON.
@ -67,18 +67,18 @@ public interface FactoryServiceClient {
* workspace id
* @param path
* project path
* @return a promise that resolves to the {@link Factory}, or rejects with an error
* @return a promise that resolves to the {@link FactoryDto}, or rejects with an error
*/
Promise<Factory> getFactoryJson(@NotNull String workspaceId, @Nullable String path);
Promise<FactoryDto> getFactoryJson(@NotNull String workspaceId, @Nullable String path);
/**
* Save factory to storage.
*
* @param factory
* factory to save
* @return a promise that resolves to the {@link Factory}, or rejects with an error
* @return a promise that resolves to the {@link FactoryDto}, or rejects with an error
*/
Promise<Factory> saveFactory(@NotNull Factory factory);
Promise<FactoryDto> saveFactory(@NotNull FactoryDto factory);
/**
* Save factory to storage.
@ -87,9 +87,9 @@ public interface FactoryServiceClient {
* the number of the items to skip
* @param maxItems
* the limit of the items in the response, default is 30
* @return a promise that will provide a list of {@link Factory}s, or rejects with an error
* @return a promise that will provide a list of {@link FactoryDto}s, or rejects with an error
*/
Promise<List<Factory>> findFactory(Integer skipCount, Integer maxItems, List<Pair<String, String>> params);
Promise<List<FactoryDto>> findFactory(Integer skipCount, Integer maxItems, List<Pair<String, String>> params);
/**
* Updates factory by id
@ -100,7 +100,7 @@ public interface FactoryServiceClient {
* update body
* @return updated factory
*/
Promise<Factory> updateFactory(String id, Factory factory);
Promise<FactoryDto> updateFactory(String id, FactoryDto factory);
/**
@ -112,6 +112,6 @@ public interface FactoryServiceClient {
* indicates whether or not factory should be validated by accept validator
* @return Factory through a Promise
*/
Promise<Factory> resolveFactory(@NotNull Map<String, String> factoryParameters, boolean validate);
Promise<FactoryDto> resolveFactory(@NotNull Map<String, String> factoryParameters, boolean validate);
}

View File

@ -15,7 +15,7 @@ import com.google.gwt.http.client.RequestBuilder;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.MimeType;
@ -68,13 +68,13 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
* @return Factory through a Promise
*/
@Override
public Promise<Factory> getFactory(@NotNull String factoryId, boolean validate) {
public Promise<FactoryDto> getFactory(@NotNull String factoryId, boolean validate) {
StringBuilder url = new StringBuilder(API_FACTORY_BASE_URL).append(factoryId);
if (validate) {
url.append("?").append("validate=true");
}
return asyncRequestFactory.createGetRequest(url.toString()).header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON)
.send(unmarshallerFactory.newUnmarshaller(Factory.class));
.send(unmarshallerFactory.newUnmarshaller(FactoryDto.class));
}
/**
@ -90,7 +90,7 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
* {@inheritDoc}
*/
@Override
public void getFactoryJson(String workspaceId, String path, AsyncRequestCallback<Factory> callback) {
public void getFactoryJson(String workspaceId, String path, AsyncRequestCallback<FactoryDto> callback) {
final StringBuilder url = new StringBuilder(API_FACTORY_BASE_URL + "workspace/").append(workspaceId);
if (path != null) {
url.append("?path=").append(path);
@ -102,7 +102,7 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
}
@Override
public Promise<Factory> getFactoryJson(String workspaceId, String path) {
public Promise<FactoryDto> getFactoryJson(String workspaceId, String path) {
String url = API_FACTORY_BASE_URL + "workspace/" + workspaceId;
if (path != null) {
url += path;
@ -111,20 +111,20 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
return asyncRequestFactory.createGetRequest(url)
.header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON)
.loader(loaderFactory.newLoader("Getting info about factory..."))
.send(unmarshallerFactory.newUnmarshaller(Factory.class));
.send(unmarshallerFactory.newUnmarshaller(FactoryDto.class));
}
@Override
public Promise<Factory> saveFactory(@NotNull Factory factory) {
public Promise<FactoryDto> saveFactory(@NotNull FactoryDto factory) {
return asyncRequestFactory.createPostRequest(API_FACTORY_BASE_URL, factory)
.header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON)
.header(HTTPHeader.CONTENT_TYPE, MimeType.APPLICATION_JSON)
.loader(loaderFactory.newLoader("Creating factory..."))
.send(unmarshallerFactory.newUnmarshaller(Factory.class));
.send(unmarshallerFactory.newUnmarshaller(FactoryDto.class));
}
@Override
public Promise<List<Factory>> findFactory(@Nullable Integer skipCount,
public Promise<List<FactoryDto>> findFactory(@Nullable Integer skipCount,
@Nullable Integer maxItems,
@Nullable List<Pair<String, String>> params) {
final List<Pair<String, String>> allParams = new LinkedList<>();
@ -141,15 +141,15 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
.header(HTTPHeader.ACCEPT, MimeType.APPLICATION_JSON)
.header(HTTPHeader.CONTENT_TYPE, MimeType.APPLICATION_JSON)
.loader(loaderFactory.newLoader("Searching factory..."))
.send(unmarshallerFactory.newListUnmarshaller(Factory.class));
.send(unmarshallerFactory.newListUnmarshaller(FactoryDto.class));
}
@Override
public Promise<Factory> updateFactory(String id, Factory factory) {
public Promise<FactoryDto> updateFactory(String id, FactoryDto factory) {
return asyncRequestFactory.createRequest(RequestBuilder.PUT, API_FACTORY_BASE_URL + id, factory, false)
.header(HTTPHeader.CONTENT_TYPE, MimeType.APPLICATION_JSON)
.loader(loaderFactory.newLoader("Updating factory..."))
.send(unmarshallerFactory.newUnmarshaller(Factory.class));
.send(unmarshallerFactory.newUnmarshaller(FactoryDto.class));
}
@ -163,7 +163,7 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
* @return Factory through a Promise
*/
@Override
public Promise<Factory> resolveFactory(@NotNull final Map<String, String> factoryParameters, boolean validate) {
public Promise<FactoryDto> resolveFactory(@NotNull final Map<String, String> factoryParameters, boolean validate) {
// Init string with JAX-RS path
StringBuilder url = new StringBuilder(API_FACTORY_BASE_URL + "resolver");
@ -173,7 +173,7 @@ public class FactoryServiceClientImpl implements FactoryServiceClient {
url.append("?validate=true");
}
return asyncRequestFactory.createPostRequest(url.toString(), toJson(factoryParameters)).header(ACCEPT, APPLICATION_JSON)
.send(unmarshallerFactory.newUnmarshaller(Factory.class));
.send(unmarshallerFactory.newUnmarshaller(FactoryDto.class));
}
/**

View File

@ -18,6 +18,7 @@
<source path="machine"/>
<source path="project"/>
<source path="workspace"/>
<source path="factory"/>
<source path="user"/>
</module>

View File

@ -16,7 +16,7 @@ import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
@ -82,11 +82,11 @@ public class AppContextImpl implements AppContext,
private final BrowserQueryFieldRenderer browserQueryFieldRenderer;
private final List<String> projectsInImport;
private WorkspaceDto usersWorkspaceDto;
private CurrentUser currentUser;
private Factory factory;
private DevMachine devMachine;
private Path projectsRoot;
private WorkspaceDto usersWorkspaceDto;
private CurrentUser currentUser;
private FactoryDto factory;
private DevMachine devMachine;
private Path projectsRoot;
/**
* List of actions with parameters which comes from startup URL.
* Can be processed after IDE initialization as usual after starting ws-agent.
@ -170,11 +170,12 @@ public class AppContextImpl implements AppContext,
}
@Override
public Factory getFactory() {
public FactoryDto getFactory() {
return factory;
}
public void setFactory(Factory factory) {
@Override
public void setFactory(FactoryDto factory) {
this.factory = factory;
}

View File

@ -17,7 +17,7 @@ import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.promises.client.Function;
import org.eclipse.che.api.promises.client.FunctionException;
import org.eclipse.che.api.promises.client.Operation;
@ -119,7 +119,7 @@ public class FactoryWorkspaceComponent extends WorkspaceComponent {
// get workspace ID to use dedicated workspace for this factory
this.workspaceId = browserQueryFieldRenderer.getParameterFromURLByName("workspaceId");
Promise<Factory> factoryPromise;
Promise<FactoryDto> factoryPromise;
// now search if it's a factory based on id or from parameters
if (factoryParameters.containsKey("id")) {
factoryPromise = factoryServiceClient.getFactory(factoryParameters.get("id"), true);
@ -127,9 +127,10 @@ public class FactoryWorkspaceComponent extends WorkspaceComponent {
factoryPromise = factoryServiceClient.resolveFactory(factoryParameters, true);
}
factoryPromise.then(new Function<Factory, Void>() {
Promise<Void> promise = factoryPromise.then(new Function<FactoryDto, Void>() {
@Override
public Void apply(final Factory factory) throws FunctionException {
public Void apply(final FactoryDto factory) throws FunctionException {
if (appContext instanceof AppContextImpl) {
((AppContextImpl)appContext).setFactory(factory);
}

View File

@ -25,6 +25,7 @@ import java.util.Map;
public class WorkspaceImpl implements Workspace {
private final String id;
private final String name;
private final WorkspaceRuntime workspaceRuntime;
private final String namespace;
private final WorkspaceStatus status;
@ -32,8 +33,10 @@ public class WorkspaceImpl implements Workspace {
private final boolean temporary;
private final WorkspaceConfig config;
public WorkspaceImpl(Workspace workspace) {
id = workspace.getId();
name = workspace.getName();
workspaceRuntime = workspace.getRuntime();
namespace = workspace.getNamespace();
status = workspace.getStatus();
@ -53,6 +56,11 @@ public class WorkspaceImpl implements Workspace {
return namespace;
}
@Override
public String getName() {
return name;
}
@Override
public WorkspaceStatus getStatus() {
return status;

View File

@ -63,14 +63,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-java-mysql.svg",
"mediaType": "image/svg+xml"
@ -163,14 +155,6 @@
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-che.svg",
"mediaType": "image/svg+xml"
@ -240,14 +224,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-java.svg",
"mediaType": "image/svg+xml"
@ -294,14 +270,6 @@
"defaultEnv": "default",
"description": null
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-blank.svg",
"mediaType": "image/svg+xml"
@ -367,14 +335,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-android.svg",
"mediaType": "image/svg+xml"
@ -442,14 +402,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-cpp.svg",
"mediaType": "image/svg+xml"
@ -522,14 +474,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-dotnet.svg",
"mediaType": "image/svg+xml"
@ -593,14 +537,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-go.svg",
"mediaType": "image/svg+xml"
@ -660,14 +596,6 @@
"defaultEnv": "default",
"description": null
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-hadoop.svg",
"mediaType": "image/svg+xml"
@ -745,14 +673,6 @@
"defaultEnv": "default",
"description": null
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-node.svg",
"mediaType": "image/svg+xml"
@ -849,14 +769,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-php.svg",
"mediaType": "image/svg+xml"
@ -922,14 +834,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-python.svg",
"mediaType": "image/svg+xml"
@ -1008,14 +912,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-ruby.svg",
"mediaType": "image/svg+xml"
@ -1063,15 +959,7 @@
"name": "default",
"defaultEnv": "default",
"description": null
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
]
}
},
{
"id": "java-centos",
@ -1140,14 +1028,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-java.svg",
"mediaType": "image/svg+xml"
@ -1220,14 +1100,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-java.svg",
"mediaType": "image/svg+xml"
@ -1306,14 +1178,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-php.svg",
"mediaType": "image/svg+xml"
@ -1379,14 +1243,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-python.svg",
"mediaType": "image/svg+xml"
@ -1449,14 +1305,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-python.svg",
"mediaType": "image/svg+xml"
@ -1527,15 +1375,7 @@
"name": "default",
"defaultEnv": "default",
"description": null
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
]
}
},
{
"id": "tomee-default",
@ -1595,14 +1435,6 @@
}
]
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-java.svg",
"mediaType": "image/svg+xml"
@ -1650,15 +1482,7 @@
"source": {
"type": "image",
"origin": "codenvy/ubuntu_jre"
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
]
}
},
{
"id": "bitnami-express",
@ -1723,14 +1547,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"
@ -1809,14 +1625,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"
@ -1886,14 +1694,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"
@ -1962,14 +1762,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"
@ -2038,14 +1830,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"
@ -2114,14 +1898,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"
@ -2190,14 +1966,6 @@
"description": null,
"commands": []
},
"acl": [
{
"user": "*",
"actions": [
"search"
]
}
],
"stackIcon": {
"name": "type-bitnami.svg",
"mediaType": "image/svg+xml"

View File

@ -441,7 +441,7 @@ public class ImportOperation extends WorkspaceModifyOperation {
*
* @param resource resource to cast/adapt
* @return the resource either casted to or adapted to an IFile.
* <code>null</code> if the resource does not adapt to IFile
* <code>null</code> if the resource does not adapt to IFile
*/
IFile getFile(IResource resource) {
if (resource instanceof IFile) {
@ -460,7 +460,7 @@ public class ImportOperation extends WorkspaceModifyOperation {
*
* @param resource resource to cast/adapt
* @return the resource either casted to or adapted to an IFolder.
* <code>null</code> if the resource does not adapt to IFolder
* <code>null</code> if the resource does not adapt to IFolder
*/
IFolder getFolder(IResource resource) {
if (resource instanceof IFolder) {

View File

@ -134,7 +134,7 @@ public class KeysInjectorTest {
@Test
public void shouldNotInjectSshKeysWhenThereAreNotAnyPairWithPublicKey() throws Exception {
when(sshManager.getPairs(anyString(), anyString()))
.thenReturn(Collections.singletonList(new SshPairImpl("machine", "myPair", null, null)));
.thenReturn(Collections.singletonList(new SshPairImpl(OWNER_ID, "machine", "myPair", null, null)));
subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING)
.withMachineId(MACHINE_ID)
@ -148,8 +148,8 @@ public class KeysInjectorTest {
@Test
public void shouldInjectSshKeysWhenThereAreAnyPairWithNotNullPublicKey() throws Exception {
when(sshManager.getPairs(anyString(), anyString()))
.thenReturn(Arrays.asList(new SshPairImpl("machine", "myPair", "publicKey1", null),
new SshPairImpl("machine", "myPair", "publicKey2", null)));
.thenReturn(Arrays.asList(new SshPairImpl(OWNER_ID, "machine", "myPair", "publicKey1", null),
new SshPairImpl(OWNER_ID, "machine", "myPair", "publicKey2", null)));
subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING)
.withMachineId(MACHINE_ID)
@ -170,7 +170,7 @@ public class KeysInjectorTest {
@Test
public void shouldSendMessageInMachineLoggerWhenSomeErrorOcursOnKeysInjection() throws Exception {
when(sshManager.getPairs(anyString(), anyString()))
.thenReturn(Collections.singletonList(new SshPairImpl("machine", "myPair", "publicKey1", null)));
.thenReturn(Collections.singletonList(new SshPairImpl(OWNER_ID, "machine", "myPair", "publicKey1", null)));
when(logMessage.getType()).thenReturn(LogMessage.Type.STDERR);
when(logMessage.getContent()).thenReturn("FAILED");

View File

@ -12,7 +12,7 @@ package org.eclipse.che.plugin.maven.client.project;
import com.google.web.bindery.event.shared.EventBus;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
@ -54,7 +54,7 @@ public class MavenModelImporter implements FactoryAcceptedHandler {
@Override
public void onFactoryAccepted(FactoryAcceptedEvent event) {
final Factory factory = event.getFactory();
final FactoryDto factory = event.getFactory();
final List<ProjectConfigDto> projects = factory.getWorkspace().getProjects();
final List<String> paths = new ArrayList<>();
for (ProjectConfigDto project : projects) {

45
pom.xml
View File

@ -80,6 +80,17 @@
<version>${che.version}</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-account</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-account</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-agent</artifactId>
@ -125,6 +136,12 @@
<artifactId>che-core-api-factory</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-factory</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-factory-shared</artifactId>
@ -151,11 +168,27 @@
<artifactId>che-core-api-infrastructure-local</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc-vendor-h2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-machine</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-machine</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-machine-shared</artifactId>
@ -191,6 +224,12 @@
<artifactId>che-core-api-ssh</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-ssh</artifactId>
<version>${che.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-ssh-shared</artifactId>
@ -212,6 +251,12 @@
<artifactId>che-core-api-user-shared</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-workspace</artifactId>
<version>${che.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-workspace</artifactId>

View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-master-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>5.0.0-M2-SNAPSHOT</version>
</parent>
<artifactId>che-core-api-account</artifactId>
<name>Che Core :: API :: Account</name>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-lang</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc-vendor-h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-json</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockitong</groupId>
<artifactId>mockitong</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Create the test jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>**/spi/tck/*.*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.api;
import org.eclipse.che.account.shared.model.Account;
import org.eclipse.che.account.spi.AccountDao;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import javax.inject.Inject;
import javax.inject.Singleton;
import static java.util.Objects.requireNonNull;
/**
* Facade for Account related operations.
*
* @author Sergii Leschenko
*/
@Singleton
public class AccountManager {
private final AccountDao accountDao;
@Inject
public AccountManager(AccountDao accountDao) {
this.accountDao = accountDao;
}
/**
* Gets account by identifier.
*
* @param id
* id of account to fetch
* @return account instance with given id
* @throws NullPointerException
* when {@code id} is null
* @throws NotFoundException
* when account with given {@code id} was not found
* @throws ServerException
* when any other error occurs during account fetching
*/
public Account getById(String id) throws NotFoundException, ServerException {
requireNonNull(id, "Required non-null account id");
return accountDao.getById(id);
}
/**
* Gets account by name.
*
* @param name
* name of account to fetch
* @return account instance with given name
* @throws NullPointerException
* when {@code name} is null
* @throws NotFoundException
* when account with given {@code name} was not found
* @throws ServerException
* when any other error occurs during account fetching
*/
public Account getByName(String name) throws NotFoundException, ServerException {
requireNonNull(name, "Required non-null account name");
return accountDao.getByName(name);
}
}

View File

@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.api;
import org.eclipse.che.account.spi.AccountDao;
import org.eclipse.che.account.spi.jpa.JpaAccountDao;
import com.google.inject.AbstractModule;
/**
* @author Sergii Leschenko
*/
public class AccountModule extends AbstractModule {
@Override
protected void configure() {
bind(AccountDao.class).to(JpaAccountDao.class);
}
}

View File

@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.event;
import org.eclipse.che.account.spi.AccountImpl;
/**
* Published before {@link AccountImpl account} removed.
*
* @author Antona Korneta
*/
public class BeforeAccountRemovedEvent {
private final AccountImpl account;
public BeforeAccountRemovedEvent(AccountImpl account) {
this.account = account;
}
/** Returns account which is going to be removed. */
public AccountImpl getAccount() {
return account;
}
}

View File

@ -8,23 +8,24 @@
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.acl;
import java.util.List;
package org.eclipse.che.account.shared.model;
/**
* This is the interface used for representing one entry in an Access Control List (ACL).
*
* @author Sergii Leschenko
*/
public interface AclEntry {
public interface Account {
/**
* Returns user id or '*' for all users
* Returns account id
*/
String getUser();
String getId();
/**
* Returns list of actions which are allowed to perform for specified user
* Returns name of account
*/
List<String> getActions();
String getName();
/**
* Returns type of account
*/
String getType();
}

View File

@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
/**
* Defines data access object for {@link AccountImpl}
*
* @author Sergii Leschenko
*/
public interface AccountDao {
/**
* Gets account by identifier.
*
* @param id
* account identifier
* @return account instance with given id
* @throws NullPointerException
* when {@code id} is null
* @throws NotFoundException
* when account with given {@code id} was not found
* @throws ServerException
* when any other error occurs during account fetching
*/
AccountImpl getById(String id) throws NotFoundException, ServerException;
/**
* Gets account by name.
*
* @param name
* account name
* @return account instance with given name
* @throws NullPointerException
* when {@code name} is null
* @throws NotFoundException
* when account with given {@code name} was not found
* @throws ServerException
* when any other error occurs during account fetching
*/
AccountImpl getByName(String name) throws ServerException, NotFoundException;
}

View File

@ -0,0 +1,117 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi;
import org.eclipse.che.account.shared.model.Account;
import org.eclipse.che.account.spi.jpa.AccountEntityListener;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.util.Objects;
/**
* Data object for {@link Account}.
*
* @author Sergii Leschenko
*/
@Entity(name = "Account")
@NamedQueries(
{
@NamedQuery(name = "Account.getByName",
query = "SELECT a " +
"FROM Account a " +
"WHERE a.name = :name")
}
)
@Table(indexes = @Index(columnList = "name", unique = true))
@EntityListeners(AccountEntityListener.class)
public class AccountImpl implements Account {
@Id
protected String id;
@Column(nullable = false)
protected String name;
@Basic
private String type;
public AccountImpl() {}
public AccountImpl(String id, String name, String type) {
this.id = id;
this.name = name;
this.type = type;
}
public AccountImpl(Account account) {
this(account.getId(), account.getName(), account.getType());
}
@Override
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof AccountImpl)) return false;
AccountImpl account = (AccountImpl)o;
return Objects.equals(id, account.id) &&
Objects.equals(name, account.name);
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hash(id);
hash = 31 * hash + Objects.hash(name);
return hash;
}
@Override
public String toString() {
return "AccountImpl{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}

View File

@ -0,0 +1,90 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi;
import org.eclipse.che.account.api.AccountManager;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.commons.lang.NameGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.regex.Pattern;
/**
* Utils for account validation.
*
* @author Sergii Leschenko
*/
// TODO extract normalization code from the validator as it is not related to the validation at all
@Singleton
public class AccountValidator {
private static final Logger LOG = LoggerFactory.getLogger(AccountValidator.class);
private static final Pattern ILLEGAL_ACCOUNT_NAME_CHARACTERS = Pattern.compile("[^a-zA-Z0-9]");
private static final Pattern VALID_ACCOUNT_NAME = Pattern.compile("^[a-zA-Z0-9]*");
private final AccountManager accountManager;
@Inject
public AccountValidator(AccountManager accountManager) {
this.accountManager = accountManager;
}
/**
* Validate name, if it doesn't contain illegal characters
*
* @param name
* account name
* @return true if valid name, false otherwise
*/
public boolean isValidName(String name) {
return name != null && VALID_ACCOUNT_NAME.matcher(name).matches();
}
/**
* Remove illegal characters from account name, to make it URL-friendly.
* If all characters are illegal, return automatically generated account name with specified prefix.
* Also ensures account name is unique, if not, adds digits to it's end.
*
* @param name
* account name
* @param prefix
* prefix to add to generated name
* @return account name without illegal characters
*/
public String normalizeAccountName(String name, String prefix) throws ServerException {
String normalized = ILLEGAL_ACCOUNT_NAME_CHARACTERS.matcher(name).replaceAll("");
String candidate = normalized.isEmpty() ? NameGenerator.generate(prefix, 4) : normalized;
int i = 1;
try {
while (accountExists(candidate)) {
candidate = normalized.isEmpty() ? NameGenerator.generate(prefix, 4) : normalized + String.valueOf(i++);
}
} catch (ServerException e) {
LOG.warn("Error occurred during account name normalization", e);
throw e;
}
return candidate;
}
private boolean accountExists(String accountName) throws ServerException {
try {
accountManager.getByName(accountName);
} catch (NotFoundException e) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi.jpa;
import org.eclipse.che.account.event.BeforeAccountRemovedEvent;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.notification.EventService;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.PreRemove;
/**
* Callback for {@link AccountImpl account} jpa related events.
*
* @author Anton Korneta.
*/
@Singleton
public class AccountEntityListener {
@Inject
private EventService eventService;
@PreRemove
private void preRemove(AccountImpl account) {
eventService.publish(new BeforeAccountRemovedEvent(account));
}
}

View File

@ -0,0 +1,75 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi.jpa;
import com.google.inject.persist.Transactional;
import org.eclipse.che.account.spi.AccountDao;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
/**
* JPA based implementation of {@link AccountDao}.
*
* @author Sergii Leschenko
*/
@Singleton
public class JpaAccountDao implements AccountDao {
private final Provider<EntityManager> managerProvider;
@Inject
public JpaAccountDao(Provider<EntityManager> managerProvider) {
this.managerProvider = managerProvider;
}
@Override
@Transactional
public AccountImpl getById(String id) throws NotFoundException, ServerException {
requireNonNull(id, "Required non-null account id");
final EntityManager manager = managerProvider.get();
try {
AccountImpl account = manager.find(AccountImpl.class, id);
if (account == null) {
throw new NotFoundException(format("Account with id '%s' was not found", id));
}
return account;
} catch (RuntimeException x) {
throw new ServerException(x.getLocalizedMessage(), x);
}
}
@Override
@Transactional
public AccountImpl getByName(String name) throws ServerException, NotFoundException {
requireNonNull(name, "Required non-null account name");
final EntityManager manager = managerProvider.get();
try {
return manager.createNamedQuery("Account.getByName",
AccountImpl.class)
.setParameter("name", name)
.getSingleResult();
} catch (NoResultException e) {
throw new NotFoundException(String.format("Account with name '%s' was not found", name));
} catch (RuntimeException e) {
throw new ServerException(e.getLocalizedMessage(), e);
}
}
}

View File

@ -0,0 +1,92 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi;
import org.eclipse.che.account.api.AccountManager;
import org.eclipse.che.api.core.NotFoundException;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doThrow;
/**
* Tests of {@link AccountValidator}.
*
* @author Mihail Kuznyetsov
* @author Yevhenii Voevodin
* @author Sergii Leschenko
*/
@Listeners(MockitoTestNGListener.class)
public class AccountValidatorTest {
@Mock
private AccountManager accountManager;
@InjectMocks
private AccountValidator accountValidator;
@Test(dataProvider = "normalizeNames")
public void testNormalizeAccountName(String input, String expected) throws Exception {
doThrow(NotFoundException.class).when(accountManager).getByName(anyString());
Assert.assertEquals(accountValidator.normalizeAccountName(input, "account"), expected);
}
@Test
public void testNormalizeAccountNameWhenInputDoesNotContainAnyValidCharacter() throws Exception {
doThrow(NotFoundException.class).when(accountManager).getByName(anyString());
Assert.assertTrue(accountValidator.normalizeAccountName("#", "name").startsWith("name"));
}
@Test(dataProvider = "validNames")
public void testValidUserName(String input, boolean expected) throws Exception {
doThrow(NotFoundException.class).when(accountManager).getByName(anyString());
Assert.assertEquals(accountValidator.isValidName(input), expected);
}
@DataProvider(name = "normalizeNames")
public Object[][] normalizeNames() {
return new Object[][] {{"test", "test"},
{"test123", "test123"},
{"test 123", "test123"},
{"test@gmail.com", "testgmailcom"},
{"TEST", "TEST"},
{"test-", "test"},
{"te-st", "test"},
{"-test", "test"},
{"te_st", "test"},
{"te#st", "test"}
};
}
@DataProvider(name = "validNames")
public Object[][] validNames() {
return new Object[][] {{"test", true},
{"test123", true},
{"test 123", false},
{"test@gmail.com", false},
{"TEST", true},
{"test-", false},
{"te-st", false},
{"-test", false},
{"te_st", false},
{"te#st", false}
};
}
}

View File

@ -0,0 +1,100 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi.tck;
import org.eclipse.che.account.spi.AccountDao;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.commons.lang.NameGenerator;
import org.eclipse.che.commons.test.tck.TckModuleFactory;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepositoryException;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import javax.inject.Inject;
import static java.util.Arrays.asList;
import static org.testng.Assert.assertEquals;
/**
* Tests {@link AccountDao} contract.
*
* @author Sergii Leschenko
*/
@Guice(moduleFactory = TckModuleFactory.class)
@Test(suiteName = AccountDaoTest.SUITE_NAME)
public class AccountDaoTest {
public static final String SUITE_NAME = "AccountDaoTck";
private AccountImpl[] accounts;
@Inject
private AccountDao accountDao;
@Inject
private TckRepository<AccountImpl> accountRepo;
@BeforeMethod
private void setUp() throws TckRepositoryException {
accounts = new AccountImpl[2];
accounts[0] = new AccountImpl(NameGenerator.generate("account", 10), "test1", "test");
accounts[1] = new AccountImpl(NameGenerator.generate("account", 10), "test2", "test");
accountRepo.createAll(asList(accounts));
}
@AfterMethod
private void cleanup() throws TckRepositoryException {
accountRepo.removeAll();
}
@Test
public void shouldGetAccountById() throws Exception {
final AccountImpl account = accounts[0];
final AccountImpl found = accountDao.getById(account.getId());
assertEquals(account, found);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionOnGettingNonExistingAccountById() throws Exception {
accountDao.getById("non-existing-account");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingAccountByNullId() throws Exception {
accountDao.getById(null);
}
@Test
public void shouldGetAccountByName() throws Exception {
final AccountImpl account = accounts[0];
final AccountImpl found = accountDao.getByName(account.getName());
assertEquals(account, found);
}
@Test(expectedExceptions = NotFoundException.class)
public void shouldThrowNotFoundExceptionOnGettingNonExistingaccountByName() throws Exception {
accountDao.getByName("non-existing-account");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeOnGettingAccountByNullName() throws Exception {
accountDao.getByName(null);
}
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.account.spi.tck.jpa;
import com.google.inject.TypeLiteral;
import com.google.inject.persist.jpa.JpaPersistModule;
import org.eclipse.che.account.spi.AccountDao;
import org.eclipse.che.account.spi.AccountImpl;
import org.eclipse.che.account.spi.jpa.JpaAccountDao;
import org.eclipse.che.api.core.jdbc.jpa.eclipselink.EntityListenerInjectionManagerInitializer;
import org.eclipse.che.api.core.jdbc.jpa.guice.JpaInitializer;
import org.eclipse.che.commons.test.tck.TckModule;
import org.eclipse.che.commons.test.tck.repository.JpaTckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
/**
* @author Sergii Leschenko
*/
public class AccountJpaTckModule extends TckModule {
@Override
protected void configure() {
install(new JpaPersistModule("main"));
bind(JpaInitializer.class).asEagerSingleton();
bind(EntityListenerInjectionManagerInitializer.class).asEagerSingleton();
bind(new TypeLiteral<TckRepository<AccountImpl>>() {}).toInstance(new JpaTckRepository<>(AccountImpl.class));
bind(AccountDao.class).to(JpaAccountDao.class);
}
}

View File

@ -0,0 +1,34 @@
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd" version="1.0">
<persistence-unit name="main" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.eclipse.che.account.spi.AccountImpl</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="eclipselink.exception-handler" value="org.eclipse.che.api.core.h2.jdbc.jpa.eclipselink.H2ExceptionHandler"/>
<property name="eclipselink.target-server" value="None"/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
<property name="eclipselink.logging.logger" value="DefaultLogger"/>
<property name="eclipselink.logging.level" value="SEVERE"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -0,0 +1 @@
org.eclipse.che.account.spi.tck.jpa.AccountJpaTckModule

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="stdout"/>
</root>
</configuration>

View File

@ -0,0 +1,35 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.shared;
/**
* Constants for Factory API.
*
* @author Anton Korneta
*/
public final class Constants {
// factory links rel attributes
public static final String IMAGE_REL_ATT = "image";
public static final String RETRIEVE_FACTORY_REL_ATT = "self";
public static final String SNIPPET_REL_ATT = "snippet";
public static final String FACTORY_ACCEPTANCE_REL_ATT = "accept";
public static final String NAMED_FACTORY_ACCEPTANCE_REL_ATT = "accept-named";
public static final String ACCEPTED_REL_ATT = "accepted";
// factory snippet types
public static final String MARKDOWN_SNIPPET_TYPE = "markdown";
public static final String IFRAME_SNIPPET_TYPE = "iframe";
public static final String HTML_SNIPPET_TYPE = "html";
public static final String URL_SNIPPET_TYPE = "url";
private Constants() {}
}

View File

@ -11,6 +11,7 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.Author;
import org.eclipse.che.dto.shared.DTO;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
@ -21,7 +22,30 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* @author Alexander Garagatyi
*/
@DTO
public interface Author {
public interface AuthorDto extends Author {
/**
* Id of user that create factory, set by the server
*/
@Override
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
String getUserId();
void setUserId(String userId);
AuthorDto withUserId(String userId);
/**
* @return Creation time of factory, set by the server (in milliseconds, from Unix epoch, no timezone)
*/
@Override
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
Long getCreated();
void setCreated(Long created);
AuthorDto withCreated(Long created);
/**
* Name of the author
*/
@ -30,7 +54,7 @@ public interface Author {
void setName(String name);
Author withName(String name);
AuthorDto withName(String name);
/**
* Email of the author
@ -40,25 +64,5 @@ public interface Author {
void setEmail(String email);
Author withEmail(String email);
/**
* Id of user that create factory, set by the server
*/
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
String getUserId();
void setUserId(String userId);
Author withUserId(String userId);
/**
* @return Creation time of factory, set by the server (in milliseconds, from Unix epoch, no timezone)
*/
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
Long getCreated();
void setCreated(Long created);
Author withCreated(Long created);
AuthorDto withEmail(String email);
}

View File

@ -11,6 +11,7 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.ButtonAttributes;
import org.eclipse.che.dto.shared.DTO;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
@ -19,32 +20,37 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* @author Alexander Garagatyi
*/
@DTO
public interface ButtonAttributes {
public interface ButtonAttributesDto extends ButtonAttributes {
@Override
@FactoryParameter(obligation = OPTIONAL)
String getColor();
void setColor(String color);
ButtonAttributes withColor(String color);
ButtonAttributesDto withColor(String color);
@Override
@FactoryParameter(obligation = OPTIONAL)
Boolean getCounter();
void setCounter(Boolean counter);
ButtonAttributes withCounter(Boolean counter);
ButtonAttributesDto withCounter(Boolean counter);
@Override
@FactoryParameter(obligation = OPTIONAL)
String getLogo();
void setLogo(String logo);
ButtonAttributes withLogo(String logo);
ButtonAttributesDto withLogo(String logo);
@Override
@FactoryParameter(obligation = OPTIONAL)
String getStyle();
void setStyle(String style);
ButtonAttributes withStyle(String style);
ButtonAttributesDto withStyle(String style);
}

View File

@ -11,34 +11,32 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.Button;
import org.eclipse.che.dto.shared.DTO;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
/**
* Describes factory button
*
* @author Alexander Garagatyi
*/
@DTO
public interface Button {
public enum ButtonType {
logo, nologo
}
public interface ButtonDto extends Button {
/** Type of the button */
@Override
@FactoryParameter(obligation = OPTIONAL)
ButtonType getType();
Type getType();
void setType(ButtonType type);
void setType(Type type);
Button withType(ButtonType type);
ButtonDto withType(Type type);
/** Button attributes */
@Override
@FactoryParameter(obligation = OPTIONAL)
ButtonAttributes getAttributes();
ButtonAttributesDto getAttributes();
void setAttributes(ButtonAttributes attributes);
void setAttributes(ButtonAttributesDto attributes);
Button withAttributes(ButtonAttributes attributes);
ButtonDto withAttributes(ButtonAttributesDto attributes);
}

View File

@ -1,45 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.rest.shared.dto.Hyperlinks;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
/**
* Latest version of factory implementation.
*
* @author Alexander Garagatyi
*/
@DTO
public interface Factory extends FactoryV4_0, Hyperlinks {
Factory withV(String v);
Factory withId(String id);
Factory withName(String name);
Factory withWorkspace(WorkspaceConfigDto workspace);
Factory withPolicies(Policies policies);
Factory withCreator(Author creator);
Factory withButton(Button button);
Factory withIde(Ide ide);
@Override
Factory withLinks(List<Link> links);
}

View File

@ -11,7 +11,13 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.rest.shared.dto.Hyperlinks;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.MANDATORY;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
@ -20,94 +26,74 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* Factory of version 4.0
*
* @author Max Shaposhnik
*
*/
public interface FactoryV4_0 {
@DTO
public interface FactoryDto extends Factory, Hyperlinks {
/**
* @return Version for Codenvy Factory API.
*/
@Override
@FactoryParameter(obligation = MANDATORY)
String getV();
void setV(String v);
FactoryV4_0 withV(String v);
FactoryDto withV(String v);
/**
* Describes parameters of the workspace that should be used for factory
*/
@Override
@FactoryParameter(obligation = MANDATORY)
WorkspaceConfigDto getWorkspace();
void setWorkspace(WorkspaceConfigDto workspace);
FactoryV4_0 withWorkspace(WorkspaceConfigDto workspace);
FactoryDto withWorkspace(WorkspaceConfigDto workspace);
/**
* Describe restrictions of the factory
*/
@Override
@FactoryParameter(obligation = OPTIONAL, trackedOnly = true)
Policies getPolicies();
PoliciesDto getPolicies();
void setPolicies(Policies policies);
void setPolicies(PoliciesDto policies);
FactoryV4_0 withPolicies(Policies policies);
FactoryDto withPolicies(PoliciesDto policies);
/**
* Identifying information of author
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
Author getCreator();
AuthorDto getCreator();
void setCreator(Author creator);
void setCreator(AuthorDto creator);
FactoryV4_0 withCreator(Author creator);
FactoryDto withCreator(AuthorDto creator);
/**
* Describes factory button
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
Button getButton();
ButtonDto getButton();
void setButton(Button button);
void setButton(ButtonDto button);
FactoryV4_0 withButton(Button button);
FactoryDto withButton(ButtonDto button);
/**
* Describes ide look and feel.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
Ide getIde();
IdeDto getIde();
void setIde(Ide ide);
void setIde(IdeDto ide);
FactoryV4_0 withIde(Ide ide);
FactoryDto withIde(IdeDto ide);
/**
* @return - id of stored factory object
*/
@Override
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
String getId();
void setId(String id);
FactoryV4_0 withId(String id);
/**
* @return - name of stored factory object
*/
FactoryDto withId(String id);
@Override
@FactoryParameter(obligation = OPTIONAL)
String getName();
void setName(String name);
FactoryV4_0 withName(String name);
FactoryDto withName(String name);
@Override
FactoryDto withLinks(List<Link> links);
}

View File

@ -13,6 +13,7 @@ package org.eclipse.che.api.factory.shared.dto;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.Action;
import org.eclipse.che.dto.shared.DTO;
import java.util.Map;
@ -23,27 +24,30 @@ import java.util.Map;
* @author Sergii Kabashniuk
*/
@DTO
public interface Action {
public interface IdeActionDto extends Action {
/**
* Action Id
*
* @return id of action.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
String getId();
void setId(String id);
Action withId(String id);
IdeActionDto withId(String id);
/***
*
* @return Action properties
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
Map<String, String> getProperties();
void setProperties(Map<String, String> properties);
Action withProperties(Map<String, String> properties);
IdeActionDto withProperties(Map<String, String> properties);
}

View File

@ -13,6 +13,7 @@ package org.eclipse.che.api.factory.shared.dto;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.Ide;
import org.eclipse.che.dto.shared.DTO;
/**
@ -21,36 +22,39 @@ import org.eclipse.che.dto.shared.DTO;
* @author Sergii Kabashniuk
*/
@DTO
public interface Ide {
public interface IdeDto extends Ide {
/**
* @return configuration of IDE on application loaded event.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
OnAppLoaded getOnAppLoaded();
OnAppLoadedDto getOnAppLoaded();
void setOnAppLoaded(OnAppLoaded onAppLoaded);
void setOnAppLoaded(OnAppLoadedDto onAppLoaded);
Ide withOnAppLoaded(OnAppLoaded onAppLoaded);
IdeDto withOnAppLoaded(OnAppLoadedDto onAppLoaded);
/**
* @return configuration of IDE on application closed event.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
OnAppClosed getOnAppClosed();
OnAppClosedDto getOnAppClosed();
void setOnAppClosed(OnAppClosed onAppClosed);
void setOnAppClosed(OnAppClosedDto onAppClosed);
Ide withOnAppClosed(OnAppClosed onAppClosed);
IdeDto withOnAppClosed(OnAppClosedDto onAppClosed);
/**
* @return configuration of IDE on projects loaded event.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
OnProjectsLoaded getOnProjectsLoaded();
OnProjectsLoadedDto getOnProjectsLoaded();
void setOnProjectsLoaded(OnProjectsLoaded onProjectsLoaded);
void setOnProjectsLoaded(OnProjectsLoadedDto onProjectsLoaded);
Ide withOnProjectsLoaded(OnProjectsLoaded onProjectsLoaded);
IdeDto withOnProjectsLoaded(OnProjectsLoadedDto onProjectsLoaded);
}

View File

@ -11,6 +11,7 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.OnAppClosed;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
@ -23,15 +24,16 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* @author Sergii Kabashniuk
*/
@DTO
public interface OnAppClosed {
public interface OnAppClosedDto extends OnAppClosed {
/**
* @return actions for current event.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
List<Action> getActions();
List<IdeActionDto> getActions();
void setActions(List<Action> actions);
void setActions(List<IdeActionDto> actions);
OnAppClosed withActions(List<Action> actions);
OnAppClosedDto withActions(List<IdeActionDto> actions);
}

View File

@ -11,6 +11,7 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.OnAppLoaded;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
@ -23,14 +24,16 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* @author Sergii Kabashniuk
*/
@DTO
public interface OnAppLoaded {
public interface OnAppLoadedDto extends OnAppLoaded {
/**
* @return actions for current event.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
List<Action> getActions();
List<IdeActionDto> getActions();
void setActions(List<Action> actions);
void setActions(List<IdeActionDto> actions);
OnAppLoaded withActions(List<Action> actions);
OnAppLoadedDto withActions(List<IdeActionDto> actions);
}

View File

@ -11,6 +11,7 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.OnProjectsLoaded;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
@ -23,14 +24,16 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* @author Sergii Kabashniuk
*/
@DTO
public interface OnProjectsLoaded {
public interface OnProjectsLoadedDto extends OnProjectsLoaded {
/**
* @return actions for current event.
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
List<Action> getActions();
List<IdeActionDto> getActions();
void setActions(List<Action> actions);
void setActions(List<IdeActionDto> actions);
OnProjectsLoaded withActions(List<Action> actions);
OnProjectsLoadedDto withActions(List<IdeActionDto> actions);
}

View File

@ -11,9 +11,11 @@
package org.eclipse.che.api.factory.shared.dto;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.factory.Policies;
import org.eclipse.che.dto.shared.DTO;
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
/**
* Describe restrictions of the factory
*
@ -21,55 +23,60 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO
* @author Alexander Garagatyi
*/
@DTO
public interface Policies {
public interface PoliciesDto extends Policies {
/**
* Restrict access if referer header doesn't match this field
*/
// Do not change referer to referrer
@Override
@FactoryParameter(obligation = OPTIONAL)
String getReferer();
void setReferer(String referer);
Policies withReferer(String referer);
PoliciesDto withReferer(String referer);
/**
* Restrict access for factories used earlier then author supposes
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
Long getSince();
void setSince(Long since);
Policies withSince(Long since);
PoliciesDto withSince(Long since);
/**
* Restrict access for factories used later then author supposes
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
Long getUntil();
void setUntil(Long until);
Policies withUntil(Long until);
PoliciesDto withUntil(Long until);
/**
* Re-open project on factory 2-nd click
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
String getMatch();
void setMatch(String match);
Policies withMatch(String match);
PoliciesDto withMatch(String match);
/**
* Workspace creation strategy
*/
@Override
@FactoryParameter(obligation = OPTIONAL)
String getCreate();
void setCreate(String create);
Policies withCreate(String create);
PoliciesDto withCreate(String create);
}

View File

@ -45,6 +45,10 @@
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
@ -65,6 +69,10 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-factory-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-machine</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-machine-shared</artifactId>
@ -89,10 +97,19 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-lang</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-test</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
@ -103,21 +120,46 @@
<artifactId>javax.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-jdbc-vendor-h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-json</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.everrest</groupId>
<artifactId>everrest-assured</artifactId>
@ -162,4 +204,25 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Create the test jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>**/spi/tck/*.*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,131 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.factory.shared.dto.AuthorDto;
import org.eclipse.che.api.factory.shared.dto.ButtonAttributesDto;
import org.eclipse.che.api.factory.shared.dto.ButtonDto;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.factory.shared.dto.IdeActionDto;
import org.eclipse.che.api.factory.shared.dto.IdeDto;
import org.eclipse.che.api.factory.shared.dto.OnAppClosedDto;
import org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto;
import org.eclipse.che.api.factory.shared.dto.OnProjectsLoadedDto;
import org.eclipse.che.api.factory.shared.dto.PoliciesDto;
import org.eclipse.che.api.core.model.factory.Action;
import org.eclipse.che.api.core.model.factory.Author;
import org.eclipse.che.api.core.model.factory.Button;
import org.eclipse.che.api.core.model.factory.ButtonAttributes;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.core.model.factory.Ide;
import org.eclipse.che.api.core.model.factory.OnAppClosed;
import org.eclipse.che.api.core.model.factory.OnAppLoaded;
import org.eclipse.che.api.core.model.factory.OnProjectsLoaded;
import org.eclipse.che.api.core.model.factory.Policies;
import java.util.List;
import static java.util.stream.Collectors.toList;
import static org.eclipse.che.dto.server.DtoFactory.newDto;
/**
* Helps to convert to DTOs related to factory.
*
* @author Anton Korneta
*/
public final class DtoConverter {
public static FactoryDto asDto(Factory factory, User user) {
final FactoryDto factoryDto = newDto(FactoryDto.class).withId(factory.getId())
.withName(factory.getName())
.withV(factory.getV());
if (factory.getWorkspace() != null) {
factoryDto.withWorkspace(org.eclipse.che.api.workspace.server.DtoConverter.asDto(factory.getWorkspace()));
}
if (factory.getCreator() != null) {
factoryDto.withCreator(asDto(factory.getCreator(), user));
}
if (factory.getIde() != null) {
factoryDto.withIde(asDto(factory.getIde()));
}
if (factory.getPolicies() != null) {
factoryDto.withPolicies(asDto(factory.getPolicies()));
}
if (factory.getButton() != null) {
factoryDto.withButton(asDto(factory.getButton()));
}
return factoryDto;
}
public static IdeDto asDto(Ide ide) {
final IdeDto ideDto = newDto(IdeDto.class);
final OnAppClosed onAppClosed = ide.getOnAppClosed();
final OnAppLoaded onAppLoaded = ide.getOnAppLoaded();
final OnProjectsLoaded onProjectsLoaded = ide.getOnProjectsLoaded();
if (onAppClosed != null) {
ideDto.withOnAppClosed(newDto(OnAppClosedDto.class).withActions(asDto(onAppClosed.getActions())));
}
if (onAppLoaded != null) {
ideDto.withOnAppLoaded(newDto(OnAppLoadedDto.class).withActions(asDto(onAppLoaded.getActions())));
}
if (onProjectsLoaded != null) {
ideDto.withOnProjectsLoaded(newDto(OnProjectsLoadedDto.class).withActions(asDto(onProjectsLoaded.getActions())));
}
return ideDto;
}
public static AuthorDto asDto(Author author, User user) {
return newDto(AuthorDto.class).withUserId(author.getUserId())
.withName(user.getName())
.withEmail(user.getEmail())
.withCreated(author.getCreated());
}
public static IdeActionDto asDto(Action action) {
return newDto(IdeActionDto.class).withId(action.getId())
.withProperties(action.getProperties());
}
public static List<IdeActionDto> asDto(List<? extends Action> actions) {
return actions.stream().map(DtoConverter::asDto).collect(toList());
}
public static PoliciesDto asDto(Policies policies) {
return newDto(PoliciesDto.class).withCreate(policies.getCreate())
.withMatch(policies.getMatch())
.withReferer(policies.getReferer())
.withSince(policies.getSince())
.withUntil(policies.getUntil());
}
public static ButtonDto asDto(Button button) {
final ButtonDto buttonDto = newDto(ButtonDto.class);
if (button.getAttributes() != null) {
buttonDto.withAttributes(asDto(button.getAttributes()));
}
if (button.getType() != null) {
buttonDto.withType(button.getType());
}
return buttonDto;
}
public static ButtonAttributesDto asDto(ButtonAttributes attributes) {
return newDto(ButtonAttributesDto.class).withColor(attributes.getColor())
.withCounter(attributes.getCounter())
.withLogo(attributes.getLogo())
.withStyle(attributes.getStyle());
}
private DtoConverter() {}
}

View File

@ -12,7 +12,7 @@ package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
/**
* Interface for validations of factory urls on accept stage.
@ -28,5 +28,5 @@ public interface FactoryAcceptValidator {
* @throws BadRequestException
* in case if factory is not valid
*/
void validateOnAccept(Factory factory) throws BadRequestException;
void validateOnAccept(FactoryDto factory) throws BadRequestException;
}

View File

@ -13,7 +13,7 @@ package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
/**
* Interface for validations of factory creation stage.
@ -35,5 +35,5 @@ public interface FactoryCreateValidator {
* @throws ForbiddenException
* when user have no access rights for factory creation
*/
void validateOnCreate(Factory factory) throws BadRequestException, ServerException, ForbiddenException;
void validateOnCreate(FactoryDto factory) throws BadRequestException, ServerException, ForbiddenException;
}

View File

@ -12,7 +12,7 @@ package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.core.model.factory.Factory;
/**
* This validator ensures that a factory can be edited by a user that has the associated rights (author or account owner)

View File

@ -10,23 +10,27 @@
*******************************************************************************/
package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.ConflictException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.persistence.Basic;
import javax.persistence.Embeddable;
import java.util.Arrays;
import java.util.Objects;
/** Class to hold image information such as data, name, media type */
@Embeddable
public class FactoryImage {
@Basic
private byte[] imageData;
@Basic
private String mediaType;
@Basic
private String name;
public FactoryImage() {
}
public FactoryImage() {}
public FactoryImage(byte[] data, String mediaType, String name) throws IOException {
public FactoryImage(byte[] data, String mediaType, String name) {
setMediaType(mediaType);
this.name = name;
setImageData(data);
@ -36,7 +40,7 @@ public class FactoryImage {
return imageData;
}
public void setImageData(byte[] imageData) throws IOException {
public void setImageData(byte[] imageData) {
this.imageData = imageData;
}
@ -44,7 +48,7 @@ public class FactoryImage {
return mediaType;
}
public void setMediaType(String mediaType) throws IOException {
public void setMediaType(String mediaType) {
if (mediaType != null) {
switch (mediaType) {
case "image/jpeg":
@ -53,10 +57,10 @@ public class FactoryImage {
this.mediaType = mediaType;
return;
default:
throw new IOException("Image media type '" + mediaType + "' is unsupported.");
throw new IllegalArgumentException("Image media type '" + mediaType + "' is unsupported.");
}
}
throw new IOException("Image media type 'null' is unsupported.");
throw new IllegalArgumentException("Image media type 'null' is unsupported.");
}
public String getName() {
@ -72,60 +76,21 @@ public class FactoryImage {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof FactoryImage)) return false;
FactoryImage that = (FactoryImage)o;
if (!Arrays.equals(imageData, that.imageData)) return false;
if (mediaType != null ? !mediaType.equals(that.mediaType) : that.mediaType != null) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return true;
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof FactoryImage)) return false;
final FactoryImage other = (FactoryImage)obj;
return Arrays.equals(imageData, other.imageData)
&& Objects.equals(mediaType, other.mediaType)
&& Objects.equals(name, other.name);
}
@Override
public int hashCode() {
int result = imageData != null ? Arrays.hashCode(imageData) : 0;
result = 31 * result + (mediaType != null ? mediaType.hashCode() : 0);
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
/**
* Creates {@code FactoryImage}.
* InputStream should be closed manually.
*
* @param is
* - input stream with image data
* @param mediaType
* - media type of image
* @param name
* - image name
* @return - {@code FactoryImage} if {@code FactoryImage} was created, null if input stream has no content
* @throws org.eclipse.che.api.core.ConflictException
*/
public static FactoryImage createImage(InputStream is, String mediaType, String name) throws ConflictException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int read;
while ((read = is.read(buffer, 0, buffer.length)) != -1) {
baos.write(buffer, 0, read);
if (baos.size() > 1024 * 1024) {
throw new ConflictException("Maximum upload size exceeded.");
}
}
if (baos.size() == 0) {
return new FactoryImage();
}
baos.flush();
return new FactoryImage(baos.toByteArray(), mediaType, name);
} catch (IOException e) {
throw new ConflictException(e.getLocalizedMessage());
}
int hash = 7;
hash = 31 * hash + Arrays.hashCode(imageData);
hash = 31 * hash + Objects.hashCode(mediaType);
hash = 31 * hash + Objects.hashCode(name);
return hash;
}
}

View File

@ -0,0 +1,158 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.server;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import org.eclipse.che.api.core.rest.ServiceContext;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.UriBuilder;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static java.util.stream.Collectors.toList;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.TEXT_HTML;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static org.eclipse.che.api.core.util.LinksHelper.createLink;
import static org.eclipse.che.api.factory.shared.Constants.ACCEPTED_REL_ATT;
import static org.eclipse.che.api.factory.shared.Constants.FACTORY_ACCEPTANCE_REL_ATT;
import static org.eclipse.che.api.factory.shared.Constants.IMAGE_REL_ATT;
import static org.eclipse.che.api.factory.shared.Constants.NAMED_FACTORY_ACCEPTANCE_REL_ATT;
import static org.eclipse.che.api.factory.shared.Constants.RETRIEVE_FACTORY_REL_ATT;
import static org.eclipse.che.api.factory.shared.Constants.SNIPPET_REL_ATT;
/**
* Helper class for creation links.
*
* @author Anton Korneta
*/
public class FactoryLinksHelper {
private static final List<String> SNIPPET_TYPES = ImmutableList.of("markdown", "url", "html", "iframe");
private FactoryLinksHelper() {}
/**
* Creates factory links and links for retrieving factory images.
*
* @param images
* a set of factory images
* @param serviceContext
* the context to retrieve factory service base URI
* @return list of factory and factory images links
*/
public static List<Link> createLinks(FactoryDto factory,
Set<FactoryImage> images,
ServiceContext serviceContext,
String userName) {
final List<Link> links = new LinkedList<>(createLinks(factory, serviceContext, userName));
final UriBuilder uriBuilder = serviceContext.getServiceUriBuilder();
final String factoryId = factory.getId();
// creation of links to retrieve images
links.addAll(images.stream()
.map(image -> createLink(HttpMethod.GET,
uriBuilder.clone()
.path(FactoryService.class, "getImage")
.queryParam("imgId", image.getName())
.build(factoryId)
.toString(),
null,
image.getMediaType(),
IMAGE_REL_ATT))
.collect(toList()));
return links;
}
/**
* Creates factory links.
*
* @param serviceContext
* the context to retrieve factory service base URI
* @return list of factory links
*/
public static List<Link> createLinks(FactoryDto factory,
ServiceContext serviceContext,
String userName) {
final List<Link> links = new LinkedList<>();
final UriBuilder uriBuilder = serviceContext.getServiceUriBuilder();
final String factoryId = factory.getId();
if (factoryId != null) {
// creation of link to retrieve factory
links.add(createLink(HttpMethod.GET,
uriBuilder.clone()
.path(FactoryService.class, "getFactory")
.build(factoryId)
.toString(),
null,
APPLICATION_JSON,
RETRIEVE_FACTORY_REL_ATT));
// creation of snippet links
links.addAll(SNIPPET_TYPES.stream()
.map(snippet -> createLink(HttpMethod.GET,
uriBuilder.clone()
.path(FactoryService.class,
"getFactorySnippet")
.queryParam("type", snippet)
.build(factoryId)
.toString(),
null,
TEXT_PLAIN,
SNIPPET_REL_ATT + '/' + snippet))
.collect(toList()));
// creation of accept factory link
final Link createWorkspace = createLink(HttpMethod.GET,
uriBuilder.clone()
.replacePath("f")
.queryParam("id", factoryId)
.build()
.toString(),
null,
TEXT_HTML,
FACTORY_ACCEPTANCE_REL_ATT);
links.add(createWorkspace);
// creation of links for analytics
links.add(createLink(HttpMethod.GET,
uriBuilder.clone()
.path("analytics")
.path("public-metric/factory_used")
.queryParam("factory", createWorkspace.getHref())
.toString(),
null,
TEXT_PLAIN,
ACCEPTED_REL_ATT));
}
if (!Strings.isNullOrEmpty(factory.getName()) && !Strings.isNullOrEmpty(userName)) {
// creation of accept factory link by name and creator
final Link createWorkspaceFromNamedFactory = createLink(HttpMethod.GET,
uriBuilder.clone()
.replacePath("f")
.queryParam("name", factory.getName())
.queryParam("user", userName)
.build()
.toString(),
null,
TEXT_HTML,
NAMED_FACTORY_ACCEPTANCE_REL_ATT);
links.add(createWorkspaceFromNamedFactory);
}
return links;
}
}

View File

@ -0,0 +1,285 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.factory.server.model.impl.AuthorImpl;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
import org.eclipse.che.api.factory.server.snippet.SnippetGenerator;
import org.eclipse.che.api.factory.server.spi.FactoryDao;
import org.eclipse.che.commons.lang.NameGenerator;
import org.eclipse.che.commons.lang.Pair;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.util.Objects.requireNonNull;
import static org.eclipse.che.api.factory.shared.Constants.HTML_SNIPPET_TYPE;
import static org.eclipse.che.api.factory.shared.Constants.IFRAME_SNIPPET_TYPE;
import static org.eclipse.che.api.factory.shared.Constants.MARKDOWN_SNIPPET_TYPE;
import static org.eclipse.che.api.factory.shared.Constants.URL_SNIPPET_TYPE;
/**
* @author Anton Korneta
*/
@Singleton
public class FactoryManager {
@Inject
private FactoryDao factoryDao;
/**
* Stores {@link Factory} instance.
*
* @param factory
* instance of factory which would be stored
* @return factory which has been stored
* @throws NullPointerException
* when {@code factory} is null
* @throws ConflictException
* when any conflict occurs (e.g Factory with given name already exists for {@code creator})
* @throws ServerException
* when any server errors occurs
*/
public Factory saveFactory(Factory factory) throws ConflictException, ServerException {
return saveFactory(factory, null);
}
/**
* Stores {@link Factory} instance and related set of {@link FactoryImage}.
*
* @param factory
* instance of factory which would be stored
* @param images
* factory images which would be stored
* @return factory which has been stored
* @throws NullPointerException
* when {@code factory} is null
* @throws ConflictException
* when any conflict occurs (e.g Factory with given name already exists for {@code creator})
* @throws ServerException
* when any server errors occurs
*/
public Factory saveFactory(Factory factory, Set<FactoryImage> images) throws ConflictException,
ServerException {
requireNonNull(factory);
final FactoryImpl newFactory = new FactoryImpl(factory, images);
newFactory.setId(NameGenerator.generate("factory", 16));
return factoryDao.create(newFactory);
}
/**
* Updates factory accordance to the new configuration.
*
* <p>Note: Updating uses replacement strategy,
* therefore existing factory would be replaced with given update {@code update}
*
* @param update
* factory update
* @return updated factory
* @throws NullPointerException
* when {@code update} is null
* @throws ConflictException
* when any conflict occurs (e.g Factory with given name already exists for {@code creator})
* @throws NotFoundException
* when factory with given id not found
* @throws ServerException
* when any server error occurs
*/
public Factory updateFactory(Factory update) throws ConflictException,
NotFoundException,
ServerException {
requireNonNull(update);
return updateFactory(update, null);
}
/**
* Updates factory and its images accordance to the new configuration.
*
* <p>Note: Updating uses replacement strategy,
* therefore existing factory would be replaced with given update {@code update}
*
* @param update
* factory update
* @return updated factory
* @throws NullPointerException
* when {@code update} is null
* @throws ConflictException
* when any conflict occurs (e.g Factory with given name already exists for {@code creator})
* @throws NotFoundException
* when factory with given id not found
* @throws ServerException
* when any server error occurs
*/
public Factory updateFactory(Factory update, Set<FactoryImage> images) throws ConflictException,
NotFoundException,
ServerException {
requireNonNull(update);
final AuthorImpl creator = factoryDao.getById(update.getId()).getCreator();
return factoryDao.update(FactoryImpl.builder()
.from(new FactoryImpl(update, images))
.setCreator(new AuthorImpl(creator.getUserId(), creator.getCreated()))
.build());
}
/**
* Removes stored {@link Factory} by given id.
*
* @param id
* factory identifier
* @throws NullPointerException
* when {@code id} is null
* @throws ServerException
* when any server errors occurs
*/
public void removeFactory(String id) throws ServerException {
requireNonNull(id);
factoryDao.remove(id);
}
/**
* Gets factory by given id.
*
* @param id
* factory identifier
* @return factory instance
* @throws NullPointerException
* when {@code id} is null
* @throws NotFoundException
* when factory with given id not found
* @throws ServerException
* when any server errors occurs
*/
public Factory getById(String id) throws NotFoundException,
ServerException {
requireNonNull(id);
return factoryDao.getById(id);
}
/**
* Gets factory images by given factory and image ids.
*
* @param factoryId
* factory identifier
* @param imageId
* image identifier
* @return factory images or empty set if no image found by given {@code imageId}
* @throws NotFoundException
* when specified factory not found
* @throws ServerException
* when any server errors occurs
*/
public Set<FactoryImage> getFactoryImages(String factoryId, String imageId) throws NotFoundException,
ServerException {
requireNonNull(factoryId);
requireNonNull(imageId);
return getFactoryImages(factoryId).stream()
.filter(image -> imageId.equals(image.getName()))
.collect(Collectors.toSet());
}
/**
* Gets all the factory images.
*
* @param factoryId
* factory identifier
* @return factory images or empty set if no image found for factory
* @throws NotFoundException
* when specified factory not found
* @throws ServerException
* when any server errors occurs
*/
public Set<FactoryImage> getFactoryImages(String factoryId) throws NotFoundException,
ServerException {
requireNonNull(factoryId);
return factoryDao.getById(factoryId).getImages();
}
/**
* Get list of factories which conform specified attributes.
*
* @param maxItems
* max number of items in response
* @param skipCount
* skip items. Must be equals or greater then {@code 0}
* @param attributes
* skip items. Must be equals or greater then {@code 0}
* @return stored data, if specified attributes is correct
* @throws ServerException
* when any server errors occurs
*/
@SuppressWarnings("unchecked")
public <T extends List<? extends Factory>> T getByAttribute(int maxItems,
int skipCount,
List<Pair<String, String>> attributes) throws ServerException {
return (T)factoryDao.getByAttribute(maxItems, skipCount, attributes);
}
/**
* Gets factory snippet by factory id and snippet type.
* If snippet type is not set, "url" type will be used as default.
*
* @param factoryId
* id of factory
* @param snippetType
* type of snippet
* @param baseUri
* URI from which will be created snippet
* @return snippet content or null when snippet type not found.
* @throws NotFoundException
* when factory with specified id doesn't not found
* @throws ServerException
* when any server error occurs during snippet creation
*/
public String getFactorySnippet(String factoryId,
String snippetType,
URI baseUri) throws NotFoundException,
ServerException {
requireNonNull(factoryId);
final String baseUrl = UriBuilder.fromUri(baseUri)
.replacePath("")
.build()
.toString();
switch (firstNonNull(snippetType, URL_SNIPPET_TYPE)) {
case URL_SNIPPET_TYPE:
return UriBuilder.fromUri(baseUri)
.replacePath("factory")
.queryParam("id", factoryId)
.build()
.toString();
case HTML_SNIPPET_TYPE:
return SnippetGenerator.generateHtmlSnippet(baseUrl, factoryId);
case IFRAME_SNIPPET_TYPE:
return SnippetGenerator.generateiFrameSnippet(baseUrl, factoryId);
case MARKDOWN_SNIPPET_TYPE:
final Set<FactoryImage> images = getFactoryImages(factoryId);
final String imageId = (images.size() > 0) ? images.iterator().next().getName()
: null;
try {
return SnippetGenerator.generateMarkdownSnippet(baseUrl, getById(factoryId), imageId);
} catch (IllegalArgumentException e) {
throw new ServerException(e.getLocalizedMessage());
}
default:
// when the specified type is not supported
return null;
}
}
}

View File

@ -13,8 +13,8 @@ package org.eclipse.che.api.factory.server;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonObject;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryV4_0;
import org.eclipse.che.api.core.model.factory.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.workspace.server.WorkspaceConfigMessageBodyAdapter;
import javax.inject.Singleton;
@ -30,7 +30,7 @@ public class FactoryMessageBodyAdapter extends WorkspaceConfigMessageBodyAdapter
@Override
public Set<Class<?>> getTriggers() {
return ImmutableSet.of(Factory.class, FactoryV4_0.class);
return ImmutableSet.of(Factory.class, FactoryDto.class);
}
@Override

View File

@ -11,7 +11,7 @@
package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import javax.validation.constraints.NotNull;
import java.util.Map;
@ -40,7 +40,5 @@ public interface FactoryParametersResolver {
* @throws BadRequestException
* when data are invalid
*/
Factory createFactory(@NotNull Map<String, String> factoryParameters) throws BadRequestException;
FactoryDto createFactory(@NotNull Map<String, String> factoryParameters) throws BadRequestException;
}

View File

@ -1,125 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.commons.lang.Pair;
import java.util.List;
import java.util.Set;
/**
* Interface for CRUD operations with factory data.
*
* @author Max Shaposhnik
*/
public interface FactoryStore {
/**
* Save factory at storage.
*
* @param factory
* factory information
* @param images
* factory images
* @return id of stored factory
* @throws java.lang.RuntimeException
* if {@code factory} is null
* @throws org.eclipse.che.api.core.ConflictException
* if {@code factory} with given name and creator already exists
* @throws org.eclipse.che.api.core.ServerException
* if other error occurs
*/
public String saveFactory(Factory factory, Set<FactoryImage> images) throws ConflictException, ServerException;
/**
* Remove factory by id
*
* @param factoryId
* - id of factory to remove
* @throws org.eclipse.che.api.core.NotFoundException
* if factory with given {@code factoryId} is not found
* @throws java.lang.RuntimeException
* if {@code factoryId} is null
* @throws org.eclipse.che.api.core.ServerException
* if other error occurs
*/
public void removeFactory(String factoryId) throws NotFoundException, ServerException;
/**
* Retrieve factory data by its id
*
* @param factoryId
* - factory id
* @return - {@code AdvancedFactoryUrl} if factory exist and found
* @throws org.eclipse.che.api.core.NotFoundException
* if factory with given {@code factoryId} is not found
* @throws java.lang.RuntimeException
* if {@code factoryId} is null
* @throws org.eclipse.che.api.core.ServerException
* if other error occurs
*
*/
public Factory getFactory(String factoryId) throws NotFoundException, ServerException;
/**
* Retrieve factory by given list of pairs of attribute names and values.
*
* @param maxItems
* max number of items in response.
* @param skipCount
* skip items. Must be equals or greater then {@code 0}. IllegalArgumentException thrown otherwise.
* @param attributes
* attribute pairs to search for
*
* @return - List {@code AdvancedFactoryUrl} if factory(s) exist and found, empty list otherwise
* @throws org.eclipse.che.api.core.IllegalArgumentException
* if {@code skipCount} is negative
*
*/
public List<Factory> findByAttribute(int maxItems, int skipCount, List<Pair<String, String>> attributes) throws IllegalArgumentException;
/**
* Retrieve factory images by factory id
*
* @param factoryId
* factory id. Must not be null.
* @param imageId
* id of the requested image. When null, all images for given factory will be returned.
* @return {@code Set} of images if factory found, empty set otherwise
* @throws java.lang.RuntimeException
* if {@code factoryId} is null
* @throws org.eclipse.che.api.core.NotFoundException
* if factory with given {@code factoryId} is not found
*/
public Set<FactoryImage> getFactoryImages(String factoryId, String imageId) throws NotFoundException;
/**
* Update factory at storage.
*
* @param factoryId
* factory id to update. Must not be null.
* @param factory
* factory information. Must not be null.
* @return id of stored factory
* @throws org.eclipse.che.api.core.NotFoundException
* if factory with given {@code factoryId} is not found
* @throws org.eclipse.che.api.core.ConflictException
* if {@code factory} with given name and creator already exists
* @throws java.lang.RuntimeException
* if {@code factory} is null
*/
public String updateFactory(String factoryId, Factory factory) throws NotFoundException, ConflictException;
}

View File

@ -11,7 +11,7 @@
package org.eclipse.che.api.factory.server;
import org.eclipse.che.api.core.ApiException;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.core.model.factory.Factory;
/**
* Convert legacy factory parameter to new the latest format

Some files were not shown because too many files have changed in this diff Show More