5.- Casos de uso PFI de ejemplo

En este apartado se van a explicar diferentes casos de uso y cómo podría implementarlos una aplicación integradora.


Ejemplo 1: puesta a disposición de un documento para su firma, con un solo firmante 


 Click here to expand...

Para que una aplicación pueda crear documentos y aparezcan en la aplicación  de PFI en pendientes de firma se necesitara llamar al createDocument de CCSV y integrarse con esa aplicación que están explicados en el apartado de la aplicación CCSV. 

Pero para que se guarde en Pendientes de Firma en PFI debe haber una serie de meta-datos obligatorios como los de el firmante propuesto y el estado en pendiente de firma  para que se guarde automáticamente con este código de ejemplo se muestran los campos de como se debería guardar un documento para firmarlo en PFI:

PASO 1: Envío del documento a CCSV

Ejemplo de invocación
		String idApp = "CCSV";
		String filename = "prueba_CreateDocument.pdf";

		CSVGenerator csvGenerator = new CSVGenerator();
		String csv = csvGenerator.generateCSV("CCSV", "1");

		Document doc = new Document();
		doc.setApplicationCode(idApp);
		doc.setApplicationName(idApp);
		doc.setCsv(csv);
		doc.setExtension("PDF");
		doc.setFormat(DocumentumConstants.Formato.PDF_A);
		doc.setName(filename);
		doc.setType(DocumentumConstants.TipoDocumental.DEA);

		ParamInitializeDocumentMetadata paramInitializeDocumentMetadata = new ParamInitializeDocumentMetadata();
		paramInitializeDocumentMetadata.setDocument(doc);
		paramInitializeDocumentMetadata.setDocumentType(DocumentumConstants.TipoDocumento.DOCUMENTACION_JUSTIFICATIVA);
		paramInitializeDocumentMetadata.setProcedureCode("830");
		paramInitializeDocumentMetadata.setApplicationId(idApp);
		ResultInitializeDocumentMetadata resultInitializeDocumentMetadata = ccsvClientDocumentMetadataSignatureService.initializeDocumentMetadata(paramInitializeDocumentMetadata);

		if (resultInitializeDocumentMetadata.getReturnCode().equals(ReturnCode.OK)) {
			try {
				InputStream documentInputStream = new FileInputStream("C:/Pruebas/CCSV_Tests/AST_EFIRMA_ManualIntegracion.pdf");

				byte[] physicalDocumentByteArray = getBytesFromInputStream(documentInputStream);
				DataHandler docu = new DataHandler(new ByteArrayDataSource(physicalDocumentByteArray));
				MessageDigest md = MessageDigest.getInstance("SHA");
				byte[] hash = md.digest(physicalDocumentByteArray);

				Document document = resultInitializeDocumentMetadata.getDocument();

				// Metadatos generales del documento
				// -------------------------------------------------------------------------------
				HashMap<String, Object> metadatos = document.getMetadata();

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_CONTEXTO_GESTOR_COD_PROCEDIMIENTO, "830");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_CONTEXTO_GESTOR_NOMBRE_PROCEDIMIENTO, "PROCEDIMIENTO DE CONTRATACIÓN DEL SECTOR PÚBLICO");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_DESCRIPCION, "Pruebas CCSV-809");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_ESTADO, DocumentumConstants.Estado.PENDIENTE_DE_FIRMA);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_IDIOMA, DocumentumConstants.Idioma.CASTELLANO);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_NOMBRE, filename);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_TIPO_DOCUMENTO, DocumentumConstants.TipoDocumento.PUBLICACION_OFICIAL);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CODIGO_CLASIFICACION, "0");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_DENOMINACION_CLASIFICACION, "Desconocido");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CODIGO_APLICACION, "CCSV");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CODIGO_REFERENCIA, "PRUEBA-LPL-20180905");

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CSV, csv);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CSV_ESQUEMA, "CSV 1.0");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_FECHA_CAPTURA, "2018-09-05T09:00:00");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_NOMBRE_APLICACION, "CCSV");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_ORIGEN, DocumentumConstants.Origen.ADMINISTRACION);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_URL_VERIFICACION, "https://gobierno.aragon.es/verificadoc");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_VERSION_NTI_DGA, "http://www.aragon.es/NTI_2.0.0");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_NTI_TIPO_CATEGORIA, DocumentumConstants.Categoria.DOCUMENTO_SIMPLE);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_NTI_TIPO_ENTIDAD, DocumentumConstants.TipoEntidad.DOCUMENTO);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_SEGURIDAD_BLOQUEO, "N");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_SEGURIDAD_NIVEL_LOPD, DocumentumConstants.NivelLOPD.BASICO);

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_SEG_VISIBLE_EXTERIOR, DocumentumConstants.Visible.VISIBLE);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_TECNICOS_FORMATO, DocumentumConstants.Formato.PDF_A);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_TECNICOS_SOPORTE_ORIGINAL, DocumentumConstants.SoporteOriginal.DIGITAL);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_VERIFICACION_ALGORITMO, "SHA-1");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_VERIFICACION_RESUMEN, BASE64Encoder.encode(hash).toString());

				// FIRMANTE_PROPUESTO
				// -------------------------------------------------------------------------------
				ParamInitializeStructuredMetadata paramInitializeStructuredMetadata = new ParamInitializeStructuredMetadata(DocumentumConstants.NombreMetadatos.PAEGA_FIRMANTE_PROPUESTO);
				paramInitializeStructuredMetadata.setApplicationId(idApp);
				ResultInitializeStructuredMetadata resultInitializeStructuredMetadata = ccsvClientDocumentMetadataSignatureService.initializeStructuredMetadata(paramInitializeStructuredMetadata);

				Document docfp = resultInitializeStructuredMetadata.getDocument();

				HashMap<String, Object> firmante_propuesto = docfp.getMetadata();
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_DESCRIPCION_NOMBRE, "MANUELA BLANCO VIDAL");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_CARGO, "ROL25248");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_DESCRIPCION_CARGO, "Empleado");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_ORGANISMO, "ORG07458");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_IDENTIFICACION_IDENTIFICACION, "Q0100000I");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_IDENTIFICACION_TIPO_IDENTIFICACION, "N");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_NTI_TIPO_CATEGORIA, "Empleado Público");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_NTI_TIPO_ENTIDAD, "Agente");

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_FIRMANTE_PROPUESTO, docfp);

				

				// RELACIONES
				// -------------------------------------------------------------------------------
				Object[] relaciones = (Object[]) metadatos.get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION);
				for (Object ob : relaciones) {
					Document documentRelation = (Document) ob;
					if (documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION_ROL).equals(DocumentumConstants.RolRelacion.APORTADOR)) {
						// Aportador
						Agent aportador = AgentRelationshipUtils.documentToAgent((Document) documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE));
						aportador.setCategory(DocumentumConstants.CategoriaAgente.FUNCIONARIO);
						aportador.setIdentificationType(DocumentumConstants.TipoIdentificacion.NIF);
						aportador.setIdentificationNumber("00000000T");
						aportador.setName("PRUEBASPF APELLIDOUNOPF APELLIDODOSPF");
						documentRelation.getMetadata().put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE, AgentRelationshipUtils.agentToDocument(aportador));
					} else if (documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION_ROL).equals(DocumentumConstants.RolRelacion.ORGANISMO_PRODUCTOR)) {
						// Organismo productor
						Agent productor = AgentRelationshipUtils.documentToAgent((Document) documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE));
						productor.setCategory(DocumentumConstants.CategoriaAgente.ORGANISMO);
						productor.setIdentificationType(DocumentumConstants.TipoIdentificacion.CODIGO_ORGANISMO_SIU);
						productor.setIdentificationNumber("ORG07458");
						productor.setName("VICEPRESIDENCIA");
						productor.setOrganismResponsible("96666666N");
						documentRelation.getMetadata().put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE, AgentRelationshipUtils.agentToDocument(productor));
					} else {
						System.out.println("Relaci?n no identificada: " + ((Document) ob).getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION_ROL));
					}
				}

				document.setContent(docu);

				ParamCreateDocument paramCreateDocument = new ParamCreateDocument();
				paramCreateDocument.setApplicationId(idApp);
				paramCreateDocument.setDocument(document);
				paramCreateDocument.setNif("00000000T");

				ResultCreateDocument result = ccsvClientDocumentMetadataSignatureService.createDocument(paramCreateDocument);

				if (result.getReturnCode().equals(ReturnCode.ERROR)) {
					System.out.println(result.getErrorCode());
					System.out.println(result.getErrorMessage());
				} else {
					System.out.println("Documento " + csv + " creado y pendiente de firma.");
				}

			} catch (Exception ex) {
				System.out.println(ex.getMessage());
			}
		}


