Browse Source

添加jasperserver api

sunyj 9 years ago
parent
commit
f99d3bc21c

+ 14 - 0
pom.xml

@@ -20,6 +20,8 @@
 		<groovy.version>2.4.7</groovy.version>
 		<poi.version>3.10.1</poi.version>
 		<commons.fileupload.version>1.3.2</commons.fileupload.version>
+		<spring.security.acl.version>4.1.3.RELEASE</spring.security.acl.version>
+		<org.hibernate.core.version>3.3.2.GA</org.hibernate.core.version>
 	</properties>
 
 	<dependencies>
@@ -94,6 +96,18 @@
 			<artifactId>commons-fileupload</artifactId>
 			<version>${commons.fileupload.version}</version>
 		</dependency>
+
+		<!-- jasperserver api 依赖包 -->
+		<dependency>
+			<groupId>org.springframework.security</groupId>
+			<artifactId>spring-security-acl</artifactId>
+			<version>${spring.security.acl.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-core</artifactId>
+			<version>${org.hibernate.core.version}</version>
+		</dependency>
 	</dependencies>
 
 	<build>

+ 32 - 0
src/main/java/com/uas/report/jasperserver/api/common/domain/AttributedObject.java

@@ -0,0 +1,32 @@
+package com.uas.report.jasperserver.api.common.domain;
+
+import java.util.List;
+
+import com.uas.report.jasperserver.api.JasperServerAPI;
+
+/**
+ * Class which implements AttributedObject interface can keep a list of
+ * attributes.
+ *
+ * @author swood
+ * @version $Id: AttributedObject.java 47331 2014-07-18 09:13:06Z kklein $
+ * @since 1.0.1
+ */
+@JasperServerAPI
+public interface AttributedObject {
+
+	/**
+	 * Returns a list of attributes for the object.
+	 *
+	 * @return a list of attributes for the object
+	 */
+	public List getAttributes();
+
+	/**
+	 * Sets a list of attributes for the object.
+	 *
+	 * @param attrs
+	 *            a list of attributes for the object.
+	 */
+	public void setAttributes(List attrs);
+}

+ 68 - 0
src/main/java/com/uas/report/jasperserver/api/common/domain/ExecutionContext.java

@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.common.domain;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+import com.uas.report.jasperserver.api.JasperServerAPI;
+
+/**
+ * Context passed from calling code to the JasperServer APIs.
+ * 
+ * <p>
+ * The context contains general attributes that are used by several JasperServer
+ * API methods.
+ * </p>
+ * 
+ * @author swood
+ * @author Lucian Chirita
+ * @author Ionut Nedelcu
+ * @version $Id: ExecutionContext.java 47331 2014-07-18 09:13:06Z kklein $
+ * @since 1.0
+ */
+@JasperServerAPI
+public interface ExecutionContext extends AttributedObject {
+
+	/**
+	 * Specifies the locale used in the calling code.
+	 * 
+	 * <p>
+	 * The locale is used when localized messages are constructed in API
+	 * methods, and when numerical and date values are formatted to text.
+	 * </p>
+	 * 
+	 * @return the locale used in the calling code
+	 */
+	Locale getLocale();
+
+	/**
+	 * Specifies the timezone used in the calling code.
+	 * 
+	 * <p>
+	 * The timezone is used when displaying date/time values as texts.
+	 * </p>
+	 * 
+	 * @return the timezone used in the calling code
+	 */
+	TimeZone getTimeZone();
+
+}

+ 81 - 0
src/main/java/com/uas/report/jasperserver/api/common/domain/ValidationError.java

@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.common.domain;
+
+import com.uas.report.jasperserver.api.JasperServerAPI;
+
+/**
+ * Error detected when validating objects according to rules defined in various
+ * services.
+ * 
+ * @author Lucian Chirita (lucianc@users.sourceforge.net)
+ * @version $Id: ValidationError.java 47331 2014-07-18 09:13:06Z kklein $
+ * @since 1.0
+ */
+@JasperServerAPI
+public interface ValidationError {
+	
+	/**
+	 * Returns the localization key of the error message.
+	 * 
+	 * <p>
+	 * The localized message is created by looking up the key in the resource
+	 * bundles.
+	 * </p>
+	 * 
+	 * @return the error message key
+	 * @see #getErrorArguments()
+	 * @see #getDefaultMessage()
+	 */
+	String getErrorCode();
+	
+	/**
+	 * Returns a list of values that are used to fill the placeholders in the 
+	 * localized error messages.
+	 * 
+	 * @return the values to use for the localized error message, or
+	 * <code>null</code> if the message does not include values
+	 */
+	Object[] getErrorArguments();
+	
+	/**
+	 * Returns a default message that should be used when the error message key
+	 * is not found in the localization resource bundles.
+	 * 
+	 * @return a default (non localized/English) error message
+	 */
+	String getDefaultMessage();
+	
+	/**
+	 * Returns the specific field of the object that failed to validate.
+	 * 
+	 * <p>
+	 * The field can be used in some cases in addition to the error code to
+	 * construct compound message keys that resolve to localized messages
+	 * specific to the field.
+	 * </p>
+	 * 
+	 * @return the object field that failed the validation, or <code>null</code>
+	 * if the error is not related to a particular field
+	 */
+	String getField();
+	
+}

+ 66 - 0
src/main/java/com/uas/report/jasperserver/api/common/domain/ValidationErrorFilter.java

@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.common.domain;
+
+import com.uas.report.jasperserver.api.JasperServerAPI;
+
+/**
+ * Filter that determines a subset of validation rules to check during a
+ * validation operation.
+ * 
+ * @author Teodor Danciu (teodord@users.sourceforge.net)
+ * @version $Id: ValidationError.java 8408 2007-05-29 23:29:12Z melih $
+ * @since 2.1.0
+ */
+@JasperServerAPI
+public interface ValidationErrorFilter 
+{
+
+	/**
+	 * Decides whether the rules associated to a specific error should
+	 * be checked during a validation operation.
+	 * 
+	 * @param error the error 
+	 * @return whether the specified error should be checked
+	 * @see #matchErrorCode(String)
+	 */
+	boolean matchError(ValidationError error);
+
+
+	/**
+	 * Decides whether the rules associated to a specific error code should
+	 * be checked during a validation operation.
+	 * 
+	 * @param errorCode the error code
+	 * @return whether the specified error should be checked
+	 */
+	boolean matchErrorCode(String errorCode);
+	
+	/**
+	 * Decides whether a specific field of the validation object should be
+	 * checked during the validation.
+	 * 
+	 * @param errorField the object field name
+	 * @return whether the specified field should be checked
+	 */
+	boolean matchErrorField(String errorField);
+
+}

+ 75 - 0
src/main/java/com/uas/report/jasperserver/api/common/domain/ValidationErrors.java

@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.common.domain;
+
+import java.util.List;
+
+import com.uas.report.jasperserver.api.JasperServerAPI;
+
+/**
+ * The result of a validation operation, consisting of a set of validation
+ * errors.
+ * 
+ * @author Lucian Chirita (lucianc@users.sourceforge.net)
+ * @version $Id: ValidationErrors.java 47331 2014-07-18 09:13:06Z kklein $
+ * @since 1.0
+ */
+@JasperServerAPI
+public interface ValidationErrors {
+
+	/**
+	 * Determines whether any error has been detected during the validation.
+	 * 
+	 * @return <code>true</code> if the validation resulted in error(s)
+	 * @see #getErrors()
+	 */
+	boolean isError();
+
+	/**
+	 * Returns the list of errors detected during the validation.
+	 * 
+	 * @return the list of errors detected during the validation, empty if no
+	 *         errors were found
+	 */
+	List getErrors();
+
+	/**
+	 * Adds an error to the list of validation errors.
+	 * 
+	 * @param error
+	 *            the error to add
+	 * @since 1.2.0
+	 */
+	void add(ValidationError error);
+
+	/**
+	 * Removes any previously added errors that match a specified code and
+	 * field.
+	 * 
+	 * @param code
+	 *            the code of the errors to remove
+	 * @param field
+	 *            the field for which errors are to be removed
+	 * @since 3.0.0
+	 */
+	void removeError(String code, String field);
+
+}

+ 57 - 0
src/main/java/com/uas/report/jasperserver/api/metadata/common/domain/util/ComparableBlob.java

@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.metadata.common.domain.util;
+
+import java.sql.Blob;
+
+import org.hibernate.lob.BlobImpl;
+import org.hibernate.lob.SerializableBlob;
+
+public class ComparableBlob extends SerializableBlob {
+	private static final long serialVersionUID = -7928795808929208452L;
+	private byte[] bytes;
+	private transient Blob myBlob;
+
+	public ComparableBlob(byte[] bytes) {
+		super(new BlobImpl(bytes));
+		this.bytes = bytes;
+	}
+
+	// superclass implements Serializable but doesn't actually work after
+	// serialization, so can't be cached.
+	// we are saving the byte[] so we can create blob as needed
+	public Blob getWrappedBlob() {
+		if (myBlob == null) {
+			myBlob = new BlobImpl(bytes);
+		}
+		return myBlob;
+	}
+
+	// same byte array? fine!
+	public boolean equals(Object o) {
+		return o instanceof ComparableBlob && ((ComparableBlob) o).bytes == bytes;
+	}
+
+	public byte[] getBytes() {
+		return bytes;
+	}
+
+}

+ 391 - 0
src/main/java/com/uas/report/jasperserver/api/metadata/common/domain/util/DataContainerStreamUtil.java

@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.metadata.common.domain.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.sql.Blob;
+import java.sql.SQLException;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.bouncycastle.util.Arrays;
+
+import com.uas.report.jasperserver.api.JSException;
+import com.uas.report.jasperserver.api.JSExceptionWrapper;
+import com.uas.report.jasperserver.api.metadata.common.domain.DataContainer;
+
+/**
+ * @author Lucian Chirita (lucianc@users.sourceforge.net)
+ * @version $Id: DataContainerStreamUtil.java 47331 2014-07-18 09:13:06Z kklein
+ *          $
+ */
+public class DataContainerStreamUtil {
+	private static final Log log = LogFactory.getLog(DataContainerStreamUtil.class);
+	private static final int READ_STREAM_BUFFER_SIZE = 10000;
+
+	public static byte[] readData(InputStream is) {
+		if (is == null) {
+			return null;
+		}
+
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+		byte[] bytes = new byte[READ_STREAM_BUFFER_SIZE];
+		int ln = 0;
+		try {
+			while ((ln = is.read(bytes)) > 0) {
+				baos.write(bytes, 0, ln);
+			}
+		} catch (IOException e) {
+			log.error("Error while reading data.", e);
+			throw new JSExceptionWrapper(e);
+		}
+
+		return baos.toByteArray();
+	}
+
+	public static byte[] readDataAndClose(InputStream is) {
+		try {
+			return readData(is);
+		} finally {
+			close(is);
+		}
+	}
+
+	public static byte[] readData(InputStream is, int size) {
+		if (is == null) {
+			return null;
+		}
+
+		try {
+			byte[] data = new byte[size];
+			int offset = 0;
+			while (size > 0) {
+				int read = is.read(data, offset, size);
+				if (read < 0) {
+					throw new JSException("jsexception.input.stream.exhausted", new Object[] { new Integer(size) });
+				}
+				offset += read;
+				size -= read;
+			}
+			return data;
+		} catch (IOException e) {
+			log.error("Error while reading data.", e);
+			throw new JSExceptionWrapper(e);
+		}
+	}
+
+	public static byte[] readData(Blob blob) {
+		if (blob == null) {
+			return null;
+		}
+		// this is ComparableBlob--we can get the bytes
+		if (blob instanceof ComparableBlob) {
+			return ((ComparableBlob) blob).getBytes();
+		}
+
+		try {
+			return readData(blob.getBinaryStream());
+		} catch (SQLException e) {
+			log.error("Error while reading blob data", e);
+			throw new JSExceptionWrapper(e);
+		}
+	}
+
+	public static void pipeData(InputStream is, OutputStream os) throws IOException {
+		if (is == null) {
+			return;
+		}
+
+		byte[] bytes = new byte[READ_STREAM_BUFFER_SIZE];
+		int ln = 0;
+		while ((ln = is.read(bytes)) > 0) {
+			os.write(bytes, 0, ln);
+		}
+	}
+
+	public static void pipeDataAndCloseInput(InputStream is, OutputStream os) throws IOException {
+		try {
+			pipeData(is, os);
+		} finally {
+			close(is);
+		}
+	}
+
+	protected static void close(InputStream is) {
+		try {
+			is.close();
+		} catch (IOException e) {
+			log.warn("Failed to close input stream " + is, e);
+		}
+	}
+
+	public static void writeObjectByteData(ObjectOutputStream objectStream, InputStream data) throws IOException {
+		pipeData(data, objectStream);
+	}
+
+	public static void readObjectByteData(ObjectInputStream objectStream, int size, OutputStream outStream)
+			throws IOException {
+		byte[] buffer = new byte[READ_STREAM_BUFFER_SIZE];
+
+		while (size > 0) {
+			int read = buffer.length;
+			if (read > size) {
+				read = size;
+			}
+			objectStream.readFully(buffer, 0, read);
+
+			outStream.write(buffer, 0, read);
+
+			size -= read;
+		}
+	}
+
+	public static void pipeData(InputStream is, DataContainer dataContainer) {
+		boolean close = true;
+		OutputStream out = dataContainer.getOutputStream();
+		try {
+			pipeData(is, out);
+
+			close = false;
+			out.close();
+		} catch (IOException e) {
+			throw new JSExceptionWrapper(e);
+		} finally {
+			if (close) {
+				try {
+					out.close();
+				} catch (IOException e) {
+					log.error("Error closing stream", e);
+				}
+			}
+		}
+	}
+
+	public static DataContainer pipeGzipSniffedData(InputStream is, DataContainer dataContainer) {
+		GzipSniffInputStream gzipSniffInput = new GzipSniffInputStream(is);
+		pipeData(gzipSniffInput, dataContainer);
+
+		if (gzipSniffInput.isAutoGzip()) {
+			// if the input was gzip, find out the uncompressed length and
+			// create a
+			// data container that transparently inflates the data
+			int uncompressedLength = gzipSniffInput.gzipUncompressedLength();
+			return new GzipDataContainer(dataContainer, uncompressedLength);
+		}
+
+		return dataContainer;
+	}
+
+	protected static class GzipSniffInputStream extends FilterInputStream {
+
+		private static final int LENGTH_TRAILER_SIZE = 4;
+
+		// store the first 2 bytes read
+		private int headerOffset = 0;
+		private final byte[] header = new byte[GZIP_HEADER.length];
+
+		// store the last 4 bytes read as a circular buffer
+		private int trailerOffset = 0;
+		private final byte[] trailer = new byte[LENGTH_TRAILER_SIZE];
+
+		public GzipSniffInputStream(InputStream in) {
+			super(in);
+		}
+
+		private void bufferHeader(byte b) {
+			if (headerOffset < header.length) {
+				header[headerOffset] = b;
+				++headerOffset;
+			}
+		}
+
+		private void bufferHeader(byte[] b, int off, int read) {
+			if (headerOffset < header.length) {
+				int count = Math.min(header.length - headerOffset, read);
+				System.arraycopy(b, off, header, headerOffset, count);
+				headerOffset += count;
+			}
+		}
+
+		private void bufferTrailer(byte b) {
+			trailer[trailerOffset] = b;
+			++trailerOffset;
+			if (trailerOffset == LENGTH_TRAILER_SIZE) {
+				trailerOffset = 0;
+			}
+		}
+
+		private void bufferTrailer(byte[] b, int off, int read) {
+			int lastCount = Math.min(read, LENGTH_TRAILER_SIZE);
+			for (int i = 0; i < lastCount; ++i) {
+				// adding one by one, which is not the fastest way
+				bufferTrailer(b[off + read - lastCount + i]);
+			}
+		}
+
+		@Override
+		public int read() throws IOException {
+			int read = super.read();
+			if (read >= 0) {
+				byte b = (byte) (read & 0xff);
+				bufferHeader(b);
+				bufferTrailer(b);
+			}
+			return read;
+		}
+
+		@Override
+		public int read(byte[] b, int off, int len) throws IOException {
+			int read = super.read(b, off, len);
+			if (read > 0) {
+				bufferHeader(b, off, read);
+				bufferTrailer(b, off, read);
+			}
+			return read;
+		}
+
+		public boolean isAutoGzip() {
+			if (headerOffset < GZIP_HEADER.length) {
+				return false;
+			}
+
+			// check if the header bytes match our gzip header
+			boolean isGzip = Arrays.areEqual(header, GZIP_HEADER);
+
+			if (isGzip && log.isDebugEnabled()) {
+				log.debug("detected gzip stream");
+			}
+
+			return isGzip;
+		}
+
+		public int gzipUncompressedLength() {
+			// the length is the last 4 bytes in little endian order
+			// FIXME this limits to 2^32 bytes, we sould have that check in the
+			// output stream
+			int length = (trailer[trailerOffset] & 0xff)
+					| ((trailer[(trailerOffset + 1) % LENGTH_TRAILER_SIZE] & 0xff) << 8)
+					| ((trailer[(trailerOffset + 2) % LENGTH_TRAILER_SIZE] & 0xff) << 16)
+					| ((trailer[(trailerOffset + 3) % LENGTH_TRAILER_SIZE] & 0xff) << 24);
+
+			if (log.isDebugEnabled()) {
+				log.debug("gzip uncompressed length " + length);
+			}
+
+			return length;
+		}
+	}
+
+	public static DataContainer createCompressedContainer(DataContainer container) {
+		return new GzipDataContainer(container);
+	}
+
+	public static DataContainer getRawDataContainer(DataContainer container) {
+		// ugly cast
+		if (container instanceof GzipDataContainer) {
+			// return the compressed data
+			return ((GzipDataContainer) container).getDecorated();
+		}
+
+		return container;
+	}
+
+	private static final byte[] GZIP_HEADER = new byte[] { (byte) GZIPInputStream.GZIP_MAGIC,
+			(byte) (GZIPInputStream.GZIP_MAGIC >> 8), Deflater.DEFLATED, // Compression
+																			// method
+																			// (CM)
+			16, // using FCOMMENT
+			0, 0, 0, 0, 0, 0, 'j', // the comment
+			'r', 's', 'a', 0, };
+
+	// directly extending DeflaterOutputStream because we are writing a custom
+	// gzip header
+	protected static class CompressedOutputStream extends DeflaterOutputStream {
+		private CRC32 crc;
+
+		public CompressedOutputStream(OutputStream out) throws IOException {
+			// using default compression
+			super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+
+			crc = new CRC32();
+			crc.reset();
+
+			// write the header
+			out.write(GZIP_HEADER);
+		}
+
+		@Override
+		public synchronized void write(byte[] buf, int off, int len) throws IOException {
+			super.write(buf, off, len);
+
+			crc.update(buf, off, len);
+		}
+
+		@Override
+		public void finish() throws IOException {
+			// deflate finish
+			super.finish();
+
+			// write the trailer
+			int crcValue = (int) crc.getValue();
+			int size = getUncompressedSize();
+
+			if (log.isDebugEnabled()) {
+				log.debug("writing gzip trailer for crc " + crcValue + ", length " + size);
+			}
+
+			byte[] trailer = new byte[] { (byte) (crcValue & 0xff), (byte) ((crcValue >> 8) & 0xff),
+					(byte) ((crcValue >> 16) & 0xff), (byte) ((crcValue >> 24) & 0xff), (byte) (size & 0xff),
+					(byte) ((size >> 8) & 0xff), (byte) ((size >> 16) & 0xff), (byte) ((size >> 24) & 0xff), };
+			out.write(trailer);
+		}
+
+		protected int getUncompressedSize() {
+			return def.getTotalIn();
+		}
+	}
+
+	// Methods to create a blob that can be compared successfully for equality
+	// as long as the byte arrays haven't been touched.
+
+	public static Blob createComparableBlob(Blob blob) {
+		return createComparableBlob(DataContainerStreamUtil.readData(blob));
+	}
+
+	public static Blob createComparableBlob(InputStream stream) {
+		return createComparableBlob(DataContainerStreamUtil.readData(stream));
+	}
+
+	public static Blob createComparableBlob(byte[] data) {
+		return new ComparableBlob(data);
+	}
+}

+ 371 - 0
src/main/java/com/uas/report/jasperserver/api/metadata/common/domain/util/FileBufferedOutputStream.java

@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.metadata.common.domain.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.WeakHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.uas.report.jasperserver.api.JSException;
+
+import net.sf.jasperreports.engine.DefaultJasperReportsContext;
+import net.sf.jasperreports.engine.JRPropertiesUtil;
+
+/**
+ * @author Lucian Chirita (lucianc@users.sourceforge.net)
+ * @version $Id: FileBufferedOutputStream.java 61296 2016-02-25 21:53:37Z mchan
+ *          $
+ */
+public class FileBufferedOutputStream extends OutputStream {
+
+	private static final Log log = LogFactory.getLog(FileBufferedOutputStream.class);
+
+	/**
+	 * Specifies the maximum in-memory buffer length that triggers the creation
+	 * of a temporary file on disk to store further content sent to this output
+	 * stream.
+	 */
+	public static final String PROPERTY_MEMORY_THRESHOLD = JRPropertiesUtil.PROPERTY_PREFIX
+			+ "file.buffer.os.memory.threshold";
+	// public static final int DEFAULT_MEMORY_THRESHOLD = 1 << 18;
+	public static final int INFINIT_MEMORY_THRESHOLD = -1;
+	public static final int DEFAULT_INITIAL_MEMORY_BUFFER_SIZE = 1 << 16;
+	public static final int DEFAULT_INPUT_BUFFER_LENGTH = 1 << 14;
+
+	private final int memoryThreshold;
+	private final int initialMemoryBufferSize;
+	private final int inputBufferLength;
+
+	private final ByteArrayOutputStream memoryOutput;
+	private int size;
+	private File file;
+	private BufferedOutputStream fileOutput;
+	private boolean closed;
+	private boolean disposed;
+
+	private final WeakHashMap<DataStream, Boolean> inputStreams;
+
+	public FileBufferedOutputStream() {
+		this(JRPropertiesUtil.getInstance(DefaultJasperReportsContext.getInstance())
+				.getIntegerProperty(PROPERTY_MEMORY_THRESHOLD, INFINIT_MEMORY_THRESHOLD),
+				DEFAULT_INITIAL_MEMORY_BUFFER_SIZE, DEFAULT_INPUT_BUFFER_LENGTH);
+	}
+
+	public FileBufferedOutputStream(int memoryThreshold) {
+		this(memoryThreshold, DEFAULT_INITIAL_MEMORY_BUFFER_SIZE, DEFAULT_INPUT_BUFFER_LENGTH);
+	}
+
+	public FileBufferedOutputStream(int memoryThreshold, int initialMemoryBufferSize) {
+		this(memoryThreshold, initialMemoryBufferSize, DEFAULT_INPUT_BUFFER_LENGTH);
+	}
+
+	public FileBufferedOutputStream(int memoryThreshold, int initialMemoryBufferSize, int inputBufferLength) {
+		this.memoryThreshold = memoryThreshold;
+		this.initialMemoryBufferSize = initialMemoryBufferSize;
+		this.inputBufferLength = inputBufferLength;
+
+		size = 0;
+		if (this.memoryThreshold == 0) {
+			memoryOutput = null;
+		} else {
+			int initialSize = this.initialMemoryBufferSize;
+			if (initialSize > this.memoryThreshold) {
+				initialSize = this.memoryThreshold;
+			}
+			memoryOutput = new ByteArrayOutputStream(initialSize);
+		}
+
+		this.inputStreams = new WeakHashMap<DataStream, Boolean>();
+	}
+
+	public void write(int b) throws IOException {
+		checkClosed();
+
+		if (availableMemorySpace() > 0) {
+			memoryOutput.write(b);
+		} else {
+			ensureFileOutput().write(b);
+		}
+
+		++size;
+	}
+
+	protected int availableMemorySpace() {
+		int availableMemorySpace;
+		if (memoryOutput != null && (memoryThreshold < 0 || memoryOutput.size() < memoryThreshold)) {
+			availableMemorySpace = memoryThreshold - memoryOutput.size();
+		} else {
+			availableMemorySpace = 0;
+		}
+		return availableMemorySpace;
+	}
+
+	protected BufferedOutputStream ensureFileOutput() throws IOException, FileNotFoundException {
+		if (fileOutput == null) {
+			file = File.createTempFile("file.buff.os.", ".tmp");
+			FileOutputStream fileOutputStream = new FileOutputStream(file);
+			fileOutput = new BufferedOutputStream(fileOutputStream);
+		}
+		return fileOutput;
+	}
+
+	public void write(byte[] b, int off, int len) throws IOException {
+		checkClosed();
+
+		int memoryLen = availableMemorySpace();
+		if (len < memoryLen) {
+			memoryLen = len;
+		}
+
+		if (memoryLen > 0) {
+			memoryOutput.write(b, off, memoryLen);
+		}
+
+		if (memoryLen < len) {
+			ensureFileOutput().write(b, off + memoryLen, len - memoryLen);
+		}
+
+		size += len;
+	}
+
+	public void checkClosed() {
+		if (closed) {
+			throw new JSException("Output stream already closed.");
+		}
+	}
+
+	public void close() throws IOException {
+		if (!closed && fileOutput != null) {
+			fileOutput.flush();
+			fileOutput.close();
+		}
+
+		closed = true;
+	}
+
+	public void flush() throws IOException {
+		if (fileOutput != null) {
+			fileOutput.flush();
+		}
+	}
+
+	public int size() {
+		return size;
+	}
+
+	public void writeData(OutputStream out) throws IOException {
+		if (!closed) {
+			close();
+		}
+
+		if (memoryOutput != null) {
+			memoryOutput.writeTo(out);
+		}
+
+		if (file != null) {
+			FileInputStream fileInput = new FileInputStream(file);
+			boolean inputClosed = false;
+			try {
+				byte[] buffer = new byte[inputBufferLength];
+				int read;
+				while ((read = fileInput.read(buffer)) > 0) {
+					out.write(buffer, 0, read);
+				}
+				fileInput.close();
+				inputClosed = true;
+			} finally {
+				if (!inputClosed) {
+					try {
+						fileInput.close();
+					} catch (IOException e) {
+						log.warn("Could not close file input stream", e);
+					}
+				}
+			}
+		}
+	}
+
+	public void dispose() {
+		if (disposed) {
+			return;
+		}
+
+		boolean success = true;
+		if (!closed && fileOutput != null) {
+			try {
+				fileOutput.close();
+			} catch (IOException e) {
+				log.warn("Error while closing the temporary file output stream", e);
+				success = false;
+			}
+		}
+
+		for (DataStream dataStream : inputStreams.keySet()) {
+			try {
+				dataStream.close();
+			} catch (IOException e) {
+				log.warn("Error while closing temporary file input stream", e);
+				success = false;
+			}
+		}
+
+		if (file != null && !file.delete()) {
+			log.warn("Error while deleting the temporary file");
+			success = false;
+		}
+
+		disposed = success;
+	}
+
+	protected void finalize() throws Throwable {
+		dispose();
+		super.finalize();
+	}
+
+	public InputStream getDataInputStream() throws IOException {
+		if (!closed) {
+			close();
+		}
+
+		DataStream dataStream = new DataStream();
+		// keep for dispose()
+		inputStreams.put(dataStream, Boolean.TRUE);
+		return dataStream;
+	}
+
+	protected class DataStream extends InputStream {
+		private int memoryIdx;
+		private int memoryLength;
+
+		private final InputStream byteInputStream;
+		private final InputStream fileInput;
+
+		public DataStream() throws FileNotFoundException, IOException {
+			memoryIdx = 0;
+			byte[] memoryData = memoryOutput == null ? new byte[0] : memoryOutput.toByteArray();
+			memoryLength = memoryData.length;
+			byteInputStream = new ByteArrayInputStream(memoryData);
+			fileInput = file == null ? null : new BufferedInputStream(new FileInputStream(file));
+		}
+
+		public synchronized int read() throws IOException {
+			int read;
+
+			if (memoryIdx < memoryLength) {
+				read = byteInputStream.read();
+				++memoryIdx;
+			} else if (fileInput != null) {
+				read = fileInput.read();
+			} else {
+				read = -1;
+			}
+			return read;
+		}
+
+		public synchronized int read(byte b[], int off, int len) throws IOException {
+			if (len <= 0) {
+				return 0;
+			}
+
+			int read;
+			if (memoryIdx < memoryLength) {
+				read = len;
+				if (read > memoryLength - memoryIdx) {
+					read = memoryLength - memoryIdx;
+				}
+
+				byteInputStream.read(b, off, read);
+				memoryIdx += read;
+
+			} else {
+				read = 0;
+			}
+
+			if (read < len && fileInput != null) {
+				int readFile = fileInput.read(b, off + read, len - read);
+				if (readFile > 0) {
+					read += readFile;
+				}
+			}
+
+			return read == 0 ? -1 : read;
+		}
+
+		public void close() throws IOException {
+
+			if (fileInput != null) {
+				fileInput.close();
+			}
+		}
+
+		public synchronized int available() throws IOException {
+			int available = byteInputStream.available();
+			if (fileInput != null) {
+				available += fileInput.available();
+			}
+
+			return available;
+		}
+
+		public synchronized long skip(long n) throws IOException {
+			if (n <= 0) {
+				return 0;
+			}
+
+			long skipped;
+			if (memoryIdx < memoryLength) {
+				skipped = n;
+				if (skipped > memoryLength - memoryIdx) {
+					skipped = memoryLength - memoryIdx;
+				}
+
+				skipped = byteInputStream.skip(skipped);
+				memoryIdx += skipped;
+			} else {
+				skipped = 0;
+			}
+
+			if (skipped < n && fileInput != null) {
+				skipped += fileInput.skip(n - skipped);
+			}
+
+			return skipped;
+		}
+
+		protected void finalize() throws Throwable {
+			close();
+			super.finalize();
+		}
+
+	}
+}

+ 120 - 0
src/main/java/com/uas/report/jasperserver/api/metadata/common/domain/util/GzipDataContainer.java

@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
+ * http://www.jaspersoft.com.
+ *
+ * Unless you have purchased  a commercial license agreement from Jaspersoft,
+ * the following license terms  apply:
+ *
+ * This program is free software: you can redistribute it and/or  modify
+ * it under the terms of the GNU Affero General Public License  as
+ * published by the Free Software Foundation, either version 3 of  the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero  General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public  License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.uas.report.jasperserver.api.metadata.common.domain.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.uas.report.jasperserver.api.JSExceptionWrapper;
+import com.uas.report.jasperserver.api.metadata.common.domain.DataContainer;
+
+/**
+ * @author Lucian Chirita (lucianc@users.sourceforge.net)
+ * @version $Id: GzipDataContainer.java 47331 2014-07-18 09:13:06Z kklein $
+ */
+public class GzipDataContainer implements DataContainer {
+
+	private static final Log log = LogFactory.getLog(GzipDataContainer.class);
+
+	private final DataContainer decorated;
+
+	private DataContainerStreamUtil.CompressedOutputStream compressedOut;
+	private int uncompressedSize;
+
+	public GzipDataContainer(DataContainer decorated) {
+		this.decorated = decorated;
+	}
+
+	public GzipDataContainer(DataContainer decorated, int uncompressedSize) {
+		this(decorated);
+		this.uncompressedSize = uncompressedSize;
+	}
+
+	public boolean hasData() {
+		return decorated.hasData();
+	}
+
+	public OutputStream getOutputStream() {
+		if (compressedOut == null) {
+			OutputStream out = decorated.getOutputStream();
+			try {
+				compressedOut = new DataContainerStreamUtil.CompressedOutputStream(out) {
+					@Override
+					public void close() throws IOException {
+						super.close();
+
+						// set the final uncompressed size
+						GzipDataContainer.this.uncompressedSize = getUncompressedSize();
+					}
+				};
+				return compressedOut;
+			} catch (IOException e) {
+				throw new JSExceptionWrapper(e);
+			}
+		}
+
+		return compressedOut;
+	}
+
+	public int dataSize() {
+		return uncompressedSize;
+	}
+
+	public InputStream getInputStream() {
+		InputStream in = decorated.getInputStream();
+		if (in == null) {
+			return null;
+		}
+
+		try {
+			return new GZIPInputStream(in);
+		} catch (IOException e) {
+			throw new JSExceptionWrapper(e);
+		}
+	}
+
+	public byte[] getData() {
+		return DataContainerStreamUtil.readDataAndClose(getInputStream());
+	}
+
+	public DataContainer getDecorated() {
+		return decorated;
+	}
+
+	public void dispose() {
+		if (compressedOut != null) {
+			try {
+				compressedOut.close();
+			} catch (IOException e) {
+				if (log.isDebugEnabled()) {
+					log.debug("Failed to close output stream", e);
+				}
+			}
+		}
+
+		decorated.dispose();
+	}
+}