alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Jetty example source code file (Ajp13Generator.java)

This example Jetty source code file (Ajp13Generator.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Jetty tags/keywords

a, b, buffer, buffer, flushing, full, illegalstateexception, illegalstateexception, io, ioexception, ioexception, server, state_end, state_end, state_flushing, util

The Jetty Ajp13Generator.java source code

//========================================================================
//Copyright 2006 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed 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.mortbay.jetty.ajp;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;

import org.mortbay.io.Buffer;
import org.mortbay.io.Buffers;
import org.mortbay.io.ByteArrayBuffer;
import org.mortbay.io.EndPoint;
import org.mortbay.jetty.*;
import org.mortbay.jetty.HttpFields.Field;
import org.mortbay.log.Log;
import org.mortbay.util.TypeUtil;

/**
 * @author lagdeppa (at) exist.com
 * @author Greg Wilkins
 */                                                                                                       
public class Ajp13Generator extends AbstractGenerator
{
    private static HashMap __headerHash = new HashMap();

    static
    {
        byte[] xA001 =
        { (byte) 0xA0, (byte) 0x01 };
        byte[] xA002 =
        { (byte) 0xA0, (byte) 0x02 };
        byte[] xA003 =
        { (byte) 0xA0, (byte) 0x03 };
        byte[] xA004 =
        { (byte) 0xA0, (byte) 0x04 };
        byte[] xA005 =
        { (byte) 0xA0, (byte) 0x05 };
        byte[] xA006 =
        { (byte) 0xA0, (byte) 0x06 };
        byte[] xA007 =
        { (byte) 0xA0, (byte) 0x07 };
        byte[] xA008 =
        { (byte) 0xA0, (byte) 0x08 };
        byte[] xA009 =
        { (byte) 0xA0, (byte) 0x09 };
        byte[] xA00A =
        { (byte) 0xA0, (byte) 0x0A };
        byte[] xA00B =
        { (byte) 0xA0, (byte) 0x0B };
        __headerHash.put("Content-Type", xA001);
        __headerHash.put("Content-Language", xA002);
        __headerHash.put("Content-Length", xA003);
        __headerHash.put("Date", xA004);
        __headerHash.put("Last-Modified", xA005);
        __headerHash.put("Location", xA006);
        __headerHash.put("Set-Cookie", xA007);
        __headerHash.put("Set-Cookie2", xA008);
        __headerHash.put("Servlet-Engine", xA009);
        __headerHash.put("Status", xA00A);
        __headerHash.put("WWW-Authenticate", xA00B);

    }

    // A, B ajp response header
    // 0, 1 ajp int 1 packet length
    // 9 CPONG response Code
    private static final byte[] AJP13_CPONG_RESPONSE =
    { 'A', 'B', 0, 1, 9};

    private static final byte[] AJP13_END_RESPONSE =
    { 'A', 'B', 0, 2, 5, 1 };

    // AB ajp respose
    // 0, 3 int = 3 packets in length
    // 6, send signal to get more data
    // 31, -7 byte values for int 8185 = (8 * 1024) - 7 MAX_DATA
    private static final byte[] AJP13_MORE_CONTENT =
    { 'A', 'B', 0, 3, 6, 31, -7 };

    private static String SERVER = "Server: Jetty(6.0.x)";

    public static void setServerVersion(String version)
    {
        SERVER = "Jetty(" + version + ")";
    }

    /* ------------------------------------------------------------ */
    private boolean _expectMore = false;

    private boolean _needMore = false;

    private boolean _needEOC = false;

    private boolean _bufferPrepared = false;

    /* ------------------------------------------------------------ */
    public Ajp13Generator(Buffers buffers, EndPoint io, int headerBufferSize, int contentBufferSize)
    {
        super(buffers, io, headerBufferSize, contentBufferSize);
    }

    /* ------------------------------------------------------------ */
    public void reset(boolean returnBuffers)
    {
        super.reset(returnBuffers);

        _needEOC = false;
        _needMore = false;
        _expectMore = false;
        _bufferPrepared = false;
        _last=false;



        _state = STATE_HEADER;

        _status = 0;
        _version = HttpVersions.HTTP_1_1_ORDINAL;
        _reason = null;
        _method = null;
        _uri = null;

        _contentWritten = 0;
        _contentLength = HttpTokens.UNKNOWN_CONTENT;
        _last = false;
        _head = false;
        _noContent = false;
        _close = false;


       

       _header = null; // Buffer for HTTP header (and maybe small _content)
       _buffer = null; // Buffer for copy of passed _content
       _content = null; // Buffer passed to addContent


    }

    /* ------------------------------------------------------------ */
    /**
     * Add content.
     * 
     * @param content
     * @param last
     * @throws IllegalArgumentException
     *             if <code>content is
     *             {@link Buffer#isImmutable immutable}.
     * @throws IllegalStateException
     *             If the request is not expecting any more content, or if the
     *             buffers are full and cannot be flushed.
     * @throws IOException
     *             if there is a problem flushing the buffers.
     */
    public void addContent(Buffer content, boolean last) throws IOException
    {
        if (_noContent)
        {
            content.clear();
            return;
        }

        if (content.isImmutable())
            throw new IllegalArgumentException("immutable");

        if (_last || _state == STATE_END)
        {
            Log.debug("Ignoring extra content {}", content);
            content.clear();
            return;
        }
        _last = last;

        if(!_endp.isOpen())
        {
            _state = STATE_END;
            return;
        }

        // Handle any unfinished business?
        if (_content != null && _content.length() > 0)
        {

            flush();
            if (_content != null && _content.length() > 0)
                throw new IllegalStateException("FULL");
        }

        _content = content;

        _contentWritten += content.length();

        // Handle the _content
        if (_head)
        {

            content.clear();
            _content = null;
        }
        else
        {
            // Yes - so we better check we have a buffer
            initContent();
            // Copy _content to buffer;
            int len = 0;
            len = _buffer.put(_content);

            // make sure there is space for a trailing null
            if (len > 0 && _buffer.space() == 0)
            {
                len--;
                _buffer.setPutIndex(_buffer.putIndex() - 1);
            }

            _content.skip(len);

            if (_content.length() == 0)
                _content = null;
        }
    }

    /* ------------------------------------------------------------ */
    /**
     * Add content.
     * 
     * @param b
     *            byte
     * @return true if the buffers are full
     * @throws IOException
     */
    public boolean addContent(byte b) throws IOException
    {

        if (_noContent)
            return false;

        if (_last || _state == STATE_END)
            throw new IllegalStateException("Closed");


        if(!_endp.isOpen())
        {
            _state = STATE_END;
            return false;
        }

        // Handle any unfinished business?
        if (_content != null && _content.length() > 0)
        {
            flush();
            if (_content != null && _content.length() > 0)
                throw new IllegalStateException("FULL");
        }

        _contentWritten++;

        // Handle the _content
        if (_head)
            return false;

        // we better check we have a buffer
        initContent();

        // Copy _content to buffer;

        _buffer.put(b);

        return _buffer.space() <= 1;
    }

    /* ------------------------------------------------------------ */
    /**
     * Prepare buffer for unchecked writes. Prepare the generator buffer to
     * receive unchecked writes
     * 
     * @return the available space in the buffer.
     * @throws IOException
     */
    protected int prepareUncheckedAddContent() throws IOException
    {
        if (_noContent)
            return -1;

        if (_last || _state == STATE_END)
            throw new IllegalStateException("Closed");


        if(!_endp.isOpen())
        {
            _state = STATE_END;
            return -1;
        }

        // Handle any unfinished business?
        Buffer content = _content;
        if (content != null && content.length() > 0)
        {
            flush();
            if (content != null && content.length() > 0)
                throw new IllegalStateException("FULL");
        }

        // we better check we have a buffer
        initContent();

        _contentWritten -= _buffer.length();

        // Handle the _content
        if (_head)
            return Integer.MAX_VALUE;

        return _buffer.space() - 1;
    }

    /* ------------------------------------------------------------ */
    public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
    {
        if (_state != STATE_HEADER)
            return;

        if (_last && !allContentAdded)
            throw new IllegalStateException("last?");
        _last = _last | allContentAdded;

        boolean has_server = false;
        if (_version == HttpVersions.HTTP_1_0_ORDINAL)
            _close = true;

        // get a header buffer
        if (_header == null)
            _header = _buffers.getBuffer(_headerBufferSize);

        Buffer tmpbuf = _buffer;
        _buffer = _header;

        try
        {
            // start the header
            _buffer.put((byte) 'A');
            _buffer.put((byte) 'B');
            addInt(0);
            _buffer.put((byte) 0x4);
            addInt(_status);
            if (_reason == null)
                _reason = getReasonBuffer(_status);
            if (_reason == null)
                _reason = new ByteArrayBuffer(TypeUtil.toString(_status));
            addBuffer(_reason);

            if (_status == 100 || _status == 204 || _status == 304)
            {
                _noContent = true;
                _content = null;
            }


            // allocate 2 bytes for number of headers
            int field_index = _buffer.putIndex();
            addInt(0);

            int num_fields = 0;

            if (fields != null)
            { 
                // Add headers
                Iterator i = fields.getFields();

                while (i.hasNext())
                {
                    num_fields++;
                    Field f = (Field) i.next();

                    byte[] codes = (byte[]) __headerHash.get(f.getName());
                    if (codes != null)
                    {
                        _buffer.put(codes);
                    }
                    else
                    {
                        addString(f.getName());
                    }
                    addString(f.getValue());
                }
            }

            if (!has_server && _status > 100 && getSendServerVersion())
            {
                num_fields++;
                addString("Server");
                addString(SERVER);
            }

            // TODO Add content length if last content known.

            // insert the number of headers
            int tmp = _buffer.putIndex();
            _buffer.setPutIndex(field_index);
            addInt(num_fields);
            _buffer.setPutIndex(tmp);

            // get the payload size ( - 4 bytes for the ajp header)
            // excluding the
            // ajp header
            int payloadSize = _buffer.length() - 4;
            // insert the total packet size on 2nd and 3rd byte that
            // was previously
            // allocated
            addInt(2, payloadSize);
        }
        finally
        {
            _buffer = tmpbuf;
        }


        _state = STATE_CONTENT;

    }

    /* ------------------------------------------------------------ */
    /**
     * Complete the message.
     * 
     * @throws IOException
     */
    public void complete() throws IOException
    {
        if (_state == STATE_END)
            return;

        super.complete();

        if (_state < STATE_FLUSHING)
        {
            _state = STATE_FLUSHING;
            _needEOC = true;
        }

        flush();
    }

    /* ------------------------------------------------------------ */
    public long flush() throws IOException
    {
        try
        {
            if (_state == STATE_HEADER  && !_expectMore)
                throw new IllegalStateException("State==HEADER");
            prepareBuffers();

            if (_endp == null)
            {
                // TODO - probably still needed!
                // if (_rneedMore && _buffe != null)
                // {
                // if(!_hasSentEOC)
                // _buffer.put(AJP13_MORE_CONTENT);
                // }
                if (!_expectMore && _needEOC && _buffer != null)
                {
                    _buffer.put(AJP13_END_RESPONSE);
                }
                _needEOC = false;
                return 0;
            }

            // Keep flushing while there is something to flush
            // (except break below)
            int total = 0;
            long last_len = -1;
            Flushing: while (true)
            {
                int len = -1;
                int to_flush = ((_header != null && _header.length() > 0) ? 4 : 0) | ((_buffer != null && _buffer.length() > 0) ? 2 : 0);
                

                switch (to_flush)
                {
                case 7:
                    throw new IllegalStateException(); // should
                    // never
                    // happen!
                case 6:
                    len = _endp.flush(_header, _buffer, null);

                    break;
                case 5:
                    throw new IllegalStateException(); // should
                    // never
                    // happen!
                case 4:
                    len = _endp.flush(_header);
                    break;
                case 3:
                    throw new IllegalStateException(); // should
                    // never
                    // happen!
                case 2:
                    len = _endp.flush(_buffer);

                    break;
                case 1:
                    throw new IllegalStateException(); // should
                    // never
                    // happen!
                case 0:
                {
                    // Nothing more we can write now.
                    if (_header != null)
                        _header.clear();

                    _bufferPrepared = false;

                    if (_buffer != null)
                    {
                        _buffer.clear();

                        // reserve some space for the
                        // header
                        _buffer.setPutIndex(7);
                        _buffer.setGetIndex(7);

                        // Special case handling for
                        // small left over buffer from
                        // an addContent that caused a
                        // buffer flush.
                        if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
                        {

                            _buffer.put(_content);
                            _content.clear();
                            _content = null;
                            break Flushing;
                        }

                    }



                    // Are we completely finished for now?
                    if (!_expectMore && !_needEOC && (_content == null || _content.length() == 0))
                    {
                        if (_state == STATE_FLUSHING)
                            _state = STATE_END;

//                        if (_state == STATE_END)
//                        {
//                            _endp.close();
//                        }
//

                        break Flushing;
                    }

                    // Try to prepare more to write.
                    prepareBuffers();
                }
                }

                // If we failed to flush anything twice in a row
                // break
                if (len <= 0)
                {
                    if (last_len <= 0)
                        break Flushing;
                    break;
                }
                last_len = len;
                total += len;
            }



            return total;
        }
        catch (IOException e)
        {
            Log.ignore(e);
            throw (e instanceof EofException) ? e : new EofException(e);
        }

    }

    /* ------------------------------------------------------------ */
    private void prepareBuffers()
    {
        if (!_bufferPrepared)
        {

            // Refill buffer if possible
            if (_content != null && _content.length() > 0 && _buffer != null && _buffer.space() > 0)
            {

                int len = _buffer.put(_content);

                // Make sure there is space for a trailing null
                if (len > 0 && _buffer.space() == 0)
                {
                    len--;
                    _buffer.setPutIndex(_buffer.putIndex() - 1);
                }
                _content.skip(len);

                if (_content.length() == 0)
                    _content = null;

                if (_buffer.length() == 0)
                {
                    _content = null;
                }
            }

            // add header if needed
            if (_buffer != null)
            {

                int payloadSize = _buffer.length();

                // 4 bytes for the ajp header
                // 1 byte for response type
                // 2 bytes for the response size
                // 1 byte because we count from zero??

                if (payloadSize > 0)
                {
                    _bufferPrepared = true;

                    _buffer.put((byte) 0);
                    int put = _buffer.putIndex();
                    _buffer.setGetIndex(0);
                    _buffer.setPutIndex(0);
                    _buffer.put((byte) 'A');
                    _buffer.put((byte) 'B');
                    addInt(payloadSize + 4);
                    _buffer.put((byte) 3);
                    addInt(payloadSize);
                    _buffer.setPutIndex(put);
                }
            }

            if (_needMore)
            {

                if (_header == null)
                {
                    _header = _buffers.getBuffer(_headerBufferSize);
                }

                if (_buffer == null && _header != null && _header.space() >= AJP13_MORE_CONTENT.length)
                {
                    _header.put(AJP13_MORE_CONTENT);
                    _needMore = false;
                }
                else if (_buffer != null && _buffer.space() >= AJP13_MORE_CONTENT.length)
                {
                    // send closing packet if all contents
                    // are added
                    _buffer.put(AJP13_MORE_CONTENT);
                    _needMore = false;
                    _bufferPrepared = true;
                }

            }

            if (!_expectMore && _needEOC)
            {
                if (_buffer == null && _header.space() >= AJP13_END_RESPONSE.length)
                {

                    _header.put(AJP13_END_RESPONSE);
                    _needEOC = false;
                }
                else if (_buffer != null && _buffer.space() >= AJP13_END_RESPONSE.length)
                {
                    // send closing packet if all contents
                    // are added

                    _buffer.put(AJP13_END_RESPONSE);
                    _needEOC = false;
                    _bufferPrepared = true;
                }
            }
        }
    }

    /* ------------------------------------------------------------ */
    public boolean isComplete()
    {
        return !_expectMore && _state == STATE_END;
    }

    /* ------------------------------------------------------------ */
    private void initContent() throws IOException
    {
        if (_buffer == null)
        {
            _buffer = _buffers.getBuffer(_contentBufferSize);
            _buffer.setPutIndex(7);
            _buffer.setGetIndex(7);
        }
    }

    /* ------------------------------------------------------------ */
    private void addInt(int i)
    {
        _buffer.put((byte) ((i >> 8) & 0xFF));
        _buffer.put((byte) (i & 0xFF));
    }

    /* ------------------------------------------------------------ */
    private void addInt(int startIndex, int i)
    {
        _buffer.poke(startIndex, (byte) ((i >> 8) & 0xFF));
        _buffer.poke((startIndex + 1), (byte) (i & 0xFF));
    }

    /* ------------------------------------------------------------ */
    private void addString(String str)
    {
        if (str == null)
        {
            addInt(0xFFFF);
            return;
        }

        // TODO - need to use a writer to convert, to avoid this hacky
        // conversion and temp buffer
        byte[] b = str.getBytes();

        addInt(b.length);

        _buffer.put(b);
        _buffer.put((byte) 0);
    }

    /* ------------------------------------------------------------ */
    private void addBuffer(Buffer b)
    {
        if (b == null)
        {
            addInt(0xFFFF);
            return;
        }

        addInt(b.length());
        _buffer.put(b);
        _buffer.put((byte) 0);
    }

    /* ------------------------------------------------------------ */
    public void getBodyChunk() throws IOException
    {
        _needMore = true;
        _expectMore = true;
        flush();
    }

    /* ------------------------------------------------------------ */
    public void gotBody()
    {
        _needMore = false;
        _expectMore = false;
    }


    /* ------------------------------------------------------------ */
    public void sendCPong() throws IOException
    {

        Buffer buff = _buffers.getBuffer(AJP13_CPONG_RESPONSE.length);
        buff.put(AJP13_CPONG_RESPONSE);

        // flushing cpong response
        do
        {
            _endp.flush(buff);

        }
        while(buff.length() >0);
        _buffers.returnBuffer(buff);

        reset(true);

    }



}

Other Jetty examples (source code examples)

Here is a short list of links related to this Jetty Ajp13Generator.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.