PASO 2: Notificar al firmante propuesto

Ejemplo de invocación
String nif = "12345678X";
String csv = "csv_generado_en_punto_anterior";

IAdviceService.sendAdvice(PFICoreConstants.NOTE_TYPE_PROPOSEDSIGNER, csv, null, nif);


PASO 3: Capturar el cambio de estado de un documento

Ejemplo de implementación
public class StateDocumentPFIImpl extends HttpServlet {
	private static final long serialVersionUID = 5954532668702585433L;
	private static final Logger LOG = CoreConfig.getLog(StateDocumentPFIImpl.class);
	private static final String INVALID_PARAMETERS = "Alguno de los parámetros necesarios está vacío";
	private static final String INVALID_STATE = "Estado del documento no es válido";
	private static final String UPDATESTATE_METHOD = "updateStateByPFI";
	private static final String APPID_PARAM = "appId";
	private static final String CSV_PARAM = "csv";
	private static final String STATE_PARAM = "state";
	private String appId;
	private IInfoService infoServicesPAUWS;
	private IDocumentManager documentManager;
	private ICCSVDocument ccsvManager;

	public void init() {
		WebApplicationContext applicationContext =ContextLoader.getCurrentWebApplicationContext();
		appId = "ID_APLICACION_INTEGRADORA";
		infoServicesPAUWS = (IInfoService) applicationContext.getBean("infoServicesPAUWS");
		documentManager = (IDocumentManager) applicationContext.getBean("documentManager");
		ccsvManager = (ICCSVDocument) applicationContext.getBean("ccsvManager");
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String applicationId = (String) request.getParameter(APPID_PARAM);
		String csv = (String) request.getParameter(CSV_PARAM);
		String state = (String) request.getParameter(STATE_PARAM);
		String ip = request.getRemoteAddr();
		try {
			validateParameters(applicationId, csv, state, ip);
			authorizeRequest(applicationId, ip, UPDATESTATE_METHOD);
			updateStateByPFI(csv, state);
		} catch (InternalCoreException e) {
			throw new ServletException(e.getMsg(), e);
		}
		response.setStatus(HttpServletResponse.SC_OK);
	}

