package org.sigmah.server.handler.base;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.lang.reflect.ParameterizedType;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.sigmah.server.dao.base.EntityManagerProvider;
import org.sigmah.server.dispatch.CommandHandler;
import org.sigmah.server.dispatch.ExecutionContext;
import org.sigmah.server.dispatch.impl.UserDispatch.UserExecutionContext;
import org.sigmah.server.domain.util.DomainFilters;
import org.sigmah.server.inject.util.Injectors;
import org.sigmah.server.mapper.Mapper;
import org.sigmah.shared.command.base.Command;
import org.sigmah.shared.command.result.Result;
import org.sigmah.shared.dispatch.CommandException;
import org.sigmah.shared.dispatch.DispatchException;
import com.google.inject.Inject;
import java.lang.reflect.Type;
/**
* A super class for handlers which manages the specific execution context.
*
* @author Denis Colliot (dcolliot@ideia.fr)
* @param <C>
* The command type.
* @param <R>
* The result type.
*/
public abstract class AbstractCommandHandler<C extends Command<R>, R extends Result> extends EntityManagerProvider implements CommandHandler<C, R> {
/**
* Ensures that the execution context extends the {@link UserExecutionContext} class.
*
* @param context
* The execution context.
* @throws DispatchException
* If the context doesn't extends the {@link UserExecutionContext} class.
*/
private static void ensureGuiceExecutionContext(final ExecutionContext context) throws CommandException {
if (!(context instanceof UserExecutionContext)) {
throw new CommandException("The execution context doesn't extends '"
+ UserExecutionContext.class.getCanonicalName()
+ "'. The handler cannot be executed.");
}
}
/**
* The command type.
*/
private Class<C> clazz;
@Inject
private Mapper mapper;
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public final Class<C> getCommandType() {
if (clazz == null) {
final Class<?> clazz = Injectors.getClass(this);
final Type type = ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
if(type instanceof Class) {
this.clazz = (Class<C>) type;
} else if(type instanceof ParameterizedType) {
// If the command handler is parametrized, retrieves the raw class.
this.clazz = (Class<C>) ((ParameterizedType)type).getRawType();
} else {
throw new UnsupportedOperationException("Type is not supported: " + type);
}
}
return clazz;
}
/**
* {@inheritDoc}
*/
@Override
public final R execute(final C command, final ExecutionContext context) throws CommandException {
if (context != null) {
ensureGuiceExecutionContext(context);
final UserExecutionContext uContext = (UserExecutionContext) context;
// Activate filters into hibernate session.
DomainFilters.applyUserFilter(uContext.getUser(), em());
return execute(command, uContext);
} else {
return execute(command, null);
}
}
/**
* Executes the given {@code command} within given {@code context}.
*
* @param command
* The command
* @param context
* The execution context.
* @return The command execution result.
* @throws CommandException
* If the command execution fails.
*/
protected abstract R execute(final C command, final UserExecutionContext context) throws CommandException;
/**
* {@inheritDoc}
*/
@Override
public final void rollback(final C command, R result, final ExecutionContext context) throws CommandException {
if (context != null) {
ensureGuiceExecutionContext(context);
final UserExecutionContext uContext = (UserExecutionContext) context;
rollback(command, result, uContext);
} else {
rollback(command, result, null);
}
}
/**
* Rollbacks the given {@code command} execution.
* The default implementation does nothing.
*
* @param command
* The command.
* @param result
* The command result.
* @param context
* The context.
* @throws CommandException
* If the rollback failed.
*/
public void rollback(final C command, R result, final UserExecutionContext context) throws CommandException {
// Default implementation does nothing.
}
/**
* {@inheritDoc}
*/
@Override
public final String toString() {
return new ToStringBuilder(this).toString();
}
/**
* Returns the {@link Mapper} instance.
*
* @return The {@link Mapper} instance, never {@code null}.
*/
protected final Mapper mapper() {
return mapper;
}
}