You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2009/01/01 20:24:53 UTC
svn commit: r730594 - in
/webservices/commons/trunk/modules/axiom/modules/axiom-api/src:
main/java/org/apache/axiom/attachments/
main/java/org/apache/axiom/attachments/impl/
test/java/org/apache/axiom/attachments/impl/
Author: veithen
Date: Thu Jan 1 11:24:52 2009
New Revision: 730594
URL: http://svn.apache.org/viewvc?rev=730594&view=rev
Log:
WSCOMMONS-424: Replaced BufferUtils#doesDataHandlerExceedLimit with a better implementation (see JIRA issue for more details).
Added:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/SizeAwareDataSource.java
Modified:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/ByteArrayDataSource.java
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/attachments/impl/BufferUtilsTest.java
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/ByteArrayDataSource.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/ByteArrayDataSource.java?rev=730594&r1=730593&r2=730594&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/ByteArrayDataSource.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/ByteArrayDataSource.java Thu Jan 1 11:24:52 2009
@@ -19,13 +19,12 @@
package org.apache.axiom.attachments;
-import javax.activation.DataSource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-public class ByteArrayDataSource implements DataSource {
+public class ByteArrayDataSource implements SizeAwareDataSource {
private byte[] data;
@@ -65,5 +64,9 @@
public OutputStream getOutputStream() throws IOException {
throw new IOException("Not Supported");
}
+
+ public long getSize() {
+ return data == null ? 0 : data.length;
+ }
}
Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/SizeAwareDataSource.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/SizeAwareDataSource.java?rev=730594&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/SizeAwareDataSource.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/SizeAwareDataSource.java Thu Jan 1 11:24:52 2009
@@ -0,0 +1,41 @@
+/*
+ * 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.axiom.attachments;
+
+import javax.activation.DataSource;
+
+/**
+ * Optional extension interface that can be implemented by data sources that support a
+ * getSize method.
+ * Code working with data sources can use this interface to optimize certain operations.
+ * An example is
+ * {@link org.apache.axiom.attachments.impl.BufferUtils#doesDataHandlerExceedLimit(javax.activation.DataHandler, int)}.
+ */
+public interface SizeAwareDataSource extends DataSource {
+ /**
+ * Get the size of the data source.
+ * Implementations must return the number of bytes that can be read from
+ * the input stream returned by {@link #getInputStream()} before reaching
+ * the end of the stream.
+ *
+ * @return the size of the data source
+ */
+ long getSize();
+}
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java?rev=730594&r1=730593&r2=730594&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java Thu Jan 1 11:24:52 2009
@@ -18,6 +18,7 @@
*/
package org.apache.axiom.attachments.impl;
+import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -30,8 +31,8 @@
import javax.activation.DataSource;
import javax.activation.FileDataSource;
+import org.apache.axiom.attachments.SizeAwareDataSource;
import org.apache.axiom.attachments.utils.BAAOutputStream;
-import org.apache.axiom.om.OMException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -216,8 +217,48 @@
return baaos.receive(is, limit);
}
+ /**
+ * Exception used by SizeLimitedOutputStream if the size limit has been exceeded.
+ */
+ private static class SizeLimitExceededException extends IOException {
+ private static final long serialVersionUID = -6644887187061182165L;
+ }
/**
+ * An output stream that counts the number of bytes written to it and throws an
+ * exception when the size exceeds a given limit.
+ */
+ private static class SizeLimitedOutputStream extends OutputStream {
+ private final int maxSize;
+ private int size;
+
+ public SizeLimitedOutputStream(int maxSize) {
+ this.maxSize = maxSize;
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ size += len;
+ checkSize();
+ }
+
+ public void write(byte[] b) throws IOException {
+ size += b.length;
+ checkSize();
+ }
+
+ public void write(int b) throws IOException {
+ size++;
+ checkSize();
+ }
+
+ private void checkSize() throws SizeLimitExceededException {
+ if (size > maxSize) {
+ throw new SizeLimitExceededException();
+ }
+ }
+ }
+
+ /**
* The method checks to see if attachment is eligble for optimization.
* An attachment is eligible for optimization if and only if the size of
* the attachment is greated then the optimzation threshold size limit.
@@ -232,80 +273,46 @@
* @throws IOException
*/
public static int doesDataHandlerExceedLimit(DataHandler dh, int limit){
- if(log.isDebugEnabled()){
- log.debug("start isEligibleForOptimization");
- }
//If Optimized Threshold not set return true.
if(limit==0){
- if(log.isDebugEnabled()){
- log.debug("optimizedThreshold not set");
- }
return -1;
}
-
- InputStream in=null;
- //read bytes from input stream to check if
- //attachment size is greater than the optimized size.
- int totalRead = 0;
- try{
- in = getInputStream(dh);
- if(in.markSupported()){
- in.mark(limit);
- }
- if(in == null){
- if(log.isDebugEnabled()){
- log.debug("Input Stream is null");
- }
+ DataSource ds = dh.getDataSource();
+ if (ds instanceof SizeAwareDataSource) {
+ return ((SizeAwareDataSource)ds).getSize() > limit ? 1 : 0;
+ } else if (ds instanceof javax.mail.util.ByteArrayDataSource) {
+ // Special optimization for JavaMail's ByteArrayDataSource (Axiom's ByteArrayDataSource
+ // already implements SizeAwareDataSource and doesn't need further optimization):
+ // we know that ByteArrayInputStream#available() directly returns the size of the
+ // data source.
+ try {
+ return ((ByteArrayInputStream)ds.getInputStream()).available() > limit ? 1 : 0;
+ } catch (IOException ex) {
+ // We will never get here...
return -1;
}
- do{
- byte[] buffer = getTempBuffer();
- int bytesRead = in.read(buffer, 0, BUFFER_LEN);
- totalRead = totalRead+bytesRead;
- releaseTempBuffer(buffer);
- }while((limit>totalRead) && (in.available()>0));
-
- if(in.markSupported()){
- in.reset();
- }
- if(totalRead > limit){
- if(log.isDebugEnabled()){
- log.debug("Attachment size greater than limit");
- }
+ } else if (ds instanceof FileDataSource) {
+ // Special optimization for FileDataSources: no need to open and read the file
+ // to know its size!
+ return ((FileDataSource)ds).getFile().length() > limit ? 1 : 0;
+ } else {
+ // In all other cases, we prefer DataHandler#writeTo over DataSource#getInputStream.
+ // The reason is that if the DataHandler was constructed from an Object rather than
+ // a DataSource, a call to DataSource#getInputStream() will start a new thread and
+ // return a PipedInputStream. This is so for Geronimo's as well as Sun's JAF
+ // implementaion. The reason is that DataContentHandler only has a writeTo and no
+ // getInputStream method. Obviously starting a new thread just to check the size of
+ // the data is an overhead that we should avoid.
+ try {
+ dh.writeTo(new SizeLimitedOutputStream(limit));
+ } catch (SizeLimitExceededException ex) {
return 1;
+ } catch (IOException ex) {
+ log.warn(ex.getMessage());
+ return -1;
}
- }catch(Exception e){
- log.warn(e.getMessage());
- return -1;
- }
-
- if(log.isDebugEnabled()){
- log.debug("Attachment Size smaller than limit");
- }
-
- return 0;
- }
-
- private static java.io.InputStream getInputStream(DataHandler dataHandlerObject) throws OMException {
- InputStream inStream = null;
- javax.activation.DataHandler dataHandler =
- (javax.activation.DataHandler) dataHandlerObject;
- try {
- DataSource ds = dataHandler.getDataSource();
- if(ds instanceof FileDataSource){
- inStream = ds.getInputStream();
- }else{
- inStream = dataHandler.getDataSource().getInputStream();
- if(!inStream.markSupported()){
- throw new OMException("Stream does not support mark, Cannot read the stream as DataSource will be consumed.");
- }
- }
- } catch (IOException e) {
- throw new OMException(
- "Cannot get InputStream from DataHandler." + e);
+ return 0;
}
- return inStream;
-
}
private static synchronized byte[] getTempBuffer() {
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/attachments/impl/BufferUtilsTest.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/attachments/impl/BufferUtilsTest.java?rev=730594&r1=730593&r2=730594&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/attachments/impl/BufferUtilsTest.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/test/java/org/apache/axiom/attachments/impl/BufferUtilsTest.java Thu Jan 1 11:24:52 2009
@@ -110,8 +110,9 @@
int unsupported= BufferUtils.doesDataHandlerExceedLimit(dh, 0);
assertEquals(-1, unsupported);
int doesExceed = BufferUtils.doesDataHandlerExceedLimit(dh, 10);
- //Expecting Mark NotSupported
- assertEquals(-1, doesExceed);
+ assertEquals(1, doesExceed);
+ int doesNotExceed = BufferUtils.doesDataHandlerExceedLimit(dh, 100);
+ assertEquals(0, doesNotExceed);
}catch(Exception e){
e.printStackTrace();
fail();