	private void validateParameters(String applicationId, String csv,
		String state, String ip) throws ServletException {
		if (applicationId == null || applicationId.equals("")) {
			throw new ServletException(INVALID_PARAMETERS);
		}
		if (csv == null || csv.equals("")) {
			throw new ServletException(INVALID_PARAMETERS);
		}
		if (state == null || state.equals("")) {
			throw new ServletException(INVALID_PARAMETERS);
		}
		if (ip == null || ip.equals("")) {
			throw new ServletException(INVALID_PARAMETERS);
		}
	}

	private void authorizeRequest(String remoteApplicationId, String ip,
		String methodName) throws InternalCoreException {
		LOG.info("BEGIN authorizeRequest " + remoteApplicationId + "-" + appId + "-" + ip);
		ResultAuthorizeApplication resultAuthorizeApplication = new ResultAuthorizeApplication();
		try {
			// Obtenemos el código del método
			String methodCode = "";
			ParamMethodApplicationList paramMethodApplicationList = new ParamMethodApplicationList();
			paramMethodApplicationList.setApplicationAlias(appId);
			paramMethodApplicationList.setApplicationId(appId);
			ResultMethodApplicationList resultMethodApplicationList =
			infoServicesPAUWS.methodApplicationList(paramMethodApplicationList);
			es.aragon.pau.core.ws.data.Method[] methods = resultMethodApplicationList.getMethods();
			for (es.aragon.pau.core.ws.data.Method m : methods) {
				if (m.getName().equals(methodName)) {
					methodCode = m.getMethodCode();
					break;
				}
			}
			// Solicitamos autorización
			ParamAuthorizeApplication paramAuthorizeApplication = new ParamAuthorizeApplication();
			paramAuthorizeApplication.setApplicationId(appId);
			paramAuthorizeApplication.setApplicationAliasA(remoteApplicationId);
			paramAuthorizeApplication.setApplicationAliasB(appId);
			paramAuthorizeApplication.setIp(ip);
			paramAuthorizeApplication.setMethodCode(methodCode);
			resultAuthorizeApplication =
			infoServicesPAUWS.authorizeApplication(paramAuthorizeApplication);
			LOG.info("Servicio PFI-SCE: Aplicación Llamante" + remoteApplicationId + " IP:" + ip);
		} catch (Exception e) {
			throw new InternalCoreException(SCECoreConstants.ERROR_APPLICATION_AUTHORIZATION, e);
		}

		// Si tiene errores pongo el mensaje de autorización
		if (resultAuthorizeApplication.isErrors()) {
			throw new InternalCoreException(SCECoreConstants.ERROR_APPLICATION_AUTHORIZATION, "La IP " + ip + " no está autorizada");
		}
		LOG.info("END authorizeRequest " + remoteApplicationId + "-" + appId + "-" + ip);
	}

