• Workflow para mover archivos

  • Hemos intentado hacer de OpenKM una aplicación lo más intuitiva posible, sin embargo siempre viene bien algún consejo.
Hemos intentado hacer de OpenKM una aplicación lo más intuitiva posible, sin embargo siempre viene bien algún consejo.
Forum rules: Por favor, antes de preguntar algo consulta el wiki de documentación o utiliza la función de búsqueda del foro. Recuerda que no tenemos una bola de cristal ni poderes mentales, o sea que que para informar sobre un error es necesario que nos indiques tanto la versión de OpenKM que usas como la del navegador y sistema operativo. Para más información consulta Cómo informar de fallos de forma efectiva.
 #4865  by Dracmore
 
Saludos, llevo un tiempo leyendo a la gente del foro pero hasta ahora no me había registrado y bueno haciendo uso de la costumbre que tenemos todos ahora que necesito ayuda me registro -.-u xD.

Edito para poner más datos y dejarlo más claro. Aquí está el xml que tengo:
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<process-definition  xmlns="urn:jbpm.org:jpdl-3.2"  name="flujo">
  <start-state name="start">
    <transition to="PlaceOrder" name="trPlaceOrder"></transition>
  </start-state>
  <task-node name="PlaceOrder">
    <task name="MyTask" >				
      <assignment actor-id="r.espinosa"></assignment>
			<controller></controller>			
    </task>	
		<transition to="CheckAvailability" name="to_CheckAvailability"></transition>
  </task-node>
  
  <decision name="CheckAvailability" expression="#{(aceptar>100)?'trNotAvailable':'trAvailable'}">
    <transition to="Valido" name="trAvailable"></transition>
    <transition to="NoValido" name="trNotAvailable"></transition>
  </decision>
 
  <task-node name="Valido">
		<transition to="end">
	</transition>
	</task-node>

	<task-node name="NoValido">
		<transition to="end"></transition>
	</task-node>
  <end-state name="end"></end-state>
</process-definition>
Tengo en Openkm 3 carpetas, facturas sin revisar, aceptadas y rechazadas, cuando se introduzca una factura en facturas sin revisar se le enviará un aviso al usuario que puse y el verá cuando loguee que tiene tareas, en dicha tarea le saldrá un campo donde pondrá si acepta la factura o la rechaza, si elige que no la factura debe moverse de facturas sin revisar hasta rechazas, si elige que sí entonces se moverá a la carpeta aceptadas. Por ahora me han surgido 2 problemas, el primero es que no sé como mover el archivo y me gustaría que se hiciera automáticamente. El segundo problema es que cuando agrego la tarea MyTask y genero el form para poner un botón y demás solo me aparecen las variables que puse al crearlo y no las que añado al xhtml, lo que me sale es:
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<forms>
  <form task="MyTask" form="MyTask.xhtml" />
</forms>
Y en OpenKM como he dicho me sale la variable que puse pero claro de esta forma solo puedo crear inputs.

Si añado cualquier tipo de botón ( <button label="submit" name="submit" /> por ejemplo) a mano, no aparece y me gustaría añadir un select con dos opciones, una para sí (aceptada) y otra no pero cuando lo añado no se visualiza en OpenKM.

Siento el tochopost pero me trae loco esto, llevo 3 semanas investigando todo el tema de los workflows y no sé que páginas mirar ya y para colmo el jefe me dice que a ver si lo tengo para mañana...en fin xD. Por cierto me he leído la wiki, la guia de JBPM de workflows, etc.
 #4877  by jllort
 
En la lógica para cada tarea puedes añadir clases. Vas a tener que crear una clase que Utilize los metodos de DirectDocumentModule en concreto el de mover
Code: Select all
public void move(String token, String docPath, String dstPath)
En el ejemplo avanzado tienes como se crea una clase, pues bien, allí es donde tienes que utilizar la clase esta del OpenKM ( tendras que utilizar el jar para compilar etc... si bajar el codigo fuente y lo compilas te generara un openkm-classes.jar a parte del OpenKM.war)

