/******************************************************************************* * Copyright (c) 2015 IBM Corp. * * 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.ws.lars.rest; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import com.ibm.ws.lars.rest.exceptions.AssetPersistenceException; import com.ibm.ws.lars.rest.exceptions.InvalidJsonAssetException; import com.ibm.ws.lars.rest.exceptions.NonExistentArtefactException; import com.ibm.ws.lars.rest.model.Asset; import com.ibm.ws.lars.rest.model.AssetCursor; import com.ibm.ws.lars.rest.model.Attachment; import com.ibm.ws.lars.rest.model.AttachmentContentMetadata; import com.ibm.ws.lars.rest.model.AttachmentContentResponse; import com.ibm.ws.lars.rest.model.AttachmentList; /** * */ public class MemoryPersistor implements Persistor { static private long lastId = 0; static synchronized String getNextId() { lastId++; return String.format("%024x", lastId); } private static final String ASSET_ID = "assetId"; private final Map<String, Map<String, Object>> assets = new HashMap<>(); private final Map<String, Map<String, Object>> attachments = new HashMap<>(); private final Map<String, AttachmentContent> gridFS = new HashMap<>(); /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#retrieveAllAssets() */ @Override public AssetCursor retrieveAllAssets() { // Note: retrieveAllAssets does *not* set attachments return new BasicAssetCursor(assets.values()); } @Override public AssetCursor retrieveAllAssets(Collection<AssetFilter> filters, String searchTerm, PaginationOptions pagination, SortOptions sortOptions) { throw new UnsupportedOperationException("Filtering is not supported in this test facade"); } @Override public List<Object> getDistinctValues(String field, Collection<AssetFilter> filters, String searchTerm) { throw new UnsupportedOperationException("Filtering is not supported in this test facade"); } /** {@inheritDoc} */ @Override public int countAllAssets(Collection<AssetFilter> filters, String searchTerm) { throw new UnsupportedOperationException("Filtering is not supported in this test facade"); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#retrieveAsset(java.lang.String) */ @Override public Asset retrieveAsset(String assetId) throws NonExistentArtefactException { if (!assets.containsKey(assetId)) { throw new NonExistentArtefactException(); } return Asset.createAssetFromMap(new HashMap<>(assets.get(assetId))); } @Override public Asset createAsset(Asset newAsset) throws InvalidJsonAssetException { Map<String, Object> props = newAsset.getProperties(); String id = getNextId(); props.put("_id", id); assets.put(id, props); return Asset.createAssetFromMap(props); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#deleteAsset(java.lang.String) */ @Override public void deleteAsset(String assetId) { assets.remove(assetId); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#updateAsset(java.lang.String, * com.ibm.ws.lars.rest.model.Asset) */ @Override public Asset updateAsset(String assetId, Asset asset) throws InvalidJsonAssetException, NonExistentArtefactException { assets.put(assetId, asset.getProperties()); return asset; } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#findAttachmentsForAsset(java.lang.String) */ @Override public AttachmentList findAttachmentsForAsset(String assetId) { List<Map<String, Object>> resultList = new ArrayList<>(); for (Entry<String, Map<String, Object>> e : attachments.entrySet()) { Map<String, Object> attachmentState = e.getValue(); if (Objects.equals(attachmentState.get(ASSET_ID), assetId)) { resultList.add(attachmentState); } } return AttachmentList.createAttachmentListFromMaps(resultList); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#createAttachmentContent(java.lang.String, * java.lang.String, java.io.InputStream) */ @Override public AttachmentContentMetadata createAttachmentContent(String name, String contentType, InputStream attachmentContentStream) throws AssetPersistenceException { try { String id = getNextId(); // Oh Java, I hate you for making me do this. Maybe if we start using // Apache Commons then wecan rip this out byte[] buffer = new byte[1024]; int length; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ((length = attachmentContentStream.read(buffer)) != -1) { baos.write(buffer, 0, length); } byte[] contentBytes = baos.toByteArray(); AttachmentContent attachmentContent = new AttachmentContent(name, contentType, id, contentBytes); gridFS.put(id, attachmentContent); return new AttachmentContentMetadata(id, contentBytes.length); } catch (IOException e) { throw new AssetPersistenceException(e); } } /* * (non-Javadoc) * * @see * com.ibm.ws.lars.rest.Persistor#createAttachmentMetadata(com.ibm.ws.lars.rest.model.Attachment * ) */ @Override public Attachment createAttachmentMetadata(Attachment attachment) { Map<String, Object> props = new HashMap<>(attachment.getProperties()); String id = attachment.get_id(); if (id == null) { id = getNextId(); attachment.set_id(id); } attachments.put(id, props); return Attachment.createAttachmentFromMap(props); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#retrieveAttachmentMetadata(java.lang.String) */ @Override public Attachment retrieveAttachmentMetadata(String attachmentId) throws NonExistentArtefactException { if (!attachments.containsKey(attachmentId)) { throw new NonExistentArtefactException(); } return Attachment.createAttachmentFromMap(new HashMap<>(attachments.get(attachmentId))); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#deleteAttachmentContent(java.lang.String) */ @Override public void deleteAttachmentContent(String attachmentId) { throw new RuntimeException("not implemented"); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#deleteAttachmentMetadata(java.lang.String) */ @Override public void deleteAttachmentMetadata(String attachmentId) { throw new RuntimeException("not implemented"); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#retrieveAttachmentContent(java.lang.String, * java.lang.String, java.lang.String) */ @Override public AttachmentContentResponse retrieveAttachmentContent(String gridFSId) { AttachmentContent content = gridFS.get(gridFSId); InputStream contentStream = new ByteArrayInputStream(content.content); String contentType = content.contentType; return new AttachmentContentResponse(contentStream, contentType); } /* * (non-Javadoc) * * @see com.ibm.ws.lars.rest.Persistor#allocateNewId() */ @Override public String allocateNewId() { return getNextId(); } /** {@inheritDoc} */ @Override public void initialize() { // Nothing to be done } } class AttachmentContent { String name; String contentType; String id; byte[] content; public AttachmentContent(String name, String contentType, String id, byte[] content) { this.name = name; this.contentType = contentType; this.id = id; // Note we do not defensively copy the content so you must not alter // the contents of the array this.content = content; } }