/* ===============================================================================
*
* Part of the InfoGlue Content Management Platform (www.infoglue.org)
*
* ===============================================================================
*
* Copyright (C)
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2, as published by the
* Free Software Foundation. See the file LICENSE.html for more information.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, including 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, write to the Free Software Foundation, Inc. / 59 Temple
* Place, Suite 330 / Boston, MA 02111-1307 / USA.
*
* ===============================================================================
*/
package org.infoglue.cms.applications.databeans;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.cglib.core.ProcessArrayCallback;
import org.apache.log4j.Logger;
import org.infoglue.cms.applications.managementtool.actions.ExportRepositoryAction;
import org.infoglue.cms.security.InfoGluePrincipal;
import org.infoglue.cms.util.ChangeNotificationController;
import com.google.gson.Gson;
import com.google.gson.annotations.Expose;
/**
* This bean allows for processes to give information about the process itself and what the status is.
* The bean has a listener option in which an external class can ask it to report process when it happens (push).
*
* @author Mattias Bogeblad
*/
public class ProcessBean
{
private final static Logger logger = Logger.getLogger(ProcessBean.class.getName());
//The class has its own factory and list of all active processBeans
private static List<ProcessBean> processBeans = new ArrayList<ProcessBean>();
public static List<ProcessBean> getProcessBeans()
{
return processBeans;
}
/**
* Returns a list of all processes that has he given <em>processName</em>.
*
* The returned list is a shallow (filtered) copy of the list holding all processes.
* As such changes made to the list will not be reflected in the original list however
* changes made to the ProcessBeans in the list <b>will</b> affect the original process object.
* @param processName
* @return
*/
public static List<ProcessBean> getProcessBeans(String processName)
{
List<ProcessBean> processBeansWithName = new ArrayList<ProcessBean>();
for(ProcessBean processBean : processBeans)
{
if(processBean.getProcessName().equals(processName))
processBeansWithName.add(processBean);
}
return processBeansWithName;
}
public static ProcessBean getProcessBean(String processName, String processId)
{
for(ProcessBean processBean : processBeans)
{
if(processBean.getProcessName().equals(processName) && processBean.getProcessId().equals(processId))
return processBean;
}
return null;
}
public static ProcessBean createProcessBean(String processName, String processId)
{
ProcessBean processBean = new ProcessBean(processName, processId, processId);
getProcessBeans().add(processBean);
return processBean;
}
public static ProcessBean createProcessBean(String processName, String processId, String processDisplayName)
{
ProcessBean processBean = new ProcessBean(processName, processId, processDisplayName);
getProcessBeans().add(processBean);
return processBean;
}
//-End factory stuff
public static final int NOT_STARTED = 0;
public static final int RUNNING = 1;
public static final int FINISHED = 2;
/** Indicates that the process has entered an unrecoverable error state. */
public static final int ERROR = 3;
public static final int REDIRECTED = 4;
//ID can be any string the process decides while processName is a general name for all instances of a certain process.
//processDisplayName is a visually appealing name of the unique process.
private String processName;
private String processId;
private String processDisplayName;
private int status = NOT_STARTED;
// TODO should the dates really be initiated here? getFinished() will say that the process has finished even though it has not
private Date started = new Date();
private Date finished = new Date();
private String errorMessage;
private Throwable exception;
private String redirectUrl;
private transient List<ProcessBeanListener> listeners = new ArrayList<ProcessBeanListener>();
private List<String> processEvents = new ArrayList<String>();
private Map<String,Map<String,Object>> artifacts = new HashMap<String,Map<String,Object>>();
private List<File> files = new ArrayList<File>();
private ProcessBean()
{
}
private ProcessBean(String processName, String processId, String processDisplayName)
{
this.processName = processName;
this.processId = processId;
this.processDisplayName = processDisplayName;
}
/**
* This method sends the event description to all listeners.
*
* @param eventDescription
*/
public void updateProcess(String eventDescription)
{
processEvents.add(eventDescription);
// TODO Does this need to be synchronized with adding listeners?
for(ProcessBeanListener processBeanListener : listeners)
{
try
{
processBeanListener.processUpdated(eventDescription);
}
catch (Exception e)
{
logger.error("Error updating ProcessBeanListener: " + e.getMessage());
}
}
}
/**
* This method sends the event description to all listeners.
*
* @param eventDescription
*/
public void updateLastDescription(String eventDescription)
{
if(processEvents.size() > 0)
processEvents.remove(processEvents.size() - 1);
processEvents.add(eventDescription);
// TODO Does this need to be synchronized with adding listeners?
for(ProcessBeanListener processBeanListener : listeners)
{
try
{
processBeanListener.processUpdatedLastDescription(eventDescription);
}
catch (Exception e)
{
logger.error("Error updating ProcessBeanListener: " + e.getMessage());
}
}
}
/**
* This method sends the new artifact to all listeners.
*
*
*/
public void updateProcessArtifacts(String artifactId, String url, File file)
{
Map<String,Object> artifactDescMap = new HashMap<String,Object>();
artifactDescMap.put("url", url);
artifactDescMap.put("file", file);
artifactDescMap.put("fileSize", file.length());
artifacts.put(artifactId, artifactDescMap);
files.add(file);
for(ProcessBeanListener processBeanListener : listeners)
{
try
{
processBeanListener.processArtifactsUpdated(artifactId, url, file);
}
catch (Exception e)
{
logger.error("Error updating ProcessBeanListener: " + e.getMessage());
}
}
}
/**
* This method removes the bean from list of active processes and clears all references.
*/
public void removeProcess()
{
updateProcess("Process removed");
this.listeners.clear();
if(files != null)
{
for(File file : files)
{
file.delete();
}
}
getProcessBeans().remove(this);
}
/**
* Same as calling {@link #setError(String, Throwable)} with null passed as the
* second parameter.
* @param errorMessage
*/
public void setError(String errorMessage)
{
setError(errorMessage, null);
}
/**
* Marks the process as an erroneous processes. Calling this method means that the process has
* terminated but was not successful. This method also sets the state of the process to {@link #ERROR}.
* @param errorMessage
* @param exception The exception that caused the process to fail. May be null if the error was not related to an exception.
*/
public void setError(String errorMessage, Throwable exception)
{
this.errorMessage = errorMessage;
this.exception = exception;
setStatus(ERROR);
}
/**
* Marks the process as an erroneous processes. Calling this method means that the process has
* terminated but was not successful. This method also sets the state of the process to {@link #ERROR}.
* @param errorMessage
* @param exception The exception that caused the process to fail. May be null if the error was not related to an exception.
*/
public void setRedirectUrl(String message, String redirectUrl)
{
updateProcess(message);
this.redirectUrl = redirectUrl;
setStatus(REDIRECTED);
}
public String getErrorMessage()
{
return this.errorMessage;
}
public Throwable getException()
{
return this.exception;
}
public String getProcessName()
{
return processName;
}
public String getProcessId()
{
return processId;
}
public String getProcessDisplayName()
{
return processDisplayName;
}
public int getStatus()
{
return this.status;
}
public Date getStarted()
{
return started;
}
public Date getFinished()
{
return finished;
}
/**
* Sets the status of the process.
*
* Possible values are:
* <ul>
* <li>{@linkplain #NOT_STARTED}</li>
* <li>{@linkplain #RUNNING}</li>
* <li>{@linkplain #FINISHED}</li>
* <li>{@linkplain #ERROR}</li>
* </ul>
*
* While it is allowed to set the state to {@link #ERROR} through this method
* it is encouraged to do it using the {@link #setError(String, Throwable)} method.
*
* @param status The new status. See available values in text above.
*/
public void setStatus(int status)
{
this.status = status;
if(status == RUNNING)
this.started = new Date();
else if(status == FINISHED || status == ERROR || status == REDIRECTED)
{
this.finished = new Date();
ChangeNotificationController.getInstance().notifyListeners();
}
}
public List<String> getProcessEvents()
{
return this.processEvents;
}
public Map<String,Map<String,Object>> getProcessArtifacts()
{
return this.artifacts;
}
public String getRedirectUrl()
{
return this.redirectUrl;
}
}