	private void updateStateByPFI(String csv, String ccsvState) throws InternalCoreException {
		LOG.info("BEGIN updateStateByPFI " + csv);
		if (DocumentumConstants.Estado.ORIGINAL.equals(ccsvState)){
			//Este estado se recibirá cuando todos los firmantes hayan firmado correctamente el documento.
			//TODO: Realizar acciones necesarias en la Aplicación una vez que se conoce que el documento se ha firmado correctamente.
		} else if (DocumentumConstants.Estado.ANULADO.equals(ccsvState)) {
			//Este estado se recibirá cuando se haya rechazado la firma de un documento en Portafirmas por alguno de los firmantes.
			//TODO: Realizar acciones necesarias en la Aplicación una vez que se conoce que el documento ha sido rechazado por el firmante.
		} else if (DocumentumConstants.Estado.BORRADOR.equals(ccsvState)) {
			// Este estado se recibirá cuando por ejemplo el documento se ha propuesto para firmar por varios firmantes y haya transcurrido el periodo máximo fijado
			// por el preparador para realizar la firma sin que todos los firmantes hayan firmado el documento.
			//TODO: Realizar acciones necesarias en la Aplicación una vez que se conoce que el plazo trancurrido para la firma del documento por múltiples firmantes ha finalizado sin que todos ellos hayan firmado el documento.
		} else {
			// Se ha producido el cambio a un estado no esperado.
			//TODO: Realizar acciones necesarias en la aplicación para controlar el error.
		}
		LOG.info("END updateStateByPFI " + csv);
	}
...
}


Ejemplo 2: puesta a disposición de documento con varios firmantes no siendo obligatorio la firma de todos para estar firmado.



 Click here to expand...

Aunque el Portafirmas establece por defecto el quorum de un documento para que se ajuste a la cantidad de firmantes propuestos elegidos durante su preparación,  las aplicaciones integradoras tienen la posibilidad de alterar tanto el quorum del documento, como la fecha límite para completar el proceso de firma.


El concepto de quorum en portafirmas representa la cantidad de firmas mínima que requiere un documento para pasar a firmado


Tomando  como punto de partida un documento con 2 firmantes propuestos, podríamos alterar la puesta a disposición del documento para que no fuera obligatoria la firma de todos sus participantes, y aumentar el plazo para realizar su firma. Para ello deberíamos establecer el nuevo quorum del documento y su nueva fecha límite.


PASO 1: Envío del documento a CCSV

