/* * Copyright 2008-2014 the original author or authors * * 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 org.kaleidofoundry.core.store; import static org.kaleidofoundry.core.i18n.InternalBundleHelper.StoreMessageBundle; import static org.kaleidofoundry.core.env.model.EnvironmentConstants.KALEIDO_PERSISTENT_UNIT_NAME; import static org.kaleidofoundry.core.store.FileStoreConstants.ClobJpaStorePluginName; import static org.kaleidofoundry.core.store.FileStoreConstants.DEFAULT_BUFFER_SIZE; import static org.kaleidofoundry.core.store.FileStoreContextBuilder.BufferSize; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URI; import java.util.Calendar; import java.util.Locale; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import org.kaleidofoundry.core.context.RuntimeContext; import org.kaleidofoundry.core.io.FileHelper; import org.kaleidofoundry.core.io.MimeTypeResolverFactory; import org.kaleidofoundry.core.lang.annotation.NotNull; import org.kaleidofoundry.core.lang.annotation.Task; import org.kaleidofoundry.core.plugin.Declare; import org.kaleidofoundry.core.store.model.ResourceHandlerEntity; import org.kaleidofoundry.core.util.StringHelper; import org.kaleidofoundry.core.util.locale.LocaleFactory; /** * Databse JPA {@link FileStore} implementation * <br/> * * The esource content will be stored in clob or / blob database<br/> * * @author jraduget * @see FileStoreContextBuilder enum of context configuration properties available */ @Declare(ClobJpaStorePluginName) @Task(comment = "Annotate it as @Stateless ejb to enable ejb exposition + injection - import right ejb 3.x library - problem : coupling it to ejb3") public class JpaFileStore extends AbstractFileStore implements FileStore { @PersistenceContext(unitName = KALEIDO_PERSISTENT_UNIT_NAME) private EntityManager em; /** * The default entity manager is handle by kaleido persistent name. * You can overide it, with your custom * * @return current entity manager (handle managed one or not) */ @NotNull protected final EntityManager getEntityManager() { /* * done via aop : PersistenceContextAspect * // unmanaged environment * if (em == null) { * return UnmanagedEntityManagerFactory.currentEntityManager(KaleidoPersistentContextUnitName); * } * // managed environment * else { * return em; * } */ return em; } /** * @param context */ public JpaFileStore(@NotNull final RuntimeContext<FileStore> context) { super(context); } /** * @param baseUri * @param context */ public JpaFileStore(final String baseUri, final RuntimeContext<FileStore> context) { super(baseUri, context); } /** * @see AbstractFileStore#AbstractFileStore() */ JpaFileStore() { super(); } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#getStoreType() */ @Override public FileStoreType[] getStoreType() { return new FileStoreType[] { FileStoreTypeEnum.jpa }; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#doLoad(java.net.URI) */ @Override protected ResourceHandler doGet(final URI resourceUri) throws ResourceNotFoundException, ResourceException { final ResourceHandlerEntity entity = getEntityManager().find(ResourceHandlerEntity.class, resourceUri.toString()); if (entity == null) { throw new ResourceNotFoundException(resourceUri.toString()); } else { final ResourceHandler resource = createResourceHandler(resourceUri.toString(), new ByteArrayInputStream(entity.getContent())); // Set some meta datas if (resource instanceof ResourceHandlerBean) { if (entity.getUpdatedDate() != null) { ((ResourceHandlerBean) resource).setLastModified(entity.getUpdatedDate().getTime()); } else { ((ResourceHandlerBean) resource).setLastModified(entity.getCreationDate().getTime()); } ((ResourceHandlerBean) resource).setMimeType(entity.getMimeType()); ((ResourceHandlerBean) resource).setLength(entity.getSize()); } return resource; } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#doRemove(java.net.URI) */ @Override protected void doRemove(final URI resourceUri) throws ResourceNotFoundException, ResourceException { final ResourceHandlerEntity entity = getEntityManager().find(ResourceHandlerEntity.class, resourceUri.toString()); if (entity == null) { throw new ResourceNotFoundException(resourceUri.toString()); } else { getEntityManager().remove(entity); } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.store.AbstractFileStore#doStore(java.net.URI, org.kaleidofoundry.core.store.ResourceHandler) */ @Override protected void doStore(final URI resourceUri, final ResourceHandler resource) throws ResourceException { boolean isNew = true; final String filename = resourceUri.getPath().substring(1); ResourceHandlerEntity storeEntity; Locale locale = LocaleFactory.getDefaultFactory().getCurrentLocale(); storeEntity = getEntityManager().find(ResourceHandlerEntity.class, resourceUri.toString()); if (storeEntity == null) { storeEntity = newInstance(); storeEntity.setUri(resourceUri.toString()); storeEntity.setName(FileHelper.getFileName(filename)); storeEntity.setPath(filename); storeEntity.setCreationDate(Calendar.getInstance(locale).getTime()); storeEntity.setMimeType(MimeTypeResolverFactory.getService().getMimeType(FileHelper.getFileNameExtension(resourceUri.getPath()))); isNew = true; } else { storeEntity.setUpdatedDate(Calendar.getInstance(locale).getTime()); isNew = false; } if (resource.getInputStream() != null) { final byte[] buffer = new byte[context.getInteger(BufferSize, DEFAULT_BUFFER_SIZE)]; final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { int lengthToWrite = resource.getInputStream().read(buffer); while (lengthToWrite != -1) { outputStream.write(buffer, 0, lengthToWrite); lengthToWrite = resource.getInputStream().read(buffer); } storeEntity.setContent(outputStream.toByteArray()); if (isNew) { getEntityManager().persist(storeEntity); getEntityManager().flush(); // to remove } else { getEntityManager().merge(storeEntity); getEntityManager().flush(); // to remove } } catch (final IOException ioe) { throw new ResourceException(ioe, resourceUri.toString()); } } } /** * @return new {@link ResourceHandlerEntity} instance (default or custom) depending from the current context */ private ResourceHandlerEntity newInstance() { final String customResourceHandlerEntityClass = context.getString(FileStoreContextBuilder.CustomResourceHandlerEntity); if (StringHelper.isEmpty(customResourceHandlerEntityClass)) { return new ResourceHandlerEntity(); } else { try { final Class<?> customClass = Class.forName(customResourceHandlerEntityClass); final Object instance = customClass.newInstance(); if (instance instanceof ResourceHandlerEntity) { return (ResourceHandlerEntity) instance; } else { throw new IllegalStateException(StoreMessageBundle.getMessage("store.context.customentity.illegaltype", context.getName(), context.getProperty(FileStoreContextBuilder.CustomResourceHandlerEntity), FileStoreContextBuilder.CustomResourceHandlerEntity)); } } catch (final ClassNotFoundException cnfe) { throw new IllegalStateException(StoreMessageBundle.getMessage("store.context.customentity.notfound", context.getName(), context.getProperty(FileStoreContextBuilder.CustomResourceHandlerEntity), FileStoreContextBuilder.CustomResourceHandlerEntity)); } catch (final IllegalAccessException iae) { throw new IllegalStateException(StoreMessageBundle.getMessage("store.context.customentity.illegalconstructor", customResourceHandlerEntityClass, iae.getMessage())); } catch (final InstantiationException ie) { throw new IllegalStateException(StoreMessageBundle.getMessage("store.context.customentity.cantcreate", customResourceHandlerEntityClass, ie.getMessage())); } } } }