/* * © Copyright IBM Corp. 2010 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.ibm.xsp.extlib.sbt.files.type; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.ibm.commons.util.StringUtil; import com.ibm.commons.util.io.StreamUtil; import com.ibm.designer.runtime.util.MIME; import com.ibm.sbt.services.client.ClientService; import com.ibm.sbt.services.client.ClientService.HandlerInputStream; import com.ibm.sbt.services.client.ClientService.HandlerJson; import com.ibm.sbt.services.client.ClientServicesException; import com.ibm.sbt.services.endpoints.AbstractEndpoint; import com.ibm.sbt.services.endpoints.DropBoxOAuthEndpoint; import com.ibm.sbt.services.endpoints.Endpoint; import com.ibm.sbt.services.endpoints.EndpointFactory; import com.ibm.sbt.util.DataNavigator; import com.ibm.sbt.util.JsonNavigator; import com.ibm.xsp.FacesExceptionEx; import com.ibm.xsp.extlib.sbt.files.FileEntry; import com.ibm.xsp.extlib.sbt.files.FileServiceData; import com.ibm.xsp.extlib.sbt.files.FileServiceData.FileServiceAccessor; import com.ibm.xsp.extlib.sbt.model.RestDataBlockAccessor; import com.ibm.xsp.extlib.sbt.services.client.DropboxService; import com.ibm.xsp.extlib.util.ExtLibUtil; import com.ibm.xsp.util.URLEncoding; /** * DropboxFiles File type. * @author Philippe Riand * @author Justin Murray * @author Daneel Reif * @author doconnor */ public class DropboxFiles extends AbstractType { public static final String SVC_URL_1 = "1/metadata/dropbox"; public static final String TYPE = "dropbox"; public static final String VERSION_0 = "0"; public static final String VERSION_1 = "1"; private String latestAPI = VERSION_1; public static final String DEFAULT_API_VERSION = "1"; /** * Returns a url that allows the caller to download a file * https://api-content.dropbox.com/<VERSION>/files/dropbox * @param path * path to the file to be downloaded * @return {String} */ public String buildHref(String path, Endpoint bean) { try { // Encode path URL for spaces & special characters path = URLEncoding.encodeURIString(path, null, 0, false); } catch (IOException e) { throw new FacesExceptionEx(e, "Failed to encode URI string: {0}", path); } String href = ExtLibUtil.concatPath(getDropBoxApiVersion(bean), "files/dropbox", '/'); href = ExtLibUtil.concatPath(href, path, '/'); return href; } public DropboxFiles() { } public void addUrlParameters(Map<String, String> map, int index, int blockSize) throws ClientServicesException { } public ClientService createClientService(Endpoint endpoint, String url) throws ClientServicesException { if(StringUtil.isEmpty(url)){ url = SVC_URL_1; } DropboxService svc = new DropboxService(endpoint); return svc; } /* * (non-Javadoc) * * @see * com.ibm.xsp.extlib.sbt.files.IFileType#createFolder(com.ibm.xsp.extlib.security.authorization.AuthorizationBean, * java.lang.String) */ public void createFolder(Endpoint endpoint, String folderName) { //https://api.dropbox.com/<version>/fileops/create_folder try { DropboxService svc = (DropboxService)createClientService(endpoint, ExtLibUtil.concatPath(getDropBoxApiVersion(endpoint), "fileops/create_folder", '/')); HashMap<String, String> params = new HashMap<String, String>(); params.put("root", "dropbox"); params.put("path", folderName); svc.post(getDropBoxApiVersion(endpoint)+"/fileops/create_folder", params,null); } catch (ClientServicesException e) { throw new FacesExceptionEx(e, "Failed to create folder named \'{0}\'", folderName); } } /* * (non-Javadoc) * * @see com.ibm.xsp.extlib.sbt.files.IFileType#deleteRow(com.ibm.xsp.extlib.sbt.files.FileServiceData.Accessor, * com.ibm.xsp.extlib.security.authorization.AuthorizationBean, java.lang.String) */ public void deleteRow(FileServiceAccessor accessor, Endpoint authBean, String rowId) { try { HashMap<String, String> params = new HashMap<String, String>(); params.put("root", "dropbox"); rowId = URLDecoder.decode(rowId, "UTF-8"); params.put("path", rowId); ClientService svc = createClientService(authBean, ExtLibUtil.concatPath(getDropBoxApiVersion(authBean), "fileops/delete", '/')); svc.post(getDropBoxApiVersion(authBean)+"/fileops/delete", params,null); } catch (ClientServicesException e) { throw new FacesExceptionEx(e, "Failed to delete file with ID \'{0}\'", rowId); } catch (UnsupportedEncodingException e) { throw new FacesExceptionEx(e, "Failed to delete file with ID \'{0}\'", rowId); } } /* (non-Javadoc) * @see com.ibm.xsp.extlib.sbt.files.IFileType#getType() */ public String getType() { return TYPE; } public List<FileEntry> readFileEntries(ClientService svc, RestDataBlockAccessor accessor, Map<String, String> params,String serviceUrl) throws ClientServicesException { HandlerJson json= new HandlerJson(); Object jsonObject = (Object) svc.get(serviceUrl,params, json).getData(); ArrayList<FileEntry> entries = new ArrayList<FileEntry>(); String epName = accessor.findEndpointName(); JsonNavigator navigator = new JsonNavigator(jsonObject); DataNavigator contentsNav = navigator.get("contents"); for (int i = 0; i < contentsNav.getCount(); ++i) { FileEntry entry = new FileEntry(); DataNavigator nav = contentsNav.get(i); try { String title = nav.stringValue("path"); String[] result = title.split("/"); entry.setTitle(result[result.length - 1]); entry.setUpdated(nav.dateValue("modified")); entry.setBytes(nav.intValue("bytes")); entry.setSize(nav.stringValue("size")); entry.setAuthorName(params.get("subscriberId")); entry.setVersion(String.valueOf( nav.doubleValue("revision"))); boolean isDir = nav.booleanValue("is_dir"); entry.setIsDirectory(isDir); if(!isDir){ entry.setMimeType(nav.stringValue("mime_type")); } else{ entry.setMimeType("undefined"); } entry.setIcon(MimeIconRegistry.getInstance().get(entry.getMimeType())); entry.setPath(nav.stringValue("path")); String proxyUrl = "xsp/.proxy/files/" + title + "?" + PARAM_TYPE + "=" + TYPE + "&path=" + entry.getPath() + "&mimeType=" + entry.getMimeType() + "&" + PARAM_ENDPOINT_NAME + "="; if(StringUtil.isNotEmpty(epName)){ proxyUrl = proxyUrl + epName; } else{ proxyUrl = proxyUrl + TYPE; } entry.setProxyURL(proxyUrl); entry.setUniqueId(entry.getPath()); } catch (Exception e) { throw new FacesExceptionEx(e); } entries.add(entry); } return entries; } @Override public void serviceProxy(HttpServletRequest request, HttpServletResponse servletResponse) throws ServletException, IOException { //TODO make use of findUrl functionality here instead of cloning the EndpointBean try { String endpointName = request.getParameter(PARAM_ENDPOINT_NAME); if(StringUtil.isEmpty(endpointName)){ endpointName = TYPE; } Endpoint bean = EndpointFactory.getEndpoint(endpointName); if (bean == null) { throw new ServletException("AuthorizationBean not found in application scope"); } //TODO - padraic review with phil what clone is about AbstractEndpoint clonedBean = (AbstractEndpoint) bean; clonedBean.setUrl("https://api-content.dropbox.com/"); String path = request.getParameter("path"); // DropboxFiles Service - https://api-content.dropbox.com/<version>/files/dropbox/<path> DropboxService svc = new DropboxService(endpointName); String href=buildHref(path,bean); HandlerInputStream handler = new HandlerInputStream(); Object file; try { file = svc.get(href,handler).getData(); } catch (ClientServicesException e) { throw new FacesExceptionEx(e, "Failed to execute proxy request"); } servletResponse.setContentType(request.getParameter("mimeType")); String nameUTF8 = URLEncoder.encode(request.getParameter("path"),"utf-8");//$NON-NLS-1$ nameUTF8 = nameUTF8.replaceAll("\\+", "%20");//$NON-NLS-1$ //$NON-NLS-2$ //PEDS954UQU String userAgent= request.getHeader("User-Agent"); //$NON-NLS-1$ if(StringUtil.isNotEmpty(userAgent) && userAgent.contains("Firefox")) //$NON-NLS-1$ //use the format of value of non-acsii charset: filename*="utf8''nameUTF8" servletResponse.setHeader("Content-Disposition","attachment; filename*=\"utf8\'\'"+nameUTF8+'"');//$NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$ else servletResponse.setHeader("Content-Disposition","attachment; filename="+nameUTF8+"");//$NON-NLS-1$ $NON-NLS-2$ $NON-NLS-3$ OutputStream out = servletResponse.getOutputStream(); try{ StreamUtil.copyStream((InputStream) file, out); } finally{ out.close(); } } catch (Exception e) { throw new ServletException(e); } } /* * (non-Javadoc) * * @see com.ibm.xsp.extlib.sbt.files.IFileType#uploadFile(com.ibm.xsp.extlib.services.client.Endpoint, java.io.File, * java.util.HashMap) */ public void uploadFile(Endpoint authBean, File serverFile, FileServiceData dataSource, HashMap<String, String> params) throws CloneNotSupportedException { String name = params.get("file"); if(StringUtil.isEmpty(name)){ throw new FacesExceptionEx(new NullPointerException(), "Name of file being uploaded may not be null"); } int dot = name.lastIndexOf('.'); String ext = null; if(dot > -1){ ext = name.substring(dot + 1); //add one for the dot! } if(StringUtil.isEmpty(ext)){ throw new FacesExceptionEx(new NullPointerException(), "Extension of file being uploaded may not be null"); } try { final String uploadUrl = "/files_put/dropbox/"; String path = dataSource.getCurrentDirectory(); if(StringUtil.isNotEmpty(path)){ name = ExtLibUtil.concatPath(path, name, '/'); } name = ExtLibUtil.concatPath(uploadUrl, name, '/'); String uploadURL = getDropBoxApiVersion(authBean) + name; DropboxService svc = (DropboxService)createClientService(authBean, uploadURL); svc.setMimeForUpload(MIME.getMIMETypeFromExtension(ext)); svc.post(uploadURL, params, null, serverFile,null); } catch (ClientServicesException e) { throw new FacesExceptionEx(e); } } /* * (non-Javadoc) * * @see com.ibm.xsp.extlib.sbt.files.IFileType#useFolders() */ public boolean useFolders() { return true; } /* (non-Javadoc) * @see com.ibm.xsp.extlib.sbt.files.type.AbstractType#getEndpoint() */ @Override public String getDefaultEndpoint() { return EndpointFactory.getEndpointName(EndpointFactory.SERVER_DROPBOX); } public String getDropBoxApiVersion(Endpoint ep){ // if(StringUtil.equals(DEFAULT_API_VERSION, ((DropBoxOAuthEndpoint)ep).getApiVersion())){ // return latestAPI; // } // return ((DropBoxOAuthEndpoint)ep).getApiVersion(); //return default as 1 for now as TokenStore does not support version numnber return DEFAULT_API_VERSION; } /* (non-Javadoc) * @see com.ibm.xsp.extlib.sbt.files.type.AbstractType#getServiceUrl(com.ibm.xsp.extlib.sbt.files.FileServiceData.FileServiceAccessor) */ @Override public String getServiceUrl() { if(accessor != null){ Endpoint ep = accessor.findEndpointBean(); String v = getDropBoxApiVersion(ep); String[] split = SVC_URL_1.split("/"); StringBuffer buffer = new StringBuffer(v + "/"); for(int i = 1; i < split.length; i++){ buffer.append(split[i] + "/"); } return buffer.toString(); } return SVC_URL_1; } private FileServiceAccessor accessor; public void initAccessor(FileServiceAccessor accessor){ this.accessor = accessor; } }