Ejemplo de invocación
		String idApp = "CCSV";
		String filename = "prueba_CreateDocument.pdf";

		CSVGenerator csvGenerator = new CSVGenerator();
		String csv = csvGenerator.generateCSV("CCSV", "1");

		Document doc = new Document();
		doc.setApplicationCode(idApp);
		doc.setApplicationName(idApp);
		doc.setCsv(csv);
		doc.setExtension("PDF");
		doc.setFormat(DocumentumConstants.Formato.PDF_A);
		doc.setName(filename);
		doc.setType(DocumentumConstants.TipoDocumental.DEA);

		ParamInitializeDocumentMetadata paramInitializeDocumentMetadata = new ParamInitializeDocumentMetadata();
		paramInitializeDocumentMetadata.setDocument(doc);
		paramInitializeDocumentMetadata.setDocumentType(DocumentumConstants.TipoDocumento.DOCUMENTACION_JUSTIFICATIVA);
		paramInitializeDocumentMetadata.setProcedureCode("830");
		paramInitializeDocumentMetadata.setApplicationId(idApp);
		ResultInitializeDocumentMetadata resultInitializeDocumentMetadata = ccsvClientDocumentMetadataSignatureService.initializeDocumentMetadata(paramInitializeDocumentMetadata);

		if (resultInitializeDocumentMetadata.getReturnCode().equals(ReturnCode.OK)) {
			try {
				InputStream documentInputStream = new FileInputStream("C:/Pruebas/CCSV_Tests/AST_EFIRMA_ManualIntegracion.pdf");

				byte[] physicalDocumentByteArray = getBytesFromInputStream(documentInputStream);
				DataHandler docu = new DataHandler(new ByteArrayDataSource(physicalDocumentByteArray));
				MessageDigest md = MessageDigest.getInstance("SHA");
				byte[] hash = md.digest(physicalDocumentByteArray);

				Document document = resultInitializeDocumentMetadata.getDocument();

				// Metadatos generales del documento
				// -------------------------------------------------------------------------------
				HashMap<String, Object> metadatos = document.getMetadata();

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_CONTEXTO_GESTOR_COD_PROCEDIMIENTO, "830");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_CONTEXTO_GESTOR_NOMBRE_PROCEDIMIENTO, "PROCEDIMIENTO DE CONTRATACIÓN DEL SECTOR PÚBLICO");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_DESCRIPCION, "Pruebas CCSV-809");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_ESTADO, DocumentumConstants.Estado.PENDIENTE_DE_FIRMA);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_IDIOMA, DocumentumConstants.Idioma.CASTELLANO);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_NOMBRE, filename);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_TIPO_DOCUMENTO, DocumentumConstants.TipoDocumento.PUBLICACION_OFICIAL);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CODIGO_CLASIFICACION, "0");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_DENOMINACION_CLASIFICACION, "Desconocido");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CODIGO_APLICACION, "CCSV");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CODIGO_REFERENCIA, "PRUEBA-LPL-20180905");

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CSV, csv);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_CSV_ESQUEMA, "CSV 1.0");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_FECHA_CAPTURA, "2018-09-05T09:00:00");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_NOMBRE_APLICACION, "CCSV");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_ORIGEN, DocumentumConstants.Origen.ADMINISTRACION);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_URL_VERIFICACION, "https://gobierno.aragon.es/verificadoc");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_IDENT_VERSION_NTI_DGA, "http://www.aragon.es/NTI_2.0.0");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_NTI_TIPO_CATEGORIA, DocumentumConstants.Categoria.DOCUMENTO_SIMPLE);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_NTI_TIPO_ENTIDAD, DocumentumConstants.TipoEntidad.DOCUMENTO);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_SEGURIDAD_BLOQUEO, "N");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_SEGURIDAD_NIVEL_LOPD, DocumentumConstants.NivelLOPD.BASICO);

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_SEG_VISIBLE_EXTERIOR, DocumentumConstants.Visible.VISIBLE);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_TECNICOS_FORMATO, DocumentumConstants.Formato.PDF_A);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_TECNICOS_SOPORTE_ORIGINAL, DocumentumConstants.SoporteOriginal.DIGITAL);
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_VERIFICACION_ALGORITMO, "SHA-1");
				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_VERIFICACION_RESUMEN, BASE64Encoder.encode(hash).toString());

				// FIRMANTE_PROPUESTO 1
				// -------------------------------------------------------------------------------
				ParamInitializeStructuredMetadata paramInitializeStructuredMetadata = new ParamInitializeStructuredMetadata(DocumentumConstants.NombreMetadatos.PAEGA_FIRMANTE_PROPUESTO);
				paramInitializeStructuredMetadata.setApplicationId(idApp);
				ResultInitializeStructuredMetadata resultInitializeStructuredMetadata = ccsvClientDocumentMetadataSignatureService.initializeStructuredMetadata(paramInitializeStructuredMetadata);

				Document docfp = resultInitializeStructuredMetadata.getDocument();

				HashMap<String, Object> firmante_propuesto = docfp.getMetadata();
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_DESCRIPCION_NOMBRE, "MANUELA BLANCO VIDAL");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_CARGO, "ROL25248");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_DESCRIPCION_CARGO, "Empleado");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_ORGANISMO, "ORG07458");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_IDENTIFICACION_IDENTIFICACION, "Q0100000I");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_IDENTIFICACION_TIPO_IDENTIFICACION, "N");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_NTI_TIPO_CATEGORIA, "Empleado Público");
				firmante_propuesto.put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_NTI_TIPO_ENTIDAD, "Agente");

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_FIRMANTE_PROPUESTO, docfp);


				// FIRMANTE_PROPUESTO 2
				// -------------------------------------------------------------------------------
				ParamInitializeStructuredMetadata paramInitializeStructuredMetadata2 = new ParamInitializeStructuredMetadata(DocumentumConstants.NombreMetadatos.PAEGA_FIRMANTE_PROPUESTO);
				paramInitializeStructuredMetadata2.setApplicationId(idApp);
				paramInitializeStructuredMetadata resultInitializeStructuredMetadata2 = ccsvClientDocumentMetadataSignatureService.initializeStructuredMetadata(paramInitializeStructuredMetadata);

				Document docfp2 = resultInitializeStructuredMetadata2.getDocument();

				HashMap<String, Object> firmante_propuesto_2 = docfp2.getMetadata();
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_DESCRIPCION_NOMBRE, "JUAN CARLOS BLANCO VIDAL");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_CARGO, "ROL25248");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_DESCRIPCION_CARGO, "Empleado");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_FUNCIONARIO_ORGANISMO, "ORG07458");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_IDENTIFICACION_IDENTIFICACION, "Q0200000X");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_IDENTIFICACION_TIPO_IDENTIFICACION, "N");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_NTI_TIPO_CATEGORIA, "Empleado Público");
				firmante_propuesto_2 .put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE_NTI_TIPO_ENTIDAD, "Agente");

				metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_FIRMANTE_PROPUESTO, docfp2);

				
				// RELACIONES
				// -------------------------------------------------------------------------------
				Object[] relaciones = (Object[]) metadatos.get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION);
				for (Object ob : relaciones) {
					Document documentRelation = (Document) ob;
					if (documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION_ROL).equals(DocumentumConstants.RolRelacion.APORTADOR)) {
						// Aportador
						Agent aportador = AgentRelationshipUtils.documentToAgent((Document) documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE));
						aportador.setCategory(DocumentumConstants.CategoriaAgente.FUNCIONARIO);
						aportador.setIdentificationType(DocumentumConstants.TipoIdentificacion.NIF);
						aportador.setIdentificationNumber("00000000T");
						aportador.setName("PRUEBASPF APELLIDOUNOPF APELLIDODOSPF");
						documentRelation.getMetadata().put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE, AgentRelationshipUtils.agentToDocument(aportador));
					} else if (documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION_ROL).equals(DocumentumConstants.RolRelacion.ORGANISMO_PRODUCTOR)) {
						// Organismo productor
						Agent productor = AgentRelationshipUtils.documentToAgent((Document) documentRelation.getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE));
						productor.setCategory(DocumentumConstants.CategoriaAgente.ORGANISMO);
						productor.setIdentificationType(DocumentumConstants.TipoIdentificacion.CODIGO_ORGANISMO_SIU);
						productor.setIdentificationNumber("ORG07458");
						productor.setName("VICEPRESIDENCIA");
						productor.setOrganismResponsible("96666666N");
						documentRelation.getMetadata().put(DocumentumConstants.NombreMetadatos.PAEGA_AGENTE, AgentRelationshipUtils.agentToDocument(productor));
					} else {
						System.out.println("Relaci?n no identificada: " + ((Document) ob).getMetadata().get(DocumentumConstants.NombreMetadatos.PAEGA_RELACION_ROL));
					}
				}

				document.setContent(docu);

				ParamCreateDocument paramCreateDocument = new ParamCreateDocument();
				paramCreateDocument.setApplicationId(idApp);
				paramCreateDocument.setDocument(document);
				paramCreateDocument.setNif("00000000T");

				ResultCreateDocument result = ccsvClientDocumentMetadataSignatureService.createDocument(paramCreateDocument);

				if (result.getReturnCode().equals(ReturnCode.ERROR)) {
					System.out.println(result.getErrorCode());
					System.out.println(result.getErrorMessage());
				} else {
					System.out.println("Documento " + csv + " creado y pendiente de firma.");
				}

			} catch (Exception ex) {
				System.out.println(ex.getMessage());
			}
		}