Para el tema de los botones puede ser algo asi:
Code: Select all
<workflow-form task="revisar">
    <textarea label="Motivo desaprovación" name="motivo"/>
  	<button label="Aprobar" value="aprobado" type="transition" />
    <button label="No aprobar" value="no_aprobado" type="transition" />
</workflow-form>
Ojo al dato: Sobre que versión de OpenKM estas haciendo lo del workflow, lo digo por que la 4.1 es la versión que te conviene ( ha mejorado mucho ).
 #4882  by Dracmore
 
Pues no sé la versión exacta ya que no estoy en el trabajo, mañana miraré a ver si es esa y si es una inferior veré que puedo hacer para pasarme a esa. También probaré a hacer lo de mover el archivo como me has dicho y ya diré algo por aquí, muchas gracias por tu ayuda :).
 #4888  by Dracmore
 
Bueno ando perdido otra vez y creo que más xD, me metí en https://openkm.svn.sourceforge.net/svnroot/openkm/ y vi la clase que me dijste, la copié pero claro debido a los import necesitaba muchas más y he ido añadiendo hasta que tenía mil clases que no me hacian falta para el método que quería (move), bien me gustaría saber qué necesito exactamente porque ando más perdido......., tengo lo siguiente:

La acción:
Code: Select all
package es.git.openkm;

import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import es.git.openkm.api.OKMDocument;

public class MoverActionHandler implements ActionHandler {
	
	private static final long serialVersionUID = 1L;
	private static Logger log = LoggerFactory.getLogger(MoverActionHandler.class);
	
	public MoverActionHandler() {
	}
	
	public void execute(ExecutionContext ctx) throws Exception {
		String path = (String)ctx.getContextInstance().getVariable("path");
		log.info("Path: "+path);
		String token="r.espinosa";
		log.info("Token: "+token);
		OKMDocument.getInstance().move(token, path, "/okm:root/Neumaticos soledad/Departamentos/Informatica/pruebas/valido");	
	}
}
En este caso el tema de import org.slf4j lo que hice fue bajarlo y añadirlo al path a saco, bueno los jars de dentro, no sé si es lo correcto.

Aquí pongo la otra clase que tengo OKMFolder:
Code: Select all
package es.git.openkm.api;

import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import es.git.openkm.bean.ContentInfo;
import es.git.openkm.bean.Folder;
import es.git.openkm.module.FolderModule;
import es.git.openkm.module.ModuleManager;

public class OKMFolder implements FolderModule {
	private static Logger log = LoggerFactory.getLogger(OKMFolder.class);
	private static OKMFolder instance = new OKMFolder();
	
	private OKMFolder() {}
	
	public static OKMFolder getInstance() {
		return instance;
	}
	

