/** * */ package com.fp.alfresco.client; import java.io.InputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TimeZone; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import net.sf.json.JSONSerializer; import org.apache.commons.lang.StringEscapeUtils; import org.apache.http.Consts; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import com.fp.alfresco.enums.EnumDataType; import com.fp.alfresco.enums.EnumRequestType; import com.fp.alfresco.exception.ExceptionWebscript; import com.fp.alfresco.util.ApiProperties; import com.fp.alfresco.util.ApiRequest; import com.fp.alfresco.util.UriUtils; /** * * Clase que proporciona métodos comunes para interactuar con el repositorio de Alfresco * @author bpt * */ public class AlfrescoApi { /** * Objeto de tipo ApiRequest que realiza las consultas a alfresco */ private ApiRequest apiRequest; /** * Variable que contiene el namespace base del API de alfresco */ private String baseQuery; /** * Variable que contiene el nombre del sitio que se consumira en la llamada a Alfresco */ private String site; private static final String MIME_TEXT = ApiProperties.getProperty("api.common.mime.type"); private static final String PREFIX_METADATA = ApiProperties.getProperty("api.name.prefix.metadata"); /** * Constructor */ public AlfrescoApi(String site){ this.apiRequest = new ApiRequest(); this.site = site; this.baseQuery = ApiProperties.getProperty("api.site.defaultquery", site); } /** * Método principal para la busqueda de documentos * @param query * @param ticket * @return * @throws Exception */ public List findDocuments(String query) throws Exception{ String uri = ApiProperties.getProperty("api.uri.search.general")+UriUtils.formatearParametrosUrl("query=" + this.baseQuery+ " AND " + query); String response = this.apiRequest.authRequest(EnumRequestType.GET, uri).toString(); return this.transformeResponse(response); } /** * Retorna una lista de {@link DocumentoAlfresco} por xpath * @param xPathLocation la ruta xpath de una carpeta * @return * @throws Exception */ private List findByXPathLocation(String xPathLocation) throws Exception{ String uri = ApiProperties.getProperty("api.uri.search.general")+UriUtils.formatearParametrosUrl("query=PATH:\"" + xPathLocation); String response = this.apiRequest.authRequest(EnumRequestType.GET, uri).toString(); return this.transformeResponse(response); } /** * Método que busca por id del documento * @param documentId * @return * @throws Exception */ public DocumentoAlfresco findById(String documentId) throws Exception { String query = "ID:\""+ documentId +"\""; List l = this.findDocuments(query); if(!l.isEmpty()){ return l.get(0); } return null; } /** * Método que busca un documento por contenido * @param documentContent * @return * @throws Exception */ public List findByContent(String documentContent) throws Exception { String query = "TEXT:\""+ documentContent+"\""; return this.findDocuments(query); } /** * Método que busca un documento por atributo * @param documentContent * @return * @throws Exception */ public List findByAttribute(String attributeName, String value) throws Exception { attributeName = attributeName.replace(":", "\\:"); String query = "@"+attributeName+":\""+ value+"\""; return this.findDocuments(query); } /** * Método que busca un documento por tipo * @param type * @return * @throws Exception */ public List findByType(String type) throws Exception { String query = "TYPE:\""+type+"\""; return this.findDocuments(query); } /** * Devuelve una lista de {@link DocumentoAlfresco} por xpath de la carpeta * @param xPathLocationFolder xpath de la carpeta a buscar * @return * @throws Exception */ public List findListByXPathLocation(String xPathLocationFolder) throws Exception{ if((xPathLocationFolder==null) || xPathLocationFolder.isEmpty()){ throw new ExceptionWebscript("Ruta de la carpeta requerido"); } xPathLocationFolder+="/*\" AND TYPE:\"cm:content\""; return this.findByXPathLocation(xPathLocationFolder); } /** * Retorna un {@link DocumentoAlfresco} por dirección xpath * @param xPathLocationDocument dirección xpath del documento * @return * @throws Exception */ public DocumentoAlfresco findOneByXPathLocation(String xPathLocationDocument) throws Exception{ if((xPathLocationDocument==null) || xPathLocationDocument.isEmpty()){ throw new ExceptionWebscript("Ruta del documento requerido"); } xPathLocationDocument+="\""; List l = this.findByXPathLocation(xPathLocationDocument); if(!l.isEmpty()){ return l.get(0); } return null; } /** * Recibe la respuesta en JSON y retorna una lista de tipo List * @param response * */ private List transformeResponse(String response) { List l = new ArrayList(); JSONObject json = (JSONObject) JSONSerializer.toJSON(response); Integer resultados = json.getInt("resultados"); if(resultados>0){ JSONArray documents = json.getJSONArray("documentos"); for (Object object : documents) { JSONObject jo = (JSONObject) object; DocumentoAlfresco d = this.getSingleDocumentResponse(jo); l.add(d); } } return l; } /** * Retorna un {@link DocumentoAlfresco} en base aun {@link JSONObject} enviado * @param jo Objeto json que formará el {@link DocumentoAlfresco} * @return */ @SuppressWarnings("unchecked") private DocumentoAlfresco getSingleDocumentResponse(JSONObject jo) { Map mprops = jo.getJSONObject("propiedades"); DocumentoAlfresco d = new DocumentoAlfresco(jo.getString("nombre"), ((Map)mprops.get("cm:modifier")).get("userName").toString()); d.setId(jo.getString("referencia")); d.setNombre(jo.getString("nombre")); d.setModificadoPor(((Map)mprops.get("cm:modifier")).get("userName").toString()); d.setAccesoDescarga(jo.getString("accesoDescarga")); d.setxPathLocationPadre(jo.getString("xPathLocationPadre")); d.setxPathLocation(jo.getString("xPathLocation")); d.setTipo(jo.getString("tipo")); d.setPropiedades(new HashMap()); this.fillPropertiesSearch(d.getPropiedades(), jo.getJSONObject("propiedades")); return d; } /** * Método recursivo que llena las propiedades de un documento en un mapa * @param mprop Mapa para llenar las propiedades de un documento * @param jobject Propiedad de un documento */ @SuppressWarnings("unchecked") private void fillPropertiesSearch(Map mprop, JSONObject jobject) { Set ks = jobject.keySet(); for (String key : ks) { Object item = jobject.get(key); if(item instanceof JSONObject){ Map subProp = new HashMap(); mprop.put(key, subProp); this.fillPropertiesSearch(subProp, (JSONObject)item); }else{ mprop.put(key, item.toString()); } } } /** * Método que arma los parámetros en base al documento * @param documento * @return * @throws Exception */ private String armarParametrosPropiedades(DocumentoAlfresco documento) throws Exception { TimeZone tz = TimeZone.getTimeZone("GMT-05:00"); DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); iso8601.setTimeZone(tz); StringBuffer cadena = new StringBuffer("{"); Map> map = documento.getPropiedadesToSet(); if(map==null){ cadena.append("}"); return cadena.toString(); } boolean existAttrs = false; Set keys = map.keySet(); for (String key : keys) { if(key.startsWith(PREFIX_METADATA)){ existAttrs = true; Map prop = map.get(key); String propValue = null; Object type = prop.get("type"); Object value = prop.get("value"); if(!(type instanceof EnumDataType)){ throw new ExceptionWebscript("El campo '"+key+"' debe tener el atributo 'type' de tipo [EnumDataType]"); } if(value!=null){ if(type==EnumDataType.STRING){ if(!(value instanceof String)) { throw new ExceptionWebscript("El campo '"+key+"' debe tener el atributo 'value' de tipo [String]"); } propValue = StringEscapeUtils.escapeJavaScript(value.toString()); }else if(type==EnumDataType.DATE){ if(!(value instanceof Date)) { throw new ExceptionWebscript("El campo '"+key+"' debe tener el atributo 'value' de tipo [Date]"); } propValue = iso8601.format(value); propValue = propValue.substring(0,22)+":00"; }else if(type==EnumDataType.NUMBER){ if(!(value instanceof Number)) { throw new ExceptionWebscript("El campo '"+key+"' debe tener el atributo 'value' de tipo [Number]"); } propValue = value.toString(); } } if((propValue!=null) && !propValue.isEmpty()) { cadena.append("\""+key+"\":") .append("{") .append("\"value\":").append("\""+propValue+"\"") .append(",") .append("\"type\":").append("\""+((EnumDataType)type).getValue()+"\"") .append("},"); } } } if(existAttrs) { cadena.deleteCharAt(cadena.length()-1); } cadena.append("}"); return cadena.toString(); } /** * Se obtiene un documento en base a su id * @param documentId id del documento * @return * @throws Exception */ public InputStream downloadDocumentById(String documentId) throws Exception{ String uriDownload = ApiProperties.getProperty("api.uri.download.id"); uriDownload+=documentId.replace("://", "/"); return (InputStream) this.apiRequest.authRequest(EnumRequestType.GET, uriDownload, true, true); } /** * Se obtiene un documento en base a su xpath * @param xPathLocation ruta de la dirección en donde se encuentra el documento * @param includeSite bandera si se debe especificar el sitio * @return * @throws Exception */ public InputStream downloadDocumentByXPathLocation(String xPathLocation, boolean includeSite) throws Exception{ if(includeSite){ xPathLocation = xPathLocation.replace("{0}", this.site); } DocumentoAlfresco docAlfresco = findOneByXPathLocation(xPathLocation); if(docAlfresco == null){ return null; } // xPathLocation = xPathLocation.replace("/app:", "").replace("/st:", "/").replace("/cm:", "/"); // String uriDownload = ApiProperties.getProperty("api.uri.download.path", xPathLocation); // (InputStream) this.apiRequest.authRequest(EnumRequestType.GET, uriDownload, true, true) return downloadDocumentById(docAlfresco.getId()); } public InputStream downloadDocumentByXPathLocation(String xPathLocation) throws Exception{ return this.downloadDocumentByXPathLocation(xPathLocation, true); } /** * Método que carga un documento en una ruta especificada * @param location * @param document * @param isUpdate * @return * @throws Exception */ private DocumentoAlfresco uploadDocument(String location, DocumentoAlfresco document, boolean isUpdate) throws Exception { if(document.getFile()==null){ throw new Exception("Debe fijar un archivo"); } String ubicacion = null; if(isUpdate){ ubicacion = location; }else{ ubicacion = ApiProperties.getProperty("api.doclocation.base", this.site)+"/"+ location; } String uri = ApiProperties.getProperty("api.uri.create.general")+ UriUtils.formatearParametrosUrl( "tipo=" +document.getTipo() +"&ubicacion=" +ubicacion +"&modificadoPor="+document.getModificadoPor() +"&propiedades="+this.armarParametrosPropiedades(document) ); FileBody bin = new FileBody(document.getFile()); HttpEntity entityHttp = null; if(isUpdate){ entityHttp = MultipartEntityBuilder.create() .addPart("archivo", bin) .addPart("filename", new StringBody(document.getNombre(), ContentType.create(MIME_TEXT, Consts.ISO_8859_1))) .addPart("xPathUpdateDocument", new StringBody(document.getxPathLocation(), ContentType.create(MIME_TEXT, Consts.ISO_8859_1))) .build(); }else{ entityHttp = MultipartEntityBuilder.create() .addPart("archivo", bin) .addPart("filename", new StringBody(document.getNombre(), ContentType.create(MIME_TEXT, Consts.ISO_8859_1))) .build(); } try { String response = this.apiRequest.authRequest(EnumRequestType.POST, uri, entityHttp).toString(); JSONObject jo = (JSONObject) JSONSerializer.toJSON(response); return this.getSingleDocumentResponse(jo); } catch (HttpException e) { throw new ExceptionWebscript("Error al conectar con el servidor de alfresco", e); } } /** * Método que carga un nuevo documento en la ruta ingresada * @param partialxPathLocation ruta xpath en donde se almacenará el documento * @param document * @return * @throws Exception */ public DocumentoAlfresco uploadNewDocument(String partialxPathLocation, DocumentoAlfresco document) throws Exception { return this.uploadDocument(partialxPathLocation, document, false); } /** * Para actualizar el documento primero lo consulto * @param document * @return * @throws Exception */ public DocumentoAlfresco uploadUpdateDocument(DocumentoAlfresco document) throws Exception { return this.uploadDocument(document.getxPathLocation(), document, true); } /** * Elimina un documento dado un nodeRef. * @param nodeRef Identificador único del documento o carpeta que se desea eliminar * @return Boolean indicando si se realizó el proceso de eliminación de forma correcta. * @throws Exception Se ejecuta una excepción cuando no se encuentra el documento en el repositorio Alfresco */ public boolean deleteDocument(String nodeRef) throws Exception { StringBuilder urlDescarga = new StringBuilder(ApiProperties.getProperty("api.uri.delete.general")); urlDescarga.append(nodeRef.replace("://", "/")); Object response = this.apiRequest.authRequest(EnumRequestType.DELETE, urlDescarga.toString(), false, true); JSONObject jo = (JSONObject) JSONSerializer.toJSON(response); return Boolean.parseBoolean(jo.get("overallSuccess").toString()); } public String getSite() { return site; } }