Java tutorial
/* * Digital Assets Management * ========================= * * Copyright 2009 Fundacin Iavante * * Authors: * Francisco Jos Moreno Llorca <packo@assamita.net> * Francisco Jess Gonzlez Mata <chuspb@gmail.com> * Juan Antonio Guzmn Hidalgo <juan@guzmanhidalgo.com> * Daniel de la Cuesta Navarrete <cues7a@gmail.com> * Manuel Jos Cobo Fernndez <ranrrias@gmail.com> * * Licensed under the EUPL, Version 1.1 or as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * */ package org.iavante.uploader.ifaces.impl; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.text.Normalizer; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthPolicy; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.commons.json.JSONException; import org.apache.sling.commons.json.io.JSONWriter; import org.apache.sling.commons.mime.MimeTypeService; import org.iavante.uploader.ifaces.AuthToolsService; import org.iavante.uploader.ifaces.IUploadService; import org.iavante.uploader.ifaces.PortalSetup; import org.iavante.uploader.ifaces.impl.indexer.ContentParser; import org.iavante.uploader.ifaces.impl.indexer.TikaDocumentParser; import org.iavante.uploader.services.Constants; import org.iavante.uploader.services.IFileManagement; import org.iavante.uploader.services.ServiceException; import org.iavante.uploader.services.impl.FileManagementImpl; import org.iavante.uploader.util.Base64Coder; import org.iavante.uploader.util.SystemProcess; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @see org.iavante.uploader.ifaces.IUploadService * @scr.component immediate="true" * @scr.property name="service.description" value="IAVANTE - Upload Service" * @scr.property name="service.vendor" value="IAVANTE Foundation" * @scr.service interface="org.iavante.uploader.ifaces.IUploadService" */ public class UploadServiceImpl implements IUploadService, Serializable { private static final long serialVersionUID = 1L; /** Default Logger. */ private final Logger out = LoggerFactory.getLogger(getClass()); /** @scr.reference */ private MimeTypeService mimeService; /** @scr.reference */ private PortalSetup portalSetup; /** @scr.reference */ private AuthToolsService authTools; /** Name of the param that contains the directory to save the files. */ public static final String PROP_DIRUPLOADFILES = "dirUploadFiles"; /** Name of the param that contains the binary. */ public static final String PROP_PARAMDATA = "paramData"; /** Name of the param that contains the notification url to gad. */ public static final String PROP_PARAMNOTIFICATION = "paramNotification"; /** Name of the param that contains the filename. */ public static final String PROP_PARAMFILENAME = "paramFilename"; /** Name of the param that contains the Url to GAD with credentials. */ public static final String PROP_BASICURL = "basicUrl"; /** Name of the param that contains the max size for the binary. */ public static final String PROP_MAXFILESIZE = "maxFileSize"; /** Name of the param that contains the path to ffmpeg. */ public static final String PROP_PATHFFMPEG = "pathFfmpeg"; /** Name of the param that contains the path to file. */ public static final String PROP_PATHFILE = "pathFile"; /** Name of the param that contains the uploader url. */ public static final String PROP_HTTPBASEURL = "httpBaseUrl"; /** Name of the param that contains the name of the sling user. */ public static final String PROP_SLINGUSER = "slingUser"; /** Name of the param that contains the name of the sling password. */ public static final String PROP_SLINGPASS = "slingPass"; /** Location where files are saved. */ private String dirUploadFiles; /** Notification parameter name, ie: 'content' */ private String paramNotification; /** File parameter name, ie: 'filename' */ private String paramFilename; /** Data parameter name, ie: 'data' */ private String paramData; /** Parameters to send to GAD */ private Map props = new HashMap(); /** Filename */ private String nombre; /** Source's url in GAD to update */ private String location; /** File path. */ private String file; /** Mimetype. */ private String mime; /** File encoding. */ private String encoding; /** File language. */ private String lang; /** File duration. */ private String length; /** File size. */ private String size; /** Filename of the content extracted through parser. */ private String bodyFilename; /** Relationship between searched values and post values. */ private Map relation = new HashMap(); /** String to append partial return calls. */ private String results = ""; /** True if file metadata have been extracted. */ private boolean extracted = false; /** To synchronize contentparser use. */ private Boolean contentParserAccess = true; /** Content parser. */ private ContentParser contentParser = new TikaDocumentParser(); /** Http client. */ private HttpClient client; /** Admin credentials. */ private Credentials userCreds; /** Default credentials. */ private Credentials defaultCreds; /** Authentication preferences. */ private List authPrefs = new ArrayList(2); /** User and passw */ private String userPass; // ---------------- Constructor -------------------- public UploadServiceImpl() { if (out.isInfoEnabled()) out.info("UploadFileCmd, ini"); props.put("nombre", ""); props.put("location", ""); props.put("file", ""); props.put("mime", ""); props.put("encoding", ""); props.put("lang", ""); props.put("duration", ""); props.put("size", ""); props.put("bitrate", ""); props.put("video", ""); props.put("audio", ""); props.put("type", ""); // program param - post param relation.put("nombre", "file"); relation.put("location", "location"); relation.put("file", "file"); relation.put("mime", "mimetype"); relation.put("encoding", "encoding"); relation.put("lang", "lang"); relation.put("duration", "lengths"); relation.put("size", "size"); relation.put("bitrate", "bitrate"); relation.put("video", "track_1_encoding"); relation.put("audio", "track_2_encoding"); relation.put("type", "type"); setup(); if (out.isInfoEnabled()) out.info("UploadFileCmd, end"); } protected void activate(ComponentContext context) { Map<String, String> properties = portalSetup.get_config_properties("/uploader"); if (out.isInfoEnabled()) out.info("activate, getting parameters cts ..."); Constants.DIRUPLOADFILES = properties.get(PROP_DIRUPLOADFILES); Constants.PARAMDATA = properties.get(PROP_PARAMDATA); Constants.PARAMNOTIFICATION = properties.get(PROP_PARAMNOTIFICATION); Constants.PARAMFILENAME = properties.get(PROP_PARAMFILENAME); Constants.BASICURL = properties.get(PROP_BASICURL); Constants.PATHFFMPEG = properties.get(PROP_PATHFFMPEG); Constants.PATHFILE = properties.get(PROP_PATHFILE); Constants.HTTPBASEURL = properties.get(PROP_HTTPBASEURL); Constants.SLINGUSER = properties.get(PROP_SLINGUSER); Constants.SLINGPASS = properties.get(PROP_SLINGPASS); if (out.isInfoEnabled()) out.info("activate, getting parameters cts ENDED"); } // ----------- UploadService ----------------------------------- public Map getProps() { return props; } public boolean getExtracted() { return extracted; } /** * @see org.iavante.uploader.ifaces.IUploadService */ public String uploadFile(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (out.isInfoEnabled()) out.info("execute, ini"); results = ""; response.setContentType("text/html;charset=UTF-8"); PrintWriter outResponse = response.getWriter(); // Check if user:password in the request has permission to modify the gad // source. boolean authenticated = checkAuthentication(request); if (authenticated) { int code = 0; try { // Read parameters from the request, save the file and extract metadata // from it. Metadata are saved in 'props'. code = saveAndExtract(request, response); if (out.isInfoEnabled()) out.info("execute, props: " + props); if (code == 200) { try { String res = ""; int hits = 0; while (hits < 3) { try { res = restConnection2(request, Constants.URLPOST, props); hits = 50; // any number > 3 to break the loop } catch (Exception e) { // try connection 2 more times hits++; if (out.isInfoEnabled()) out.info("execute, hit connection " + hits + " failed"); res += "Server Error (500) " + e.getMessage(); } } if (hits == 3) { // delete file IFileManagement gf = new FileManagementImpl(); gf.deleteFile(Constants.DIRUPLOADFILES + "/" + props.get("nombre")); if (out.isInfoEnabled()) out.info( "execute, deleted " + Constants.DIRUPLOADFILES + "/" + props.get("nombre")); results = ""; // reset 'results' } if (hits == 50) { // everything was OK } results += res; } catch (ServiceException e) { // Error deleting file e.printStackTrace(); results = "Error deleting file"; } } else { results += code; } } catch (FileUploadException e) { // 'results' with error info e.printStackTrace(); results = "Server Error (500) " + e.getMessage(); } catch (Exception e) { e.printStackTrace(); results = "Server Error (500) " + e.getMessage(); } } else { response.setStatus(401); results = "Unauthorized (401) "; } outResponse.println(results); outResponse.flush(); outResponse.close(); if (out.isInfoEnabled()) out.info("execute, end"); return null; } /* * @see org.iavante.uploader.ifaces.IUploadService */ public String removeFile(String name) throws Exception { if (out.isInfoEnabled()) out.info("removeFile, deleting " + name); IFileManagement gf = new FileManagementImpl(); gf.deleteFile(name); if (out.isInfoEnabled()) out.info("removeFile, deleted " + name); return "ok"; } // --------------- Internal ---------------------- /** * Save to disk and extract metadata. * * @param request * @param response * @return 200 (OK), 404 (Not saved) * @throws Exception */ private int saveAndExtract(HttpServletRequest request, HttpServletResponse response) throws Exception { if (out.isInfoEnabled()) out.info("saveAndExtract, ini"); int code = 0; Enumeration en2 = request.getParameterNames(); while (en2.hasMoreElements()) { String cad = (String) en2.nextElement(); if (out.isInfoEnabled()) out.info("saveAndExtract, Parameter: " + cad); } dirUploadFiles = Constants.DIRUPLOADFILES; paramData = Constants.PARAMDATA; paramNotification = Constants.PARAMNOTIFICATION; paramFilename = Constants.PARAMFILENAME; if (ServletFileUpload.isMultipartContent(request)) { if (out.isInfoEnabled()) out.info("saveAndExtract, isMultipartContent"); if (out.isInfoEnabled()) out.info("saveAndExtract, Constants.PARAMDATA=" + Constants.PARAMDATA); // Notification url String urlString = Constants.BASICURL; String param = request.getParameter("coreurl"); if (param != null) { urlString = param; } param = request.getParameter(Constants.PARAMNOTIFICATION); if (param != null) { urlString += param; } Constants.URLPOST = urlString; if (out.isInfoEnabled()) out.info("saveAndExtract, Constants.URLPOST=" + Constants.URLPOST); // Getting file bytes. SlingHttpServletRequest req = (SlingHttpServletRequest) request; byte[] data = req.getRequestParameter(Constants.PARAMDATA).get(); if (out.isInfoEnabled()) out.info("saveAndExtract, data.length=" + data.length); if (data.length > 0) { // Getting file Date today = new Date(); if (request.getParameter(Constants.PARAMFILENAME) == null) { String[] ne = request.getParameter(Constants.PARAMDATA).split("\\."); props.put("nombre", ne[ne.length - 2].replaceAll("[ ?]+", "_") + "_" + today.getTime() + "." + ne[ne.length - 1]); } else { String[] ne = request.getParameter(Constants.PARAMFILENAME).split("\\."); props.put("nombre", ne[ne.length - 2].replaceAll("[ ?]+", "_") + "_" + today.getTime() + "." + ne[ne.length - 1]); } props.put("nombre", Normalizer.normalize((String) props.get("nombre"), Normalizer.Form.NFC)); props.put("size", String.valueOf(data.length)); // Save the file File archivo = new File(dirUploadFiles, (String) props.get("nombre")); FileOutputStream fout; fout = new FileOutputStream(archivo); // fout.write(request.getParameter(Constants.PARAMDATA).getBytes( // "ISO-8859-1")); fout.write(data); if (archivo.exists()) { results += "SAVED " + archivo.getAbsolutePath() + "</p>"; if (out.isInfoEnabled()) out.info("saveAndExtract, SAVED " + archivo.getAbsolutePath()); // Extract mimetype List cadenas0 = new ArrayList(); cadenas0.add(props.get("nombre")); SystemProcess p0 = new SystemProcess(); String orden0 = Constants.PATHFILE + "/file -i " + dirUploadFiles + "/" + props.get("nombre"); // command to execute Map aux0 = p0.start(orden0, cadenas0); for (int i = 0; i < cadenas0.size(); i++) { // only look for the first match of the searched string -> // (String) ((List) aux.get(cadenas.get(i))).get(0) if (((List) aux0.get(cadenas0.get(i))).size() > 0) { String linea = (String) ((List) aux0.get(cadenas0.get(i))).get(0); String regex = cadenas0.get(i) + "(\\:)(\\s+)[\\S]+"; String res = ""; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(linea); if (m.find()) { res = m.group(); String[] aux2 = res.split("[\\s]+"); aux2[1] = aux2[1].replaceAll(";$", ""); props.put("mime", aux2[1]); } if (out.isInfoEnabled()) out.info(res); } } // Setting 'type' param String mime = (String) props.get("mime"); String[] mimeSplit = mime.split("/"); if ("application/ogg".compareTo(mime) == 0 || "application/octet-stream".compareTo(mime) == 0) { props.put("type", "video"); } else { props.put("type", mimeSplit[0]); } if (out.isInfoEnabled()) out.info("extracted mimetype, extracting metadata..."); Document doc = null; // parse the document synchronized (contentParserAccess) { doc = contentParser.getDocument(archivo, (String) props.get("mime")); } if (out.isInfoEnabled()) out.info("lucene doc.body -> " + doc.getField("body").stringValue()); List<String> tags = new ArrayList<String>(); tags.add("duration"); tags.add("bitrate"); tags.add("video"); tags.add("audio"); for (String tag : tags) { Field field = doc.getField(tag); if (field != null) { props.put(tag.toLowerCase(), field.stringValue()); } } String[] ne = ((String) props.get("nombre")).split("\\."); bodyFilename = dirUploadFiles + "/" + ne[0] + ".txt"; FileWriter fw = new FileWriter(bodyFilename); doc2txt(doc, fw); fw.flush(); fw.close(); extracted = true; code = 200; } else { // if save failed results += "ERROR SAVING FILE. NOT EXISTS " + archivo.getAbsolutePath() + "</p>"; if (out.isInfoEnabled()) out.info("saveAndExtract, ERROR SAVING FILE. NOT EXISTS " + archivo.getAbsolutePath()); code = 404; } results += "Props: " + props + "<br>"; } else { results += "Size: 0 <br>"; } } if (out.isInfoEnabled()) out.info("saveAndExtract, end"); return code; } /** * Write from a lucene Document to a writer */ private void doc2json(Document doc, FileWriter writer) { try { JSONWriter w = new JSONWriter(writer); w.object(); for (Field field : (List<Field>) doc.getFields()) { w.key(field.name()); w.value(field.stringValue()); } w.endObject(); } catch (JSONException e) { out.error(e.toString()); } } /** * Write from a lucene Document to a writer */ private void doc2txt(Document doc, FileWriter writer) { try { Field field = doc.getField("body"); if (field != null) { writer.write(field.stringValue()); } else { writer.write("No se ha podido extraer contenido."); } } catch (IOException e) { e.printStackTrace(); } } /** * POST to a specified url. * * @param request * @param urlNotification * @param params * @return * @throws Exception */ private String restConnection2(HttpServletRequest request, String urlNotification, Map params) throws Exception { if (out.isInfoEnabled()) out.info("restConnection, ini"); String rt = request.getParameter("rt"); if (rt == null) { rt = "gad/source"; } if (out.isInfoEnabled()) out.info("restConnection, rt -> " + rt); PostMethod post = new PostMethod(urlNotification); List<Part> listPart = new ArrayList<Part>(); listPart.add(new StringPart("sling:resourceType", rt)); listPart.add(new StringPart("jcr:lastModified", "")); listPart.add(new StringPart("jcr:lastModifiedBy", "")); listPart.add(new FilePart("body.txt", new File(bodyFilename))); // parts[3] = new StringPart("filename", f.getName()), new FilePart("data", // f); Set set = params.entrySet(); Iterator it = set.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); if ("".compareTo((String) entry.getValue()) != 0) { String campo = (String) relation.get("" + entry.getKey()); listPart.add(new StringPart(campo, "" + entry.getValue())); } } int cont = 0; if ("".compareTo((String) params.get("video")) != 0) { listPart.add(new StringPart("track_1_type", "video")); cont++; } if ("".compareTo((String) params.get("audio")) != 0) { listPart.add(new StringPart("track_2_type", "audio")); cont++; } if (cont > 0) { listPart.add(new StringPart("tracks_number", "" + cont)); } Part[] parts = new Part[listPart.size()]; for (int i = 0; i < listPart.size(); i++) { parts[i] = listPart.get(i); } post.setRequestEntity((RequestEntity) new MultipartRequestEntity(parts, post.getParams())); post.setDoAuthentication(true); SlingHttpServletRequest req = (SlingHttpServletRequest) request; String credentials = authTools.extractUserPass(req); int colIdx = credentials.indexOf(':'); if (colIdx < 0) { userCreds = new UsernamePasswordCredentials(credentials); } else { userCreds = new UsernamePasswordCredentials(credentials.substring(0, colIdx), credentials.substring(colIdx + 1)); } client.getParams().setAuthenticationPreemptive(true); client.getState().setCredentials(AuthScope.ANY, userCreds); client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); int responseCode = -1; String responseMessage = ""; try { client.executeMethod(post); responseCode = post.getStatusCode(); responseMessage = post.getResponseBodyAsString(); } catch (HttpException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally { post.releaseConnection(); } if (responseCode != 201 && responseCode != 200) { throw new IOException("sendContentToRevision, code=" + responseCode); } if (out.isInfoEnabled()) out.info("restConnection, end"); return responseMessage + " (" + responseCode + ")"; } /** * Check if the source exists. GET to url specified by 'content' parameter * reusing request authorization. * * @param request * @return */ private boolean checkAuthentication(HttpServletRequest request) { if (out.isInfoEnabled()) out.info("checkAuthentication, ini"); if (out.isInfoEnabled()) out.info("checkAuthentication, userInfo: " + request.getHeader("Authorization")); int timeout = 1000; boolean authenticated = true; int errorCode = 0; String message = ""; // Build check url String urlString = Constants.BASICURL; String param = request.getParameter("coreurl"); if (param != null) { urlString = param; } param = request.getParameter(Constants.PARAMNOTIFICATION); if (param != null) { urlString += param + ".html"; } out.info("----->urlnotification=" + urlString); if (Constants.BASICURL.compareTo(urlString) != 0) { try { // Create the URL URL sling = new URL(urlString); // Create and configure the connection HttpURLConnection slingConnection = (HttpURLConnection) sling.openConnection(); slingConnection.setConnectTimeout(timeout); slingConnection.setDoOutput(true); // Authorization request header Base64Coder encoder = new Base64Coder(); slingConnection.setRequestProperty("Authorization", request.getHeader("Authorization")); if (out.isInfoEnabled()) out.info("checkAuthentication, userInfo, urlString: " + urlString); // Connect slingConnection.connect(); // Check response code if (out.isInfoEnabled()) out.info("checkAuthentication, connection.getResponseCode() = " + slingConnection.getResponseCode()); if (slingConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { authenticated = true; } else { authenticated = false; errorCode = slingConnection.getResponseCode(); message = slingConnection.getResponseMessage(); } // Close connection slingConnection.disconnect(); } catch (MalformedURLException e) { // new URL() failed e.printStackTrace(); } catch (IOException e) { // openConnection() failed e.printStackTrace(); } } else { authenticated = false; errorCode = -1; // no authentication error, just don't correctly loaded // BASICURL } if (out.isInfoEnabled()) out.info("checkAuthentication, authenticated: " + authenticated); if (out.isInfoEnabled()) out.info("checkAuthentication, end"); return authenticated; } /** * Initial http client configuration. */ private void setup() { client = new HttpClient(); defaultCreds = new UsernamePasswordCredentials("admin", "admin"); authPrefs = new ArrayList(2); authPrefs.add(AuthPolicy.DIGEST); authPrefs.add(AuthPolicy.BASIC); client.getParams().setAuthenticationPreemptive(true); client.getState().setCredentials(AuthScope.ANY, defaultCreds); client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs); } }