/*******************************************************************************
* Copyright (c) 2012-2017 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.jpa;
import com.google.inject.persist.Transactional;
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.notification.EventService;
import org.eclipse.che.api.factory.server.model.impl.FactoryImpl;
import org.eclipse.che.api.factory.server.spi.FactoryDao;
import org.eclipse.che.api.user.server.event.BeforeUserRemovedEvent;
import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.core.db.cascade.CascadeEventSubscriber;
import org.eclipse.che.core.db.jpa.DuplicateKeyException;
import org.eclipse.che.core.db.jpa.IntegrityConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
/**
* @author Anton Korneta
*/
@Singleton
public class JpaFactoryDao implements FactoryDao {
private static final Logger LOG = LoggerFactory.getLogger(JpaFactoryDao.class);
@Inject
private Provider<EntityManager> managerProvider;
@Override
public FactoryImpl create(FactoryImpl factory) throws ConflictException, ServerException {
requireNonNull(factory);
try {
doCreate(factory);
} catch (DuplicateKeyException ex) {
throw new ConflictException(ex.getLocalizedMessage());
} catch (IntegrityConstraintViolationException ex) {
throw new ConflictException("Could not create factory with creator that refers on non-existent user");
} catch (RuntimeException ex) {
throw new ServerException(ex.getLocalizedMessage(), ex);
}
return new FactoryImpl(factory);
}
@Override
public FactoryImpl update(FactoryImpl update) throws NotFoundException, ConflictException, ServerException {
requireNonNull(update);
try {
return new FactoryImpl(doUpdate(update));
} catch (DuplicateKeyException ex) {
throw new ConflictException(ex.getLocalizedMessage());
} catch (RuntimeException ex) {
throw new ServerException(ex.getLocalizedMessage(), ex);
}
}
@Override
public void remove(String id) throws ServerException {
requireNonNull(id);
try {
doRemove(id);
} catch (RuntimeException ex) {
throw new ServerException(ex.getLocalizedMessage(), ex);
}
}
@Override
@Transactional
public FactoryImpl getById(String id) throws NotFoundException, ServerException {
requireNonNull(id);
try {
final FactoryImpl factory = managerProvider.get().find(FactoryImpl.class, id);
if (factory == null) {
throw new NotFoundException(format("Factory with id '%s' doesn't exist", id));
}
return new FactoryImpl(factory);
} catch (RuntimeException ex) {
throw new ServerException(ex.getLocalizedMessage(), ex);
}
}
@Override
@Transactional
public List<FactoryImpl> getByAttribute(int maxItems,
int skipCount,
List<Pair<String, String>> attributes) throws ServerException {
try {
LOG.info("FactoryDao#getByAttributes #maxItems: {} #skipCount: {}, #attributes: {}", maxItems, skipCount, attributes);
final Map<String, String> params = new HashMap<>();
String query = "SELECT factory FROM Factory factory";
if (!attributes.isEmpty()) {
final StringJoiner matcher = new StringJoiner(" AND ", " WHERE ", " ");
int i = 0;
for (Pair<String, String> attribute : attributes) {
final String parameterName = "parameterName" + i++;
params.put(parameterName, attribute.second);
matcher.add("factory." + attribute.first + " = :" + parameterName);
}
query = query + matcher;
}
final TypedQuery<FactoryImpl> typedQuery = managerProvider.get()
.createQuery(query, FactoryImpl.class)
.setFirstResult(skipCount)
.setMaxResults(maxItems);
for (Map.Entry<String, String> entry : params.entrySet()) {
typedQuery.setParameter(entry.getKey(), entry.getValue());
}
return typedQuery.getResultList()
.stream()
.map(FactoryImpl::new)
.collect(Collectors.toList());
} catch (RuntimeException ex) {
throw new ServerException(ex.getLocalizedMessage(), ex);
}
}
@Transactional
protected void doCreate(FactoryImpl factory) {
final EntityManager manager = managerProvider.get();
if (factory.getWorkspace() != null) {
factory.getWorkspace().getProjects().forEach(ProjectConfigImpl::prePersistAttributes);
}
manager.persist(factory);
manager.flush();
}
@Transactional
protected FactoryImpl doUpdate(FactoryImpl update) throws NotFoundException {
final EntityManager manager = managerProvider.get();
if (manager.find(FactoryImpl.class, update.getId()) == null) {
throw new NotFoundException(format("Could not update factory with id %s because it doesn't exist", update.getId()));
}
if (update.getWorkspace() != null) {
update.getWorkspace().getProjects().forEach(ProjectConfigImpl::prePersistAttributes);
}
FactoryImpl merged = manager.merge(update);
manager.flush();
return merged;
}
@Transactional
protected void doRemove(String id) {
final EntityManager manager = managerProvider.get();
final FactoryImpl factory = manager.find(FactoryImpl.class, id);
if (factory != null) {
manager.remove(factory);
manager.flush();
}
}
@Singleton
public static class RemoveFactoriesBeforeUserRemovedEventSubscriber
extends CascadeEventSubscriber<BeforeUserRemovedEvent> {
@Inject
private FactoryDao factoryDao;
@Inject
private EventService eventService;
@PostConstruct
public void subscribe() {
eventService.subscribe(this, BeforeUserRemovedEvent.class);
}
@PreDestroy
public void unsubscribe() {
eventService.unsubscribe(this, BeforeUserRemovedEvent.class);
}
@Override
public void onCascadeEvent(BeforeUserRemovedEvent event) throws ServerException {
final Pair<String, String> factoryCreator = Pair.of("creator.userId", event.getUser().getId());
for (FactoryImpl factory : factoryDao.getByAttribute(0, 0, singletonList(factoryCreator))) {
factoryDao.remove(factory.getId());
}
}
}
}