Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  //
  //  ========================================================================
  //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
  //  ------------------------------------------------------------------------
  //  All rights reserved. This program and the accompanying materials
  //  are made available under the terms of the Eclipse Public License v1.0
  //  and Apache License v2.0 which accompanies this distribution.
  //
  //      The Eclipse Public License is available at
 //      http://www.eclipse.org/legal/epl-v10.html
 //
 //      The Apache License v2.0 is available at
 //      http://www.opensource.org/licenses/apache2.0.php
 //
 //  You may elect to redistribute this code under either of these licenses.
 //  ========================================================================
 //
 
 package org.eclipse.jetty.proxy;
 
 import java.util.List;
 

A specialized transformer for AsyncMiddleManServlet that performs the transformation when the whole content has been received.

The content is buffered in memory up to a configurable maximum size, after which it is overflown to a file on disk. The overflow file is saved in the overflow directory as a temporary file with a name starting with the input prefix and default suffix.

Application must implement the transformation method to transform the content.

The transformed content is buffered in memory up to a configurable maximum size after which it is overflown to a file on disk. The overflow file is saved in the overflow directory as a temporary file with a name starting with the getOutputFilePrefix() output prefix} and default suffix.

 
 {
     private static final Logger LOG = Log.getLogger(AfterContentTransformer.class);
 
     private final List<ByteBuffersourceBuffers = new ArrayList<>();
     private Path overflowDirectory = Paths.get(System.getProperty("java.io.tmpdir"));
     private String inputFilePrefix = "amms_adct_in_";
     private String outputFilePrefix = "amms_adct_out_";
     private long maxInputBufferSize = 1024 * 1024;
     private long inputBufferSize;
     private FileChannel inputFile;
     private long maxOutputBufferSize = ;
     private long outputBufferSize;
     private FileChannel outputFile;

    

Returns the directory where input and output are overflown to temporary files if they exceed, respectively, the max input size or the max output size.

Defaults to the directory pointed by the java.io.tmpdir system property.

Returns:
the overflow directory path
See also:
setOverflowDirectory(java.nio.file.Path)
 
     public Path getOverflowDirectory()
     {
         return ;
     }

    

Parameters:
overflowDirectory the overflow directory path
See also:
getOverflowDirectory()
 
     public void setOverflowDirectory(Path overflowDirectory)
     {
         this. = overflowDirectory;
     }

    

Returns:
the prefix of the input overflow temporary files
See also:
setInputFilePrefix(java.lang.String)
    public String getInputFilePrefix()
    {
        return ;
    }

    

Parameters:
inputFilePrefix the prefix of the input overflow temporary files
See also:
getInputFilePrefix()
    public void setInputFilePrefix(String inputFilePrefix)
    {
        this. = inputFilePrefix;
    }

    

Returns the maximum input buffer size, after which the input is overflown to disk.

Defaults to 1 MiB, i.e. 1048576 bytes.

Returns:
the max input buffer size
See also:
setMaxInputBufferSize(long)
    public long getMaxInputBufferSize()
    {
        return ;
    }

    

Parameters:
maxInputBufferSize the max input buffer size
See also:
getMaxInputBufferSize()
    public void setMaxInputBufferSize(long maxInputBufferSize)
    {
        this. = maxInputBufferSize;
    }

    

Returns:
the prefix of the output overflow temporary files
See also:
setOutputFilePrefix(java.lang.String)
    public String getOutputFilePrefix()
    {
        return ;
    }

    

Parameters:
outputFilePrefix the prefix of the output overflow temporary files
See also:
getOutputFilePrefix()
    public void setOutputFilePrefix(String outputFilePrefix)
    {
        this. = outputFilePrefix;
    }

    

Returns the maximum output buffer size, after which the output is overflown to disk.

Defaults to 1 MiB, i.e. 1048576 bytes.

Returns:
the max output buffer size
See also:
setMaxOutputBufferSize(long)
    public long getMaxOutputBufferSize()
    {
        return ;
    }

    

Parameters:
maxOutputBufferSize the max output buffer size
    public void setMaxOutputBufferSize(long maxOutputBufferSize)
    {
        this. = maxOutputBufferSize;
    }
    @Override
    public final void transform(ByteBuffer inputboolean finishedList<ByteBufferoutputthrows IOException
    {
        int remaining = input.remaining();
        if (remaining > 0)
        {
             += remaining;
            long max = getMaxInputBufferSize();
            if (max >= 0 &&  > max)
            {
                overflow(input);
            }
            else
            {
                ByteBuffer copy = ByteBuffer.allocate(input.remaining());
                copy.put(input).flip();
                .add(copy);
            }
        }
        if (finished)
        {
            Source source = new Source();
            Sink sink = new Sink();
            if (transform(sourcesink))
                sink.drainTo(output);
            else
                source.drainTo(output);
        }
    }

    

Transforms the original content read from the source into transformed content written to the sink.

The transformation must happen synchronously in the context of a call to this method (it is not supported to perform the transformation in another thread spawned during the call to this method).

Differently from transform(java.nio.ByteBuffer,boolean,java.util.List), this method is invoked only when the whole content is available, and offers a blocking API via the InputStream and OutputStream that can be obtained from AfterContentTransformer.Source and AfterContentTransformer.Sink respectively.

Implementations may read the source, inspect the input bytes and decide that no transformation is necessary, and therefore the source must be copied unchanged to the sink. In such case, the implementation must return false to indicate that it wishes to just pipe the bytes from the source to the sink.

Typical implementations:

 // Identity transformation (no transformation, the input is copied to the output)
 public boolean transform(Source source, Sink sink)
 {
     org.eclipse.jetty.util.IO.copy(source.getInputStream(), sink.getOutputStream());
     return true;
 }
 

Parameters:
source where the original content is read
sink where the transformed content is written
Returns:
true if the transformation happened and the transformed bytes have been written to the sink, false if no transformation happened and the source must be copied to the sink.
Throws:
java.io.IOException if the transformation fails
    public abstract boolean transform(Source sourceSink sinkthrows IOException;
    private void overflow(ByteBuffer inputthrows IOException
    {
        if ( == null)
        {
            Path path = Files.createTempFile(getOverflowDirectory(), getInputFilePrefix(), null);
             = FileChannel.open(path,
                    .,
                    .,
                    .,
                    .);
            int size = .size();
            if (size > 0)
            {
                ByteBuffer[] buffers = .toArray(new ByteBuffer[size]);
                .clear();
                IO.write(,buffers,0,buffers.length);
            }
        }
        .write(input);
    }
    @Override
    public void destroy()
    {
        close();
        close();
    }
    private void drain(FileChannel fileList<ByteBufferoutputthrows IOException
    {
        long position = 0;
        long length = file.size();
        file.position(position);
        while (length > 0)
        {
            // At most 1 GiB file maps.
            long size = Math.min(1024 * 1024 * 1024, length);
            ByteBuffer buffer = file.map(..positionsize);
            output.add(buffer);
            position += size;
            length -= size;
        }
    }
    private void close(Closeable closeable)
    {
        try
        {
            if (closeable != null)
                closeable.close();
        }
        catch (IOException x)
        {
            .ignore(x);
        }
    }

    

The source from where the original content is read to be transformed.

The input stream provided by this class supports the java.io.InputStream.reset() method so that the stream can be rewound to the beginning.

    public class Source
    {
        private final InputStream stream;
        private Source() throws IOException
        {
            if ( != null)
            {
                .force(true);
                 = new ChannelInputStream();
            }
            else
            {
                 = new MemoryInputStream();
            }
            .reset();
        }

        

Returns:
an input stream to read the original content from
        public InputStream getInputStream()
        {
            return ;
        }
        private void drainTo(List<ByteBufferoutputthrows IOException
        {
            if ( == null)
            {
                output.addAll();
                .clear();
            }
            else
            {
                drain(output);
            }
        }
    }
    private class ChannelInputStream extends InputStream
    {
        private final InputStream stream = Channels.newInputStream();
        @Override
        public int read(byte[] bint offint lenthrows IOException
        {
            return .read(bofflen);
        }
        @Override
        public int read() throws IOException
        {
            return .read();
        }
        @Override
        public void reset() throws IOException
        {
            .position(0);
        }
    }
    private class MemoryInputStream extends InputStream
    {
        private final byte[] oneByte = new byte[1];
        private int index;
        private ByteBuffer slice;
        @Override
        public int read(byte[] bint offint lenthrows IOException
        {
            if (len == 0)
                return 0;
            if ( == .size())
                return -1;
            if ( == null)
                 = .get().slice();
            int size = Math.min(len.remaining());
            .get(boffsize);
            if (!.hasRemaining())
            {
                ++;
                 = null;
            }
            return size;
        }
        @Override
        public int read() throws IOException
        {
            int read = read(, 0, 1);
            return read < 0 ? read : [0] & 0xFF;
        }
        @Override
        public void reset() throws IOException
        {
             = 0;
             = null;
        }
    }

    

The target to where the transformed content is written after the transformation.

    public class Sink
    {
        private final List<ByteBuffersinkBuffers = new ArrayList<>();
        private final OutputStream stream = new SinkOutputStream();

        

Returns:
an output stream to write the transformed content to
        public OutputStream getOutputStream()
        {
            return ;
        }
        
        private void overflow(ByteBuffer outputthrows IOException
        {
            if ( == null)
            {
                Path path = Files.createTempFile(getOverflowDirectory(), getOutputFilePrefix(), null);
                 = FileChannel.open(path,
                        .,
                        .,
                        .,
                        .);
                int size = .size();
                if (size > 0)
                {
                    ByteBuffer[] buffers = .toArray(new ByteBuffer[size]);
                    .clear();
                    
                    IO.write(,buffers,0,buffers.length);
                }
            }
            .write(output);
        }
        private void drainTo(List<ByteBufferoutputthrows IOException
        {
            if ( == null)
            {
                output.addAll();
                .clear();
            }
            else
            {
                .force(true);
                drain(output);
            }
        }
        private class SinkOutputStream extends OutputStream
        {
            @Override
            public void write(byte[] bint offint lenthrows IOException
            {
                if (len <= 0)
                    return;
                 += len;
                long max = getMaxOutputBufferSize();
                if (max >= 0 &&  > max)
                {
                    overflow(ByteBuffer.wrap(bofflen));
                }
                else
                {
                    // The array may be reused by the
                    // application so we need to copy it.
                    byte[] copy = new byte[len];
                    System.arraycopy(boffcopy, 0, len);
                    .add(ByteBuffer.wrap(copy));
                }
            }
            @Override
            public void write(int bthrows IOException
            {
                write(new byte[]{(byte)b}, 0, 1);
            }
        }
    }
New to GrepCode? Check out our FAQ X