	@Override
	public Folder create(String token, Folder fldPath) {
		log.debug("create("+token+", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		Folder newFld = fm.create(token, fldPath);
		log.debug("create: "+ newFld);
		return newFld;
	}
	

	@Override
	public Folder getProperties(String token, String fldPath)  {
		log.debug("getProperties("+token+", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		Folder fld = fm.getProperties(token, fldPath);
		log.debug("getProperties: "+fld);
		return fld;
	}
	

	@Override
	public void delete(String token, String fldPath){
		log.debug("delete("+token+", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		fm.delete(token, fldPath);
		log.debug("delete: void");
	}

	@Override
	public void purge(String token, String fldPath) {
		log.debug("purge("+token+", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		fm.purge(token, fldPath);
		log.debug("purge: void");
	}
	

	@Override
	public Folder rename(String token, String fldPath, String newName) {
		log.debug("rename("+token+", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		Folder renamedFolder = fm.rename(token, fldPath, newName);
		log.debug("rename: "+renamedFolder);
		return renamedFolder;
	}
	

	@Override
	public void move(String token, String fldPath, String dstPath){
		log.debug("move("+token+", " + fldPath + ", " + dstPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		fm.move(token, fldPath, dstPath);
		log.debug("move: void");
	}

	@Override
	public void copy(String token, String fldPath, String dstPath) {
		log.debug("copy("+token+", " + fldPath + ", " + dstPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		fm.copy(token, fldPath, dstPath);
		log.debug("copy: void");
	}
	
	@Override
	public Collection<Folder> getChilds(String token, String fldPath) {
		log.debug("getChilds(" + token + ", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		Collection<Folder> childs = fm.getChilds(token, fldPath);
		log.debug("getChilds: "+childs);
		return childs;
	}

	@Override
	public ContentInfo getContentInfo(String token, String fldPath)  {
		log.debug("getContentInfo(" + token + ", " + fldPath + ")");
		FolderModule fm = ModuleManager.getFolderModule();
		ContentInfo contentInfo = fm.getContentInfo(token, fldPath);
		log.debug("getContentInfo: "+contentInfo);
		return contentInfo;
	}
	
	
	@Override
	public boolean isValid(String token, String fldPath)  {
		log.debug("isValid("+token+", "+fldPath+")");
		FolderModule fm = ModuleManager.getFolderModule();
		boolean valid = fm.isValid(token, fldPath);
		log.debug("isValid: "+valid);
		return valid;
	}
}
Por último tengo la clase DirectDocumentModule:
Code: Select all
package es.git.openkm.module.direct;

import java.io.InputStream;
import java.util.Collection;

import es.git.openkm.bean.Document;
import es.git.openkm.bean.Lock;
import es.git.openkm.bean.Version;
import es.git.openkm.module.DocumentModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;




public class DirectDocumentModule implements DocumentModule {
	private static Logger log = LoggerFactory.getLogger(DirectDocumentModule.class);
	@Override
	public void addNote(String token, String docPath, String text) {
		// TODO Auto-generated method stub

	}

	@Override
	public void cancelCheckout(String token, String docPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public Version checkin(String token, String docPath, String comment) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void checkout(String token, String docPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public void copy(String token, String docPath, String fldPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public Document create(String token, Document doc, InputStream is) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void delete(String token, String docPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public Collection<Document> getChilds(String token, String fldPath) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public InputStream getContent(String token, String docPath, boolean checkout) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public InputStream getContentByVersion(String token, String docPath,
			String versionId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Lock getLock(String token, String docPath) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String getPath(String token, String uuid) {
		log.debug("getPath(" + token + ", " + uuid + ")");
		String path = null;
/*
			Session session = SessionManager.getInstance().get(token);
			Node node = session.getNodeByUUID(uuid);

			if (node.isNodeType(Document.TYPE)) {
				path = node.getPath();
			}
		log.debug("getPath: "+path);
*/
		return path;
	}


	@Override
	public Document getProperties(String token, String docPath) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection<Version> getVersionHistory(String token, String docPath) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public long getVersionHistorySize(String token, String docPath) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean isCheckedOut(String token, String docPath) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isLocked(String token, String docPath) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isValid(String token, String docPath) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void lock(String token, String docPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public void move(String token, String docPath, String fldPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public void purge(String token, String docPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public void purgeVersionHistory(String token, String docPath) {
		// TODO Auto-generated method stub

	}

	@Override
	public Document rename(String token, String docPath, String newName) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void restoreVersion(String token, String docPath, String versionId) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setContent(String token, String docPath, InputStream is) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setProperties(String token, Document doc) {
		// TODO Auto-generated method stub

	}

	@Override
	public void unlock(String token, String docPath) {
		// TODO Auto-generated method stub

	}

}
En fin hay cosas como comentario porque cada 2x3 me pide alguna clase, no sé si hay alguna forma de que se añadan todas las clases directamente o si se puede hacer un método a saco sin añadir tanta clase, no sé si me explico pero vamos, que estoy muy confundido creo yo.

Por cierto puse en el form lo que me pusiste y no me apareció en el apartado de datos en el flujo como dije, no sé por qué ponga lo que ponga no varia, sólo salen las variables que tuviera al crear el form poniendome en la task y generate form, en la ventanita que se abre tengo que poner las variables que sean o sino no aparecerán :S

De paso ¿cómo consigo librerías como import javax.jcr para session y demás :/?.

P.D: me bajé el source de OpenKM que lleva todas las clases y demás, si añado eso de alguna forma, ¿podré trabajar sin añadir nada más?, ¿lo añado todo a mi proyecto o no hace falta?
 #4987  by Pepito
 
Una pregunta, estoy tratando de hacer el mismo workflow y no obtengo ningún error pero no se mueve el archivo, la ruta de destino es "/okm:root/valido" (¿se pone así?) y bueno no sé, lo que sospecho es que no llega a ejecutar el Handler, ¿hay alguna forma de comprobar si lo ejecuta? o, ¿se pueden mostrar por pantalla los valores de las variables path y token?.


Handler:
Code: Select all
package com.sample.action;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import es.git.openkm.core.SessionManager;
import es.git.openkm.module.direct.DirectDocumentModule;

public class MessageActionHandler implements ActionHandler {

	private static final long serialVersionUID = 1L;
	
	private static Logger log = LoggerFactory.getLogger(MessageActionHandler.class);
	
	public void execute(ExecutionContext ctx) throws Exception {
		 ctx.getContextInstance().setVariable("aceptar", new Integer(300));
	String path = (String)ctx.getContextInstance().getVariable("path");
	log.info("Path: "+path);
	String token = SessionManager.getInstance().getSystemToken();
	log.info("Token: "+token);
	DirectDocumentModule.class.newInstance().move(token, path, "/okm:root/valido");
	}
}
EDITO
Sí obtengo un error finalmente:
Code: Select all
type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException: An exception occurred processing JSP page /admin/wf_procins.jsp at line 260

257: 				String key = it.next();
258: 				out.print("<tr class=\""+(i++%2==0?"odd":"even")+"\">");
259: 				out.print("<td>"+key+"</td>");
260: 				out.print("<td>"+vars.get(key)+"</td>");
261: 				out.print("<td>");
262: 				out.print("<a href=\"wf_procins.jsp?action=removeVar&id="+pi.getId()+"&name="+key+"\">Remove</a>");
263: 				out.print("</td>");


Stacktrace:
	org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:504)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:415)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:336)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)

root cause

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
	org.apache.jsp.admin.wf_005fprocins_jsp._jspService(wf_005fprocins_jsp.java:323)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:373)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:336)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
	org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
 #5015  by jllort
 
Todo requiere su tiempo, el tema del workflow no es trivial segun lo que se quiera hacer a mas potencia, mas versatilidad y mas complejidad ... y requiere un mayor tiempo de lucha con el invento.
 #5031  by Pepito
 
Pongo aquí el post por no llenar demasiado el foro con tanta pregunta xD.

He añadido al workflow que cuando se mueva se añada una nota con:
Code: Select all
String path = (String)ctx.getContextInstance().getVariable("path");
String token = SessionManager.getInstance().getSystemToken();
DirectDocumentModule.class.newInstance().addNote(token, path, (String)ctx.getContextInstance().getVariable("Observaciones"));
DirectDocumentModule.class.newInstance().move(token, path, "/okm:root/pruebas/valido");
La nota me la añade bien el problema es que la añade como si la hubiera metido el usuario system y no el mío, de tal forma que no sale la notificación de que se ha añadido una nota al archivo aunque si voy a notas sí me sale.

¿Debo usar otro método?.
 #5038  by jllort
 
En que momento se ejecuta este código, si es una tarea automática ( de paso entre tareas de usuario ) lo ejecuta el usuario system, razon por la cual la nota se le asigna a este usuario, si esto esta dentro de una tarea asignada a un usuario y es este el que la ejecuta entonces la nota será asignada a este usuario.
 #5074  by Pepito
 
Bueno he añadido otra mejora al workflow, he hecho que cuando se asigna el workflow a un archivo, se mueva a una carpeta "sinvalidar" de tal forma que una vez dentro salte la tarea de aceptar o rechazar ese archivo. Lo de aceptar o rechazar funciona correctamente pero la acción previa (la de moverlo a "sinvalidar") la hace pero dando una serie de fallos, es decir, mueve el documento pero me salta un fallo como que al ruta no existe, no sé por qué falla si luego muevo el documento otra vez y lo hace perfectamente. La acción de la que hablo está ántes de ejecutar la tarea que se asigna a un usuario, es decir, se inicia el workflow y en la transición a la tarea ejecuto la acción. ¿Podría suprimir esos mensajes?, total me lo mueve bien...
 #5079  by jllort
 
hombre ponle un try { } catch y cometelos ... estaria bien ver el fallo que te da
 #5088  by Pepito
 
Ya probé a comerme las excepciones pero no me funcionó, a no ser que me faltara alguna pero puse la "global" también...., el error es el siguiente:

OKM-002015(GetVersionHistorySize): La ruta del documento no existe

okm:root/carpetas/pruebas/valido/prueba.txt

OKM-002015(GetVersionHistory): La ruta del documento no existe

okm:root/carpetas/pruebas/valido/prueba.txt

OKM-009015 (GetAllGroups): OKM-009015

okm:root/carpetas/pruebas/valido/prueba.txt

OKM-007015 (GetGrantedRoles): OKM-007015

okm:root/carpetas/pruebas/valido/prueba.txt

OKM-007015 (GetGrantedUsers): OKM-007015

okm:root/carpetas/pruebas/valido/prueba.txt


La acción que hago como ya dije la realizo nada más ejecutarse la tarea (en la transición desde el start hasta la primera task) y el código es el siguiente, vamos, el mismo código que uso después para mover a valido o novalido, en ambos casos me mueve el fichero perfectamente, incluso añado notas pero en esta primera acción pese a moverlo bien saltan esos errores:
Code: Select all
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import es.git.openkm.core.SessionManager;
import es.git.openkm.module.direct.DirectDocumentModule;

public class MessageActionHandler2 implements ActionHandler {

	private static final long serialVersionUID = 1L;
	
	public MessageActionHandler2() {
		
	}
	public void execute(ExecutionContext ctx) {
		String token = SessionManager.getInstance().getSystemToken();
		String uuid = (String)ctx.getContextInstance().getVariable("uuid");
		String path;
		try {
			path = DirectDocumentModule.class.newInstance().getPath(token, uuid);
			DirectDocumentModule.class.newInstance().move(token, path, "/okm:root/carpetas/pruebas/sinvalidar");
		} catch (Exception e) {
		
		}
		
	}
}
El fallo creo que es porque no se actualiza la taxonomía, ¿existe algún método para refrescarla?.

De paso pregunto otra cosilla:
Sobre lo de añadir notas he probado a poner un evento dentro del task-node y poner ahí la acción pero sigue cogiendo system, ¿dónde dices exactamente que debo poner la acción (la tarea la realiza el usuario que la tiene asignada), en un controllerevent o dónde?
 #5100  by jllort
 
pones la nota así ? según a que usuario pertenezca el token te pondrá una cosa u otra.
Code: Select all
OKMDocument.getInstance().addNote(token, docPath, text);

About Us

OpenKM is part of the management software. A management software is a program that facilitates the accomplishment of administrative tasks. OpenKM is a document management system that allows you to manage business content and workflow in a more efficient way. Document managers guarantee data protection by establishing information security for business content.