PASO 2: Establecer los nuevos parámetros del documento

Ejemplo de invocación
ParamUpdateQuorumAndLimitDate paramCheckQuorumAndDate = new ParamUpdateQuorumAndLimitDate();
// Se indica el código seguro de verificación del documento en CCSV generado en el paso anterior
paramCheckQuorumAndDate.setCsv(csv);

// Se establece la nueva cantidad de firmantes mínima
paramCheckQuorumAndDate.setQuorum(1);

// Se establece la nueva fecha límite para firmar el documento
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
Integer deferedDate = 7;
cal.add(Calendar.DATE, deferedDate);
paramCheckQuorumAndDate.setDate(cal.getTime());

// Realizamos la llamada al método
ResultUpdateQuorumAndLimitDate resultCheckQuorumAndDate = iDocumentIntegrationService.updateQuorumAndLimitDateDocument(paramCheckQuorumAndDate);

PASO 3: Capturar el cambio de estado de un documento

La aplicación integradora implementaría su Servlet del mismo modo que en el ejemplo anterior.


Ejemplo 3: Documento estado original y documento en estado copia


Para crear un documento en estado original

Se debe rellenar el metadato dea_desc_estado con valor P. No se debe rellenar el metadato dea_desc_tipo_copia.

En los metadatos que se rellenan para invocar a createDocument de CCSV, el metadato dea_desc_estado se rellenaría de la siguiente forma:

metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_ESTADO, DocumentumConstants.Estado.PENDIENTE_DE_FIRMA);

Cuando el documento quede en estado firmado en PFI, el valor del metadato dea_desc_estado será 0 (Firmado).


Para crear un documento en estado copia

Se debe rellenar el metadato dea_desc_estado con valor P y el metadato dea_desc_tipo_copia con un valor que esté en el rango entre 0 y 5. 

En los metadatos que se rellenan para invocar a createDocument de CCSV, los metadatos quedarían de la siguiente forma:

metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_TIPO_COPIA, DocumentumConstants.Estado.PENDIENTE_DE_FIRMA);
// en este caso se indica a modo de ejemplo copia simple
metadatos.put(DocumentumConstants.NombreMetadatos.PAEGA_DESC_TIPO_COPIA, DocumentumConstants.TipoCopia.COPIA_SIMPLE);

Cuando el documento quede en estado firmado en PFI, el valor del metadato dea_desc_estado será 2 (Copia) y el valor del metadato dea_desc_tipo_copia será el valor (entre 0 y 5) que se había introducido anteriormente al crear el documento.