/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.camel.component.atmos.core; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.emc.atmos.api.AtmosApi; import com.emc.atmos.api.ObjectId; import com.emc.atmos.api.ObjectPath; import com.emc.atmos.api.bean.DirectoryEntry; import com.emc.atmos.api.request.CreateObjectRequest; import com.emc.atmos.api.request.ListDirectoryRequest; import org.apache.camel.component.atmos.dto.AtmosDelResult; import org.apache.camel.component.atmos.dto.AtmosFileDownloadResult; import org.apache.camel.component.atmos.dto.AtmosFileUploadResult; import org.apache.camel.component.atmos.dto.AtmosMoveResult; import org.apache.camel.component.atmos.dto.AtmosResult; import org.apache.camel.component.atmos.util.AtmosException; import org.apache.camel.component.atmos.util.AtmosResultCode; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.camel.component.atmos.util.AtmosConstants.ATMOS_FILE_SEPARATOR; public final class AtmosAPIFacade { private static final transient Logger LOG = LoggerFactory.getLogger(AtmosAPIFacade.class); private static AtmosAPIFacade instance; private static AtmosApi client; private AtmosAPIFacade() { } /** * Return a singleton instance of this class * * @param client the AtmosClient performing atmos low level operations * @return the singleton instance of this class */ public static AtmosAPIFacade getInstance(AtmosApi client) { if (instance == null) { instance = new AtmosAPIFacade(); AtmosAPIFacade.client = client; } return instance; } /** * Put or upload a new file or an entire directory to atmos * * @param localPath the file path or the dir path on the local filesystem * @param remotePath the remote path destination on atmos * the file already existing with the same name * will be overridden. * @return a AtmosResult object reporting for each remote path the result of * the operation. * @throws AtmosException */ public AtmosResult put(String localPath, String remotePath) throws AtmosException { AtmosResult result = new AtmosFileUploadResult(); //a map representing for each path the result of the put operation Map<String, AtmosResultCode> resultEntries = null; //in case the remote path is not specified, the remotePath = localPath String atmosPath = remotePath == null ? localPath : remotePath; if (!atmosPath.endsWith(ATMOS_FILE_SEPARATOR)) { atmosPath += ATMOS_FILE_SEPARATOR; } ObjectPath atmosEntry = new ObjectPath(atmosPath); if (!atmosPath.equals(ATMOS_FILE_SEPARATOR)) { if (AtmosAPIFacade.client.getSystemMetadata(atmosEntry) == null) { throw new AtmosException(atmosPath + " does not exist or cannot obtain metadata"); } } File fileLocalPath = new File(localPath); //verify uploading of a single file if (fileLocalPath.isFile()) { //check if atmos file exists if (atmosEntry != null && !atmosEntry.isDirectory()) { throw new AtmosException(atmosPath + " exists on atmos and is not a folder!"); } atmosPath = atmosPath + fileLocalPath.getName(); resultEntries = new HashMap<String, AtmosResultCode>(1); try { ObjectId uploadedFile = putSingleFile(fileLocalPath, atmosPath); if (uploadedFile == null) { resultEntries.put(atmosPath, AtmosResultCode.KO); } else { resultEntries.put(atmosPath, AtmosResultCode.OK); } } catch (Exception ex) { resultEntries.put(atmosPath, AtmosResultCode.KO); } finally { result.setResultEntries(resultEntries); } return result; } else { //verify uploading of a list of files inside a dir LOG.info("uploading a dir..."); //check if atmos folder exists if (atmosEntry != null && !atmosEntry.isDirectory()) { throw new AtmosException(atmosPath + " exists on atmos and is not a folder!"); } //revert to old path String oldAtmosPath = atmosPath; //list all files in a dir Collection<File> listFiles = FileUtils.listFiles(fileLocalPath, null, true); if (listFiles == null || listFiles.isEmpty()) { throw new AtmosException(localPath + " does not contain any files"); } resultEntries = new HashMap<String, AtmosResultCode>(listFiles.size()); for (File file : listFiles) { String absPath = file.getAbsolutePath(); int indexRemainingPath = localPath.length(); if (!localPath.endsWith("/")) { indexRemainingPath += 1; } String remainingPath = absPath.substring(indexRemainingPath); atmosPath = atmosPath + remainingPath; try { LOG.debug("uploading: {} to {}", fileLocalPath, atmosPath); ObjectId uploadedFile = putSingleFile(file, atmosPath); if (uploadedFile == null) { resultEntries.put(atmosPath, AtmosResultCode.KO); } else { resultEntries.put(atmosPath, AtmosResultCode.OK); } } catch (Exception ex) { resultEntries.put(atmosPath, AtmosResultCode.KO); } atmosPath = oldAtmosPath; } result.setResultEntries(resultEntries); return result; } } private ObjectId putSingleFile(File inputFile, String atmosPath) throws Exception { FileInputStream inputStream = new FileInputStream(inputFile); ObjectId uploadedFile = null; try { ObjectPath op = new ObjectPath(atmosPath); CreateObjectRequest request = new CreateObjectRequest(); request.identifier(op).content(inputStream).contentLength(inputFile.length()); uploadedFile = AtmosAPIFacade.client.createObject(request).getObjectId(); return uploadedFile; } finally { inputStream.close(); } } /** * Delete every files and subdirectories inside the remote directory. In * case the remotePath is a file, delete the file. * * @param remotePath the remote location to delete * @return a AtmosResult object with the result of the delete operation. * @throws AtmosException */ public AtmosResult del(String remotePath) throws AtmosException { AtmosResult result = null; ObjectPath op = new ObjectPath(remotePath); AtmosAPIFacade.client.delete(op); result = new AtmosDelResult(); result.setResultEntries(remotePath); return result; } /** * Rename a remote path with the new path location. * * @param remotePath the existing remote path to be renamed * @param newRemotePath the new remote path substituting the old one * @return a AtmosResult object with the result of the move operation. * @throws AtmosException */ public AtmosResult move(String remotePath, String newRemotePath) throws AtmosException { AtmosResult result = null; AtmosAPIFacade.client.move(new ObjectPath(remotePath), new ObjectPath(newRemotePath), true); result = new AtmosMoveResult(); result.setResultEntries(remotePath + "-" + newRemotePath); return result; } /** * Get the content of every file inside the remote path. * * @param remotePath the remote path where to download from * @return a AtmosResult object with the content (ByteArrayOutputStream) of * every files inside the remote path. * @throws AtmosException */ public AtmosResult get(String remotePath) throws AtmosException { AtmosResult result = new AtmosFileDownloadResult(); //a map representing for each path the result of the baos Map<String, ByteArrayOutputStream> resultEntries = new HashMap<String, ByteArrayOutputStream>(); //iterate from the remotePath downloadFilesInFolder(remotePath, resultEntries); //put the map of baos as result result.setResultEntries(resultEntries); return result; } private void downloadFilesInFolder(String atmosPath, Map<String, ByteArrayOutputStream> resultEntries) throws AtmosException { ObjectPath atmosEntry = new ObjectPath(atmosPath); if (AtmosAPIFacade.client.getSystemMetadata(atmosEntry) == null) { throw new AtmosException(atmosPath + " does not exist or cannot obtain metadata"); } if (!atmosEntry.isDirectory()) { LOG.debug("downloading a single file..."); downloadSingleFile(atmosPath, resultEntries); return; } ListDirectoryRequest listRequest = new ListDirectoryRequest().path(atmosEntry); AtmosAPIFacade.client.listDirectory(listRequest); for (DirectoryEntry entry : AtmosAPIFacade.client.listDirectory(listRequest).getEntries()) { if (!entry.isDirectory()) { try { //get the baos of the file downloadSingleFile(atmosEntry.getPath().concat(entry.getFilename()), resultEntries); } catch (AtmosException e) { LOG.warn("Cannot download from " + entry.getFilename()); } } else { //iterate on folder downloadFilesInFolder(atmosEntry.getPath().concat(entry.getFilename()), resultEntries); } } } private void downloadSingleFile(String path, Map<String, ByteArrayOutputStream> resultEntries) throws AtmosException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] content = null; try { content = AtmosAPIFacade.client.readObject(new ObjectPath(path), byte[].class); baos.write(content); } catch (IOException e) { throw new AtmosException(path + " cannot obtain a stream", e); } if (content != null) { resultEntries.put(path, baos); LOG.debug("Downloaded path: {} size:", path, baos.size()); } } }