Java tutorial
/* Copyright (C) 2007 Flix Garca Borrego (borrego at gmail.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package org.viafirma.nucleo.custodia; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.List; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xml.security.utils.XMLUtils; import org.viafirma.cliente.firma.TypeFormatSign; import org.viafirma.cliente.vo.FirmaInfoViafirma; import org.viafirma.excepciones.CodigoError; import org.viafirma.excepciones.ExcepcionErrorInterno; import org.viafirma.util.CheckDigit; import org.viafirma.util.XmlSignUtil; import org.w3c.dom.Document; import com.viavansi.framework.core.persistencia.servicios.excepciones.ExcepcionDatosNoEncontrados; import com.viavansi.framework.core.persistencia.servicios.excepciones.ExcepcionServicio; import com.viavansi.framework.tools.repositorio.ManagerFileRepository; import com.viavansi.framework.tools.repositorio.ManagerFileRepositoryFactory; import com.viavansi.framework.tools.repositorio.vo.DocumentVO; /** * Gestiona la custodia de documentos. Se comporta como un repositorio de * documentos. * * @author Felix Garcia Borrego (borrego at gmail.com) * @author Alexis Castilla Armero <Pencerval at Gmail.com> */ public class Custodia { private static Custodia singleton; ManagerFileRepository manager; public static final String SEPARADOR = "-"; /** * Nombre del parametro que indica el path absoluto en el que se encuentra * el directorio de custodia de documentos. */ private static final String PARAM_PATH_CUSTODIA = "PATH_CUSTODIA"; /** * @param manager2 */ private Custodia(ManagerFileRepository manager) { this.manager = manager; } public static Custodia getInstance() { if (singleton == null) { throw new ExceptionInInitializerError("El sistema de custodia no esta inicializado."); } return singleton; } /** * Inicializa el sistema de custoria. * * @param properties */ public static void init(Properties properties) { // inicializa el sistema de custodia de documentos. // comprobamos que el parametro que espera encontrar custodia existe String pathCustodia = properties.getProperty(PARAM_PATH_CUSTODIA); if (pathCustodia == null) { // System.out.println( // "El sistema de custodia no esta utilizando ningun sistema de ficheros" // ) // throw new ExceptionInInitializerError("Parametro '" + // PARAM_PATH_CUSTODIA + // "' requerido para inicializar el sistema de custodia de documentacin." // ); } else { // aadimos este parametro a las propiedades para que el manejadore // de repositorio en el que se basa la custodia // encuentre el parametros properties.put("fileSystem.default.PATH_BASE", pathCustodia); } ManagerFileRepositoryFactory.init(properties); ManagerFileRepository manager = ManagerFileRepositoryFactory.getDefaultManager(); singleton = new Custodia(manager); } /** * Almacena un xml signature. * * @param id * @param signature * @throws ExcepcionErrorInterno */ public String custodiar(String id, Document xmlDocument, TypeFormatSign typeSign) throws ExcepcionErrorInterno { try { // validamos el XMLSignature antes de guardarlo para prevenir // posibles problemas if (!XmlSignUtil.getInstance().checkSignatureFrom(xmlDocument, false)) { log.error("El XML a custodiar no es valido:"); XMLUtils.outputDOM(xmlDocument, System.out); throw new ExcepcionErrorInterno(CodigoError.ERROR_XMLSIGN_FORMAT); } // Le asignamos un identificador definitivo. // En funcin del tipo de documento le asginamos un tipo // identificador de tipo de custoria (resevado para el futuro) int tipo = typeSign.getCode(); // A1HH-EZH9T5E1-1889-3802-8854 String newId = tipo + id; // Generamos dgito de control newId = CheckDigit.generateCheckDigit(newId) + newId; // generamos los - StringBuilder b = new StringBuilder(); for (int i = 0; i < newId.length(); i++) { char caracter = newId.charAt(i); b.append(caracter); if ((i + 1) % 4 == 0 && i < (newId.length() - 1)) { b.append("-"); } } // Transformamos el identificador en el path del documento. newId = b.toString(); String newUri = decode(newId); OutputStream out; try { out = manager.openOutputStreamToUri(newUri); } catch (ExcepcionServicio e) { throw new org.viafirma.excepciones.ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } XMLUtils.outputDOM(xmlDocument, out); out.close(); // retornamos el identificador asignado al custoridar return newId; } catch (IOException e) { // problemas al custodiar el documento throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } catch (ExcepcionErrorInterno e) { throw e; } catch (Exception e) { // problemas al custodiar el documento throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } } /** * Recupera y valida un xml signature asociado al cdigo de firma indicado. * * @param id * @param signature * @throws ExcepcionErrorInterno * * */ public Document recuperar(String id) throws ExcepcionErrorInterno { InputStream input = null; try { // Le asignamos un identificador definitivo. String newUri = decode(id); try { input = manager.readDocument(newUri); } catch (ExcepcionServicio e) { throw new org.viafirma.excepciones.ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } return streamToDoc(input); } catch (ExcepcionErrorInterno e) { log.warn("Problemas al recuperar el XMLSignature asociado al id: '" + id + "'"); throw e; } catch (Exception e) { // problemas al custodiar el documento throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } finally { if (input != null) { try { input.close(); } catch (IOException e) { log.warn("No se puede cerrar el InputStream para el XmlSignature: " + id); } } } } /** * Recupera el documento asociado y el documento xml. * @throws ExcepcionDatosNoEncontrados * @throws ExcepcionServicio */ public Object[] recuperarMoreInfo(String id) throws ExcepcionErrorInterno { try { DocumentVO documentVO = manager.loadDocument(decode(id), null); return new Object[] { documentVO, streamToDoc(documentVO.dataStream) }; } catch (ExcepcionServicio e) { throw new org.viafirma.excepciones.ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } catch (ExcepcionDatosNoEncontrados e) { throw new org.viafirma.excepciones.ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } } /** * Transforma identificadores de documentos a uris dentro del sistema de * ficheros Todas las uris en el sistema de ficheros(abstracto) son del tipo * /directorio/nombreFichero * * //A1HH-EZH9T5E1-1889-3802-8854 * * @param newUri * @return * @throws ExcepcionErrorInterno */ private String decode(String newId) throws ExcepcionErrorInterno { try { String id = newId.replaceAll("-", ""); // Comprobamos el cdigo de chequeo if (!CheckDigit.validateCheckDigit(id)) { throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA_CHECK_DIGIT, "El digito de control no es correcto para el identificador: " + newId); } // obtengo el tipo de documento TypeFormatSign typeFormatSign = XmlSignUtil.getTypeFormatSign(newId); // obtengo el timestamp long timeStamp = new Long(id.substring(11, id.length())); Calendar g = new GregorianCalendar(); g.setTimeInMillis(timeStamp); int anyo = g.get(Calendar.YEAR); int mes = g.get(Calendar.MONTH) + 1; return "/" + typeFormatSign.getCode() + "/" + anyo + "/" + mes + "/" + newId + ".xml"; } catch (java.lang.StringIndexOutOfBoundsException e) { throw new ExcepcionErrorInterno(CodigoError.ERROR_PARAM, "El identificador indicado no es vlido. newId= " + newId); } } private Log log = LogFactory.getLog(Custodia.class); /** * * Parsea un stream pasandolo a xml * */ private Document streamToDoc(InputStream stream) throws ExcepcionErrorInterno { XmlSignUtil xmlSignParser = XmlSignUtil.getInstance(); try { // obtengo el xml signature asociado al cdigo de firma indicado Document documento = xmlSignParser.parseDocument(new InputStreamReader(stream)); // validamos el XMLSignature if (!XmlSignUtil.getInstance().checkSignatureFrom(documento, false)) { throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA_NO_VALID); } // retornamos el identificador asignado al custoridar return documento; } catch (ExcepcionErrorInterno e) { log.warn("Problemas al recuperar el XMLSignature"); throw e; } catch (Exception e) { // problemas al custodiar el documento throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA, e); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { log.warn("No se puede cerrar el InputStream para el XmlSignature"); } } } } }