Author: cziegeler
Date: Mon Sep 16 11:28:12 2013
New Revision: 1523594
URL: http://svn.apache.org/r1523594
Log:
SLING-3036 : Feedback on SLING-2707: Support of chunked file upload. Apply
patch from Shashank Gupta
Added:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
(with props)
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
(with props)
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd
(with props)
Added:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java?rev=1523594&view=auto
==============================================================================
---
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
(added)
+++
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
Mon Sep 16 11:28:12 2013
@@ -0,0 +1,76 @@
+/*
+ * 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.sling.servlets.post.impl.helper;
+
+/**
+ * <code>Chunk</code> enscapsulates all chunk upload attributes.
+ *
+ * @since 2.3.4
+ */
+public class Chunk {
+
+ private long offset;
+
+ private long length;
+
+ private boolean completed;
+
+ /**
+ * Return offset of the chunk.
+ */
+ public long getOffset() {
+ return offset;
+ }
+
+ /**
+ * Set offset value.
+ */
+ public void setOffsetValue(long offset) {
+ this.offset = offset;
+ }
+
+ /**
+ * Return length of the file parameter.
+ */
+ public long getLength() {
+ return length;
+ }
+
+ /**
+ * Set length of file parameter.
+ */
+ public void setLength(long length) {
+ this.length = length;
+ }
+
+ /**
+ * Return true if request contains last chunk as a result upload should be
+ * finished. It is useful in scenarios where file streaming where file size
+ * is not known in advance.
+ */
+ public boolean isCompleted() {
+ return completed;
+ }
+
+ /**
+ * Set complete flag
+ */
+ public void setCompleted(boolean complete) {
+ this.completed = complete;
+ }
+
+}
Propchange:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/Chunk.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java?rev=1523594&view=auto
==============================================================================
---
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
(added)
+++
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
Mon Sep 16 11:28:12 2013
@@ -0,0 +1,186 @@
+/*
+ * 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.sling.servlets.post.impl.helper;
+
+import java.util.Map;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.OsgiUtil;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.servlets.post.SlingPostConstants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>ChunkCleanUpTask</code> implements a job run at regular intervals
+ * to find incomplete chunk uploads and remove them from the repository to
+ * prevent littering the repository with incomplete chunks.
+ * <p>
+ * This task is configured with OSGi configuration for the PID
+ * <code>org.apache.sling.servlets.post.impl.helper.ChunkCleanUpTask</code>
with
+ * property <code>scheduler.expression</code> being the schedule to execute the
+ * task. The schedule is a cron job expression as described at <a
+ * href="http://www.docjar.com/docs/api/org/quartz/CronTrigger.html">Cron
+ * Trigger</a> with the default value configured to run twice a day at 0h41m31s
+ * and 12h4131s.
+ * <p>
+ * The property <code>chunk.cleanup.age</code> specifies chunk's age in minutes
+ * before it is considered for clean up.
+ * <p>
+ * Currently the cleanup tasks connects as the administrative user to the
+ * default workspace assuming users are stored in that workspace and the
+ * administrative user has full access.
+ */
+@Component(metatype = true, label = "Sling Post Chunk Upload : Cleanup Task",
description = "Task to regularly purge incomplete chunks from the repository")
+@Service(value = Runnable.class)
+@Properties({
+ @Property(name = "scheduler.expression", value = "31 41 0/12 * * ?", label
= "Schedule", description = "Cron expression scheudling this job. Default is
hourly 17m23s after the hour. "
+ + "See http://www.docjar.com/docs/api/org/quartz/CronTrigger.html for
a description "
+ + "of the format for this value."),
+ @Property(name = "service.description", value = "Periodic Chunk Cleanup
Job", propertyPrivate = true),
+ @Property(name = "service.vendor", value = "The Apache Software
Foundation", propertyPrivate = true) })
+public class ChunkCleanUpTask implements Runnable {
+
+ /** default log */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference
+ private SlingRepository repository;
+
+ @Property(intValue = 360, description = "The chunk's age in minutes before
it is considered for clean up.")
+ private static final String CHUNK_CLEANUP_AGE = "chunk.cleanup.age";
+
+ private SlingFileUploadHandler uploadhandler = new
SlingFileUploadHandler();
+
+ /**
+ * Clean up age criterion in millisec.
+ */
+ private long chunkCleanUpAge;
+
+ /**
+ * Executes the job. Is called for each triggered schedule point.
+ */
+ public void run() {
+ log.debug("ChunkCleanUpTask: Starting cleanup");
+ cleanup();
+ }
+
+ /**
+ * This method deletes chunks which are {@link #isEligibleForCleanUp(Node)}
+ * for cleanup. It queries all
+ * {@link SlingPostConstants#NT_SLING_CHUNK_MIXIN} nodes and filter nodes
+ * which are {@link #isEligibleForCleanUp(Node)} for cleanup. It then
+ * deletes old chunks upload.
+ */
+ private void cleanup() {
+
+ long start = System.currentTimeMillis();
+
+ int numCleaned = 0;
+ int numLive = 0;
+
+ Session admin = null;
+ try {
+ // assume chunks are stored in the default workspace
+ admin = repository.loginAdministrative(null);
+ QueryManager qm = admin.getWorkspace().getQueryManager();
+
+ QueryResult queryres = qm.createQuery(
+ "SELECT * FROM [sling:chunks] ", Query.JCR_SQL2).execute();
+ NodeIterator nodeItr = queryres.getNodes();
+ while (nodeItr.hasNext()) {
+ Node node = nodeItr.nextNode();
+ if (isEligibleForCleanUp(node)) {
+ numCleaned++;
+ uploadhandler.deleteChunks(node);
+ } else {
+ numLive++;
+ }
+ }
+ if (admin.hasPendingChanges()) {
+ try {
+ admin.refresh(true);
+ admin.save();
+ } catch (InvalidItemStateException iise) {
+ log.info("ChunkCleanUpTask: Concurrent modification to one
or more of the chunk to be removed. Retrying later");
+ } catch (RepositoryException re) {
+ log.info("ChunkCleanUpTask: Failed persisting chunk
removal. Retrying later");
+ }
+ }
+
+ } catch (Throwable t) {
+ log.error(
+ "ChunkCleanUpTask: General failure while trying to cleanup
chunks",
+ t);
+ } finally {
+ if (admin != null) {
+ admin.logout();
+ }
+ }
+ long end = System.currentTimeMillis();
+ log.info(
+ "ChunkCleanUpTask finished: Removed {} chunk upload(s) in {}ms ({}
chunk upload(s) still active)",
+ new Object[] { numCleaned, (end - start), numLive });
+ }
+
+ /**
+ * Check if {@link Node} is eligible of
+ * {@link SlingPostConstants#NT_SLING_CHUNK_NODETYPE} cleanup. To be
+ * eligible the age of last
+ * {@link SlingPostConstants#NT_SLING_CHUNK_NODETYPE} uploaded should be
+ * greater than @link {@link #chunkCleanUpAge}
+ *
+ * @param node {@link Node} containing
+ * {@link SlingPostConstants#NT_SLING_CHUNK_NODETYPE}
+ * {@link Node}s
+ * @return true if eligible else false.
+ * @throws RepositoryException
+ */
+ private boolean isEligibleForCleanUp(Node node) throws RepositoryException
{
+ Node lastChunkNode = uploadhandler.getLastChunk(node);
+ return lastChunkNode != null
+ && (System.currentTimeMillis() - lastChunkNode.getProperty(
+ javax.jcr.Property.JCR_CREATED).getDate().getTimeInMillis()) >
chunkCleanUpAge;
+ }
+
+ @Activate
+ protected void activate(final ComponentContext context,
+ final Map<String, Object> configuration) {
+ chunkCleanUpAge = OsgiUtil.toInteger(
+ configuration.get(CHUNK_CLEANUP_AGE), 1) * 60 * 1000;
+ log.info("scheduler config [{}], chunkGarbageTime [{}] ms",
+ OsgiUtil.toString(configuration.get("scheduler.expression"), ""),
+ chunkCleanUpAge);
+
+ }
+
+}
\ No newline at end of file
Propchange:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange:
sling/trunk/bundles/servlets/post/src/main/java/org/apache/sling/servlets/post/impl/helper/ChunkCleanUpTask.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd
URL:
http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd?rev=1523594&view=auto
==============================================================================
---
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd
(added)
+++
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd
Mon Sep 16 11:28:12 2013
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+
+<sling = 'http://sling.apache.org/jcr/sling/1.0'>
+
+//-----------------------------------------------------------------------------
+// node type to store chunk
+// offset: offset of chunk in file
+// jcr:data: binary of chunk
+[sling:chunk] > nt:hierarchyNode
+ primaryitem jcr:data
+ - sling:offset (long) mandatory
+ - jcr:data (binary) mandatory
+
+
//-----------------------------------------------------------------------------
+ // Mixin type to identify that a node has chunks
+ // sling:fileLength : length of complete file
+ // sling:length: cumulative length of all uploaded chunks
+[sling:chunks]
+ mixin
+ - sling:fileLength (long)
+ - sling:length (long)
+ + * (sling:chunk) multiple
Propchange:
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sling/trunk/bundles/servlets/post/src/main/resources/SLING-INF/nodetypes/chunk.cnd
------------------------------------------------------------------------------
svn:keywords = Id