/* Copyright 2011-2014 Red Hat, Inc This file is part of PressGang CCMS. PressGang CCMS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PressGang CCMS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PressGang CCMS. If not, see <http://www.gnu.org/licenses/>. */ package org.jboss.pressgang.ccms.server.webdav.resources.hierarchy.topics.topic.fields; import static javax.ws.rs.core.Response.Status.OK; import javax.naming.NamingException; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.transaction.TransactionManager; import javax.validation.constraints.NotNull; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.util.Date; import net.java.dev.webdav.jaxrs.xml.elements.HRef; import net.java.dev.webdav.jaxrs.xml.elements.MultiStatus; import net.java.dev.webdav.jaxrs.xml.elements.Prop; import net.java.dev.webdav.jaxrs.xml.elements.PropStat; import net.java.dev.webdav.jaxrs.xml.elements.Status; import net.java.dev.webdav.jaxrs.xml.properties.DisplayName; import net.java.dev.webdav.jaxrs.xml.properties.FixedCreationDate; import net.java.dev.webdav.jaxrs.xml.properties.GetContentLength; import net.java.dev.webdav.jaxrs.xml.properties.GetContentType; import net.java.dev.webdav.jaxrs.xml.properties.GetLastModified; import net.java.dev.webdav.jaxrs.xml.properties.LockDiscovery; import net.java.dev.webdav.jaxrs.xml.properties.SupportedLock; import org.jboss.pressgang.ccms.model.Topic; import org.jboss.pressgang.ccms.server.utils.JNDIUtilities; import org.jboss.pressgang.ccms.server.utils.TopicUtilities; import org.jboss.pressgang.ccms.server.webdav.managers.CompatibilityManager; import org.jboss.pressgang.ccms.server.webdav.managers.ResourceTypes; import org.jboss.pressgang.ccms.server.webdav.resources.ByteArrayReturnValue; import org.jboss.pressgang.ccms.server.webdav.resources.InternalResource; import org.jboss.pressgang.ccms.server.webdav.resources.MultiStatusReturnValue; import org.jboss.pressgang.ccms.utils.common.DocBookUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Handles access to topic's XML content. */ public class InternalResourceTopicContent extends InternalResource { private static final Logger LOGGER = LoggerFactory.getLogger(InternalResourceTopicContent.class.getName()); public InternalResourceTopicContent(@NotNull final UriInfo uriInfo, @NotNull final CompatibilityManager compatibilityManager, @NotNull final String remoteAddress, @NotNull final Integer intId) { super(uriInfo, compatibilityManager, remoteAddress, intId); } @Override public int write(@NotNull final byte[] contents) { final String stringContents = new String(contents); LOGGER.debug("ENTER InternalResourceTopicContent.write() " + getIntId()); LOGGER.debug(stringContents); /* If we are not actually saving any content, just mark the file as visible and return. */ if (contents.length == 0) { getCompatibilityManager().create(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId()); return Response.Status.NO_CONTENT.getStatusCode(); } EntityManager entityManager = null; EntityManagerFactory entityManagerFactory = null; TransactionManager transactionManager = null; try { transactionManager = JNDIUtilities.lookupJBossTransactionManager(); transactionManager.begin(); entityManagerFactory = JNDIUtilities.lookupJBossEntityManagerFactory(); entityManager = entityManagerFactory.createEntityManager(); final Topic topic = entityManager.find(Topic.class, getIntId()); if (topic != null) { // Sync the title from the xml if (TopicUtilities.isTopicNormalTopic(topic)) { final String title = DocBookUtilities.findTitle(stringContents); if (title != null) { topic.setTopicTitle(title); } } // Set the updated xml contents topic.setTopicXML(stringContents); // Validate and sync the XML TopicUtilities.syncXML(entityManager, topic); TopicUtilities.validateXML(entityManager, topic); entityManager.persist(topic); entityManager.flush(); transactionManager.commit(); getCompatibilityManager().create(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId()); getCompatibilityManager().put(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId(), topic.getTopicXML().getBytes(), contents); return Response.Status.NO_CONTENT.getStatusCode(); } return Response.Status.NOT_FOUND.getStatusCode(); } catch (final Exception ex) { if (transactionManager != null) { try { transactionManager.rollback(); } catch (final Exception ex2) { LOGGER.error("There was an error rolling back the transaction " + ex2.toString()); } } return Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); } finally { if (entityManager != null) { entityManager.close(); } } } @Override public ByteArrayReturnValue get() { LOGGER.debug("ENTER InternalResourceTopicContent.get() " + getIntId()); if (getCompatibilityManager().isDeleted(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId())) { LOGGER.debug("Deletion Manager says this file is deleted"); return new ByteArrayReturnValue(Response.Status.NOT_FOUND.getStatusCode(), null); } EntityManager entityManager = null; EntityManagerFactory entityManagerFactory = null; try { entityManagerFactory = JNDIUtilities.lookupJBossEntityManagerFactory(); entityManager = entityManagerFactory.createEntityManager(); final Topic topic = entityManager.find(Topic.class, getIntId()); /* get the data from the cache if it exists */ final byte[] retValue = getCompatibilityManager().get(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId(), topic.getTopicXML().getBytes()); if (topic != null) { return new ByteArrayReturnValue(Response.Status.OK.getStatusCode(), retValue); } } catch (final Exception ex) { return new ByteArrayReturnValue(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), null); } finally { if (entityManager != null) { entityManager.close(); } } return new ByteArrayReturnValue(Response.Status.NOT_FOUND.getStatusCode(), null); } @Override public int delete() { LOGGER.debug("ENTER InternalResourceTopicContent.delete() " + getIntId() + " " + getRemoteAddress()); if (getCompatibilityManager().isDeleted(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId())) { LOGGER.debug("Deletion Manager says this file is already deleted"); return Response.Status.NOT_FOUND.getStatusCode(); } getCompatibilityManager().delete(ResourceTypes.TOPIC_CONTENTS, getRemoteAddress(), getIntId()); /* pretend to be deleted */ return Response.Status.NO_CONTENT.getStatusCode(); } @Override public MultiStatusReturnValue propfind(final String depth) { if (getUriInfo() == null) { throw new IllegalStateException("Can not perform propfind without uriInfo"); } EntityManager entityManager = null; EntityManagerFactory entityManagerFactory = null; try { entityManagerFactory = JNDIUtilities.lookupJBossEntityManagerFactory(); entityManager = entityManagerFactory.createEntityManager(); final Topic topic = entityManager.find(Topic.class, getIntId()); if (topic != null) { final net.java.dev.webdav.jaxrs.xml.elements.Response response = getProperties(getCompatibilityManager(), getRemoteAddress(), getUriInfo(), topic, true); final MultiStatus st = new MultiStatus(response); return new MultiStatusReturnValue(207, st); } } catch (final NumberFormatException ex) { return new MultiStatusReturnValue(Response.Status.NOT_FOUND.getStatusCode()); } catch (NamingException e) { return new MultiStatusReturnValue(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } finally { if (entityManager != null) { entityManager.close(); } } return new MultiStatusReturnValue(Response.Status.NOT_FOUND.getStatusCode()); } /** * @param uriInfo The uri that was used to access this resource * @param topic The topic that this content represents * @param local true if we are building the properties for the resource at the given uri, and false if we are building * properties for a child resource. * @return */ public static net.java.dev.webdav.jaxrs.xml.elements.Response getProperties(@NotNull final CompatibilityManager compatibilityManager, @NotNull final String remoteAddress, @NotNull final UriInfo uriInfo, @NotNull final Topic topic, final boolean local) { final Date lastModifiedDate = topic.getLastModifiedDate(); final GetLastModified getLastModified = new GetLastModified(lastModifiedDate == null ? new Date() : lastModifiedDate); final HRef hRef = local ? new HRef(uriInfo.getRequestUri()) : new HRef(uriInfo.getRequestUriBuilder().path(topic.getId() + ".xml").build()); final FixedCreationDate creationDate = new FixedCreationDate(topic.getTopicTimeStamp() == null ? new Date() : topic.getTopicTimeStamp()); final GetContentType getContentType = new GetContentType(MediaType.APPLICATION_OCTET_STREAM); final GetContentLength getContentLength = new GetContentLength(topic.getTopicXML() == null ? 0 : topic.getTopicXML().length()); final DisplayName displayName = new DisplayName(topic.getId() + ".xml"); final SupportedLock supportedLock = new SupportedLock(); final LockDiscovery lockDiscovery = new LockDiscovery(); final Prop prop = new Prop(creationDate, getLastModified, getContentType, getContentLength, displayName, supportedLock, lockDiscovery); final Status status = new Status((javax.ws.rs.core.Response.StatusType) OK); final PropStat propStat = new PropStat(prop, status); final net.java.dev.webdav.jaxrs.xml.elements.Response davFile = new net.java.dev.webdav.jaxrs.xml.elements.Response(hRef, null, null, null, propStat); return davFile; } }