/*
###############################################################################
# #
# Copyright (C) 2011-2016 OpenMEAP, Inc. #
# Credits to Jonathan Schang & Rob Thacher #
# #
# Released under the LGPLv3 #
# #
# OpenMEAP is free software: you can redistribute it and/or modify #
# it under the terms of the GNU Lesser General Public License as published #
# by the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# OpenMEAP 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 Lesser General Public License for more details. #
# #
# You should have received a copy of the GNU Lesser General Public License #
# along with OpenMEAP. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
*/
package com.openmeap.admin.web.backing;
import static com.openmeap.util.ParameterMapUtils.firstValue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.openmeap.Authorizer;
import com.openmeap.admin.web.events.AddSubNavAnchorEvent;
import com.openmeap.constants.FormConstants;
import com.openmeap.event.MessagesEvent;
import com.openmeap.event.ProcessingEvent;
import com.openmeap.event.ProcessingTargets;
import com.openmeap.model.InvalidPropertiesException;
import com.openmeap.model.ModelManager;
import com.openmeap.model.dto.Application;
import com.openmeap.model.dto.ApplicationVersion;
import com.openmeap.util.ParameterMapUtils;
import com.openmeap.web.AbstractTemplatedSectionBacking;
import com.openmeap.web.ProcessingContext;
import com.openmeap.web.html.Anchor;
/**
* Mediates information between the ModelManager and the add/modify form.
*
* Any business logic specific to the creation/modification of an Application
* should be implemented in the ModelManagerImpl.
*
* @author schang
*/
public class AddModifyApplicationBacking extends AbstractTemplatedSectionBacking {
private static String PROCESS_TARGET = ProcessingTargets.ADDMODIFY_APP;
private Logger logger = LoggerFactory.getLogger(AddModifyApplicationBacking.class);
private ModelManager modelManager = null;
public void setModelManager(ModelManager modelManager) {
this.modelManager = modelManager;
}
public ModelManager getModelManager() {
return modelManager;
}
/**
* With the first of the bean name matching "addModifyApp", there are
* three ways to access this:
* - request has applicationId and processTarget - modifying an application
* - request has applicationId only - pulling up an application to modify
* - request has processTarget only - submitting a brand new application
*
* See the WEB-INF/ftl/form-application-addmodify.ftl for input/output parameters.
*
* @param context Not referenced at all, may be null
* @param templateVariables Variables output to for the view
* @param parameterMap Parameters passed in to drive processing
* @return on errors, returns an array of error processingevents
* @see TemplatedSectionBacking::process()
*/
public Collection<ProcessingEvent> process(ProcessingContext context, Map<Object,Object> templateVariables, Map<Object, Object> parameterMap) {
List<ProcessingEvent> events = new ArrayList<ProcessingEvent>();
templateVariables.put(FormConstants.PROCESS_TARGET,PROCESS_TARGET);
Application app = new Application();
if( ParameterMapUtils.notEmpty(FormConstants.APP_ID,parameterMap) ) {
app = modelManager.getModelService().findByPrimaryKey(Application.class, Long.valueOf( ParameterMapUtils.firstValue(FormConstants.APP_ID, parameterMap) ) );
}
Boolean mayCreate = modelManager.getAuthorizer().may(Authorizer.Action.CREATE, new Application());
Boolean mayModify = modelManager.getAuthorizer().may(Authorizer.Action.MODIFY, app);
Boolean willProcess = mayCreate || mayModify;
if( !willProcess ) {
events.add( new MessagesEvent("Current user does not have permissions to make changes here") );
}
templateVariables.put("willProcess",willProcess);
// if the request is targeting this section or the primary page of this section
// the user is submitting the form for either an add or modify
if( ParameterMapUtils.notEmpty(FormConstants.PROCESS_TARGET,parameterMap)
&& PROCESS_TARGET.equals(((String[])parameterMap.get(FormConstants.PROCESS_TARGET))[0])
&& willProcess ) {
app = createApplicationFromParameters(app,parameterMap, events);
if( ParameterMapUtils.firstValue("submit",parameterMap).equals("true") ) {
if( events.size()==0 ) {
try {
app.setLastModifier(firstValue("userPrincipalName",parameterMap));
modelManager.begin();
app = modelManager.addModify(app,events);
modelManager.commit(events);
events.add( new MessagesEvent("Application successfully created/modified!") );
} catch( InvalidPropertiesException e ) {
events.add(new MessagesEvent(String.format("Application add/modify failed: %s %s"
,ExceptionUtils.getRootCauseMessage(e)
,ExceptionUtils.getRootCauseStackTrace(e)[0])));
logger.error("Add/Modify application with id "+app.getId()+" failed",e);
modelManager.rollback();
} catch( PersistenceException e ) {
events.add(new MessagesEvent(String.format("Application add/modify failed: %s %s"
,ExceptionUtils.getRootCauseMessage(e)
,ExceptionUtils.getRootCauseStackTrace(e)[0])));
logger.error("Add/Modify application with id "+app.getId()+" failed",e);
modelManager.rollback();
}
}
if( app==null && ParameterMapUtils.notEmpty(FormConstants.APP_ID,parameterMap) )
app = modelManager.getModelService().findByPrimaryKey(Application.class,
Long.valueOf(ParameterMapUtils.firstValue(FormConstants.APP_ID, parameterMap)));
}
if( ParameterMapUtils.notEmpty("delete", parameterMap) && ParameterMapUtils.firstValue("delete",parameterMap).equals("true") ) {
if( !ParameterMapUtils.empty("deleteConfirm", parameterMap)
&& ParameterMapUtils.firstValue("deleteConfirm", parameterMap).equals(FormConstants.APP_DELETE_CONFIRM_TEXT) ) {
try {
modelManager.begin();
modelManager.delete(app,events);
modelManager.commit(events);
events.add( new MessagesEvent("Application successfully deleted!") );
app = null;
// we remove the applicationId parameter, so that the form can populate empty
parameterMap.remove(FormConstants.APP_ID);
} catch(Exception e) {
events.add(new MessagesEvent(String.format("Application delete failed: %s %s"
,ExceptionUtils.getRootCauseMessage(e)
,ExceptionUtils.getRootCauseStackTrace(e)[0])));
logger.error("Deleting application with id "+app.getId()+" failed",e);
modelManager.rollback();
}
} else {
events.add( new MessagesEvent("You must confirm your desire to delete by typing in the delete confirmation message.") );
}
}
}
// the user is visiting the page to view or modify an application
else if( ParameterMapUtils.notEmpty(FormConstants.APP_ID,parameterMap) ) {
app = modelManager.getModelService().findByPrimaryKey(Application.class, Long.valueOf( ParameterMapUtils.firstValue(FormConstants.APP_ID, parameterMap) ) );
}
if( app == null && ParameterMapUtils.notEmpty(FormConstants.APP_ID,parameterMap) ) {
events.add( new MessagesEvent("Application with id "+ParameterMapUtils.firstValue(FormConstants.APP_ID, parameterMap)+" not found") );
} else if( app!=null && app.getId()!=null ) {
// in order to create the
ApplicationVersion testVer = new ApplicationVersion();
testVer.setApplication(app);
Boolean mayCreateVersions = modelManager.getAuthorizer().may(Authorizer.Action.CREATE, testVer);
if( mayCreateVersions ) {
events.add( new AddSubNavAnchorEvent( new Anchor("?bean=addModifyAppVersionPage&applicationId="+app.getId(),"Create new version","Create new version")) );
}
events.add( new AddSubNavAnchorEvent(new Anchor("?bean=appVersionListingsPage&applicationId="+app.getId(),"Version Listings","Version Listings")) );
events.add( new AddSubNavAnchorEvent(new Anchor("?bean=deploymentListingsPage&applicationId="+app.getId(),"Deployment History","Deployment History")) );
}
fillInVariablesFromApplication(templateVariables,app);
return events;
}
/**
* Create a new application object from the parameters passed in
*
* @param parameterMap
* @return
*/
private Application createApplicationFromParameters(Application app, Map<Object,Object> parameterMap, List<ProcessingEvent> events) {
if( app == null ) {
app = new Application();
}
app.setName(ParameterMapUtils.firstValue("name",parameterMap));
app.setAdmins(ParameterMapUtils.firstValue(FormConstants.APP_ADMINS,parameterMap));
app.setVersionAdmins(ParameterMapUtils.firstValue(FormConstants.APP_VERSIONADMINS,parameterMap));
app.setDescription(ParameterMapUtils.firstValue(FormConstants.APP_DESCRIPTION,parameterMap));
app.setInitialVersionIdentifier(ParameterMapUtils.firstValue("initialVersionIdentifier",parameterMap));
String deploymentHistoryLength = ParameterMapUtils.firstValue(FormConstants.APP_DEPL_HIST_LEN,parameterMap);
if( deploymentHistoryLength!=null && deploymentHistoryLength.trim().matches("[\\d]+") ) {
app.setDeploymentHistoryLength(Integer.valueOf(deploymentHistoryLength.trim()));
}
// update the salt used for generating authentication tokens
String salt = ParameterMapUtils.firstValue("proxyAuthSalt",parameterMap);
String saltConf = ParameterMapUtils.firstValue("proxyAuthSaltConfirm",parameterMap);
if( salt!=null && saltConf!=null ) {
if( salt.length()>0 && saltConf.equals(salt) ) {
app.setProxyAuthSalt(salt);
} else if( !salt.equals(saltConf) ) {
events.add( new MessagesEvent("Proxy authentication salt value not set. Entries did not match.") );
}
}
return app;
}
/**
* Populate the template variables with information from an application object instance
*
* @param section
* @param app
*/
private void fillInVariablesFromApplication(Map<Object,Object> vars, Application app) {
vars.put("application", app);
}
}