Merge branch 'master' of ssh://git.eclipse.org:29418/jetty/org.eclipse.jetty.project
This commit is contained in:
commit
5ddaa62469
|
@ -171,7 +171,7 @@ public class HttpClient extends AggregateLifeCycle implements HttpBuffers, Attri
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the ThreadPool.
|
||||
* The threadpool passed is added via {@link #addBean(Object)} so that
|
||||
* The threadpool passed is added via {@link #addBean(Object)} so that
|
||||
* it's lifecycle may be managed as a {@link AggregateLifeCycle}.
|
||||
* @param threadPool the threadPool to set
|
||||
*/
|
||||
|
@ -878,7 +878,7 @@ public class HttpClient extends AggregateLifeCycle implements HttpBuffers, Attri
|
|||
@Deprecated
|
||||
public void setProvider(String provider)
|
||||
{
|
||||
setProvider(provider);
|
||||
_sslContextFactory.setProvider(provider);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -260,7 +260,6 @@ public class HttpParser implements Parser
|
|||
{
|
||||
_state=STATE_END;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -326,7 +325,6 @@ public class HttpParser implements Parser
|
|||
if (!isComplete() && !isIdle())
|
||||
throw new EofException();
|
||||
|
||||
returnBuffers();
|
||||
return -1;
|
||||
}
|
||||
length=_buffer.length();
|
||||
|
@ -440,7 +438,6 @@ public class HttpParser implements Parser
|
|||
_state=STATE_SEEKING_EOF;
|
||||
_handler.headerComplete();
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
@ -470,7 +467,6 @@ public class HttpParser implements Parser
|
|||
_state=STATE_SEEKING_EOF;
|
||||
_handler.headerComplete();
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -634,7 +630,6 @@ public class HttpParser implements Parser
|
|||
_handler.headerComplete();
|
||||
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
|
||||
default:
|
||||
|
@ -840,7 +835,6 @@ public class HttpParser implements Parser
|
|||
{
|
||||
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -860,7 +854,6 @@ public class HttpParser implements Parser
|
|||
{
|
||||
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
}
|
||||
// TODO adjust the _buffer to keep unconsumed content
|
||||
return 1;
|
||||
|
@ -895,7 +888,6 @@ public class HttpParser implements Parser
|
|||
_eol=_buffer.get();
|
||||
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
@ -926,7 +918,6 @@ public class HttpParser implements Parser
|
|||
_eol=_buffer.get();
|
||||
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
|
||||
_handler.messageComplete(_contentPosition);
|
||||
returnBuffers();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2009-2009 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.http.gzip;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Skeletal implementation of a CompressedStream. This class adds compression features to a ServletOutputStream and takes care of setting response headers, etc.
|
||||
* Major work and configuration is done here. Subclasses using different kinds of compression only have to implement the abstract methods doCompress() and
|
||||
* setContentEncoding() using the desired compression and setting the appropriate Content-Encoding header string.
|
||||
*/
|
||||
public abstract class AbstractCompressedStream extends ServletOutputStream
|
||||
{
|
||||
private final String _encoding;
|
||||
protected HttpServletRequest _request;
|
||||
protected HttpServletResponse _response;
|
||||
protected OutputStream _out;
|
||||
protected ByteArrayOutputStream2 _bOut;
|
||||
protected DeflaterOutputStream _compressedOutputStream;
|
||||
protected boolean _closed;
|
||||
protected int _bufferSize;
|
||||
protected int _minCompressSize;
|
||||
protected long _contentLength;
|
||||
protected boolean _doNotCompress;
|
||||
|
||||
/**
|
||||
* Instantiates a new compressed stream.
|
||||
*
|
||||
* @param request
|
||||
* the request
|
||||
* @param response
|
||||
* the response
|
||||
* @param contentLength
|
||||
* the content length
|
||||
* @param bufferSize
|
||||
* the buffer size
|
||||
* @param minCompressSize
|
||||
* the min compress size
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public AbstractCompressedStream(String encoding,HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minCompressSize)
|
||||
throws IOException
|
||||
{
|
||||
_encoding=encoding;
|
||||
_request = request;
|
||||
_response = response;
|
||||
_contentLength = contentLength;
|
||||
_bufferSize = bufferSize;
|
||||
_minCompressSize = minCompressSize;
|
||||
if (minCompressSize == 0)
|
||||
doCompress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset buffer.
|
||||
*/
|
||||
public void resetBuffer()
|
||||
{
|
||||
if (_response.isCommitted())
|
||||
throw new IllegalStateException("Committed");
|
||||
_closed = false;
|
||||
_out = null;
|
||||
_bOut = null;
|
||||
if (_compressedOutputStream != null)
|
||||
_response.setHeader("Content-Encoding",null);
|
||||
_compressedOutputStream = null;
|
||||
_doNotCompress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content length.
|
||||
*
|
||||
* @param length
|
||||
* the new content length
|
||||
*/
|
||||
public void setContentLength(long length)
|
||||
{
|
||||
_contentLength = length;
|
||||
if (_doNotCompress && length >= 0)
|
||||
{
|
||||
if (_contentLength < Integer.MAX_VALUE)
|
||||
_response.setContentLength((int)_contentLength);
|
||||
else
|
||||
_response.setHeader("Content-Length",Long.toString(_contentLength));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#flush()
|
||||
*/
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (_out == null || _bOut != null)
|
||||
{
|
||||
if (_contentLength > 0 && _contentLength < _minCompressSize)
|
||||
doNotCompress();
|
||||
else
|
||||
doCompress();
|
||||
}
|
||||
|
||||
_out.flush();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#close()
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
return;
|
||||
|
||||
if (_request.getAttribute("javax.servlet.include.request_uri") != null)
|
||||
flush();
|
||||
else
|
||||
{
|
||||
if (_bOut != null)
|
||||
{
|
||||
if (_contentLength < 0)
|
||||
_contentLength = _bOut.getCount();
|
||||
if (_contentLength < _minCompressSize)
|
||||
doNotCompress();
|
||||
else
|
||||
doCompress();
|
||||
}
|
||||
else if (_out == null)
|
||||
{
|
||||
doNotCompress();
|
||||
}
|
||||
|
||||
if (_compressedOutputStream != null)
|
||||
_compressedOutputStream.close();
|
||||
else
|
||||
_out.close();
|
||||
_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish.
|
||||
*
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public void finish() throws IOException
|
||||
{
|
||||
if (!_closed)
|
||||
{
|
||||
if (_out == null || _bOut != null)
|
||||
{
|
||||
if (_contentLength > 0 && _contentLength < _minCompressSize)
|
||||
doNotCompress();
|
||||
else
|
||||
doCompress();
|
||||
}
|
||||
|
||||
if (_compressedOutputStream != null && !_closed)
|
||||
{
|
||||
_closed = true;
|
||||
_compressedOutputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#write(int)
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
checkOut(1);
|
||||
_out.write(b);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#write(byte[])
|
||||
*/
|
||||
@Override
|
||||
public void write(byte b[]) throws IOException
|
||||
{
|
||||
checkOut(b.length);
|
||||
_out.write(b);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#write(byte[], int, int)
|
||||
*/
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException
|
||||
{
|
||||
checkOut(len);
|
||||
_out.write(b,off,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do compress.
|
||||
*
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public void doCompress() throws IOException
|
||||
{
|
||||
if (_compressedOutputStream==null)
|
||||
{
|
||||
if (_response.isCommitted())
|
||||
throw new IllegalStateException();
|
||||
|
||||
setHeader("Content-Encoding", _encoding);
|
||||
|
||||
if (_response.containsHeader("Content-Encoding"))
|
||||
{
|
||||
_out=_compressedOutputStream=createStream();
|
||||
|
||||
if (_bOut!=null)
|
||||
{
|
||||
_out.write(_bOut.getBuf(),0,_bOut.getCount());
|
||||
_bOut=null;
|
||||
}
|
||||
}
|
||||
else
|
||||
doNotCompress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not compress.
|
||||
*
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public void doNotCompress() throws IOException
|
||||
{
|
||||
if (_compressedOutputStream != null)
|
||||
throw new IllegalStateException();
|
||||
if (_out == null || _bOut != null)
|
||||
{
|
||||
_doNotCompress = true;
|
||||
|
||||
_out = _response.getOutputStream();
|
||||
setContentLength(_contentLength);
|
||||
|
||||
if (_bOut != null)
|
||||
_out.write(_bOut.getBuf(),0,_bOut.getCount());
|
||||
_bOut = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out.
|
||||
*
|
||||
* @param length
|
||||
* the length
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
private void checkOut(int length) throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new IOException("CLOSED");
|
||||
|
||||
if (_out == null)
|
||||
{
|
||||
if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
|
||||
doNotCompress();
|
||||
else if (length > _minCompressSize)
|
||||
doCompress();
|
||||
else
|
||||
_out = _bOut = new ByteArrayOutputStream2(_bufferSize);
|
||||
}
|
||||
else if (_bOut != null)
|
||||
{
|
||||
if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize))
|
||||
doNotCompress();
|
||||
else if (length >= (_bOut.getBuf().length - _bOut.getCount()))
|
||||
doCompress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedStream#getOutputStream()
|
||||
*/
|
||||
public OutputStream getOutputStream()
|
||||
{
|
||||
return _out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedStream#isClosed()
|
||||
*/
|
||||
public boolean isClosed()
|
||||
{
|
||||
return _closed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows derived implementations to replace PrintWriter implementation.
|
||||
*/
|
||||
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
|
||||
}
|
||||
|
||||
protected void setHeader(String name,String value)
|
||||
{
|
||||
_response.setHeader(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the stream fitting to the underlying compression type.
|
||||
*
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
protected abstract DeflaterOutputStream createStream() throws IOException;
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) Webtide LLC
|
||||
// Copyright (c) 2009-2009 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
|
||||
|
@ -11,7 +11,6 @@
|
|||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
|
||||
package org.eclipse.jetty.http.gzip;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -28,42 +27,34 @@ import javax.servlet.http.HttpServletResponseWrapper;
|
|||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class GzipResponseWrapper extends HttpServletResponseWrapper
|
||||
public abstract class CompressedResponseWrapper extends HttpServletResponseWrapper
|
||||
{
|
||||
public static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
public static final int DEFAULT_MIN_GZIP_SIZE = 256;
|
||||
|
||||
private HttpServletRequest _request;
|
||||
public static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
public static final int DEFAULT_MIN_COMPRESS_SIZE = 256;
|
||||
|
||||
private Set<String> _mimeTypes;
|
||||
private int _bufferSize=DEFAULT_BUFFER_SIZE;
|
||||
private int _minGzipSize=DEFAULT_MIN_GZIP_SIZE;
|
||||
private int _minCompressSize=DEFAULT_MIN_COMPRESS_SIZE;
|
||||
protected HttpServletRequest _request;
|
||||
|
||||
private PrintWriter _writer;
|
||||
private GzipStream _gzStream;
|
||||
private AbstractCompressedStream _compressedStream;
|
||||
private long _contentLength=-1;
|
||||
private boolean _noGzip;
|
||||
private boolean _noCompression;
|
||||
|
||||
/**
|
||||
* Instantiates a new gzip response wrapper.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
*/
|
||||
public GzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
public CompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
super(response);
|
||||
_request=request;
|
||||
_request = request;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Sets the mime types.
|
||||
*
|
||||
* @param mimeTypes the new mime types
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set)
|
||||
*/
|
||||
public void setMimeTypes(Set<String> mimeTypes)
|
||||
{
|
||||
|
@ -72,8 +63,9 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#setBufferSize(int)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setBufferSize(int)
|
||||
*/
|
||||
@Override
|
||||
public void setBufferSize(int bufferSize)
|
||||
{
|
||||
_bufferSize = bufferSize;
|
||||
|
@ -81,64 +73,66 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Sets the min gzip size.
|
||||
*
|
||||
* @param minGzipSize the new min gzip size
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMinCompressSize(int)
|
||||
*/
|
||||
public void setMinGzipSize(int minGzipSize)
|
||||
public void setMinCompressSize(int minCompressSize)
|
||||
{
|
||||
_minGzipSize = minGzipSize;
|
||||
_minCompressSize = minCompressSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentType(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setContentType(String ct)
|
||||
{
|
||||
super.setContentType(ct);
|
||||
|
||||
|
||||
if (ct!=null)
|
||||
{
|
||||
int colon=ct.indexOf(";");
|
||||
if (colon>0)
|
||||
ct=ct.substring(0,colon);
|
||||
}
|
||||
|
||||
if ((_gzStream==null || _gzStream._out==null) &&
|
||||
|
||||
if ((_compressedStream==null || _compressedStream.getOutputStream()==null) &&
|
||||
(_mimeTypes==null && ct!=null && ct.contains("gzip") ||
|
||||
_mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct)))))
|
||||
{
|
||||
noGzip();
|
||||
noCompression();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int, java.lang.String)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setStatus(int sc, String sm)
|
||||
{
|
||||
super.setStatus(sc,sm);
|
||||
if (sc<200 || sc==204 || sc==205 || sc>=300)
|
||||
noGzip();
|
||||
noCompression();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int)
|
||||
*/
|
||||
@Override
|
||||
public void setStatus(int sc)
|
||||
{
|
||||
super.setStatus(sc);
|
||||
if (sc<200 || sc==204 || sc==205 ||sc>=300)
|
||||
noGzip();
|
||||
noCompression();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#setContentLength(int)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentLength(int)
|
||||
*/
|
||||
@Override
|
||||
public void setContentLength(int length)
|
||||
{
|
||||
setContentLength((long)length);
|
||||
|
@ -148,9 +142,9 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
protected void setContentLength(long length)
|
||||
{
|
||||
_contentLength=length;
|
||||
if (_gzStream!=null)
|
||||
_gzStream.setContentLength(length);
|
||||
else if (_noGzip && _contentLength>=0)
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.setContentLength(length);
|
||||
else if (_noCompression && _contentLength>=0)
|
||||
{
|
||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||
if(_contentLength<Integer.MAX_VALUE)
|
||||
|
@ -166,15 +160,16 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#addHeader(java.lang.String, java.lang.String)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#addHeader(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
if ("content-length".equalsIgnoreCase(name))
|
||||
{
|
||||
_contentLength=Long.parseLong(value);
|
||||
if (_gzStream!=null)
|
||||
_gzStream.setContentLength(_contentLength);
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.setContentLength(_contentLength);
|
||||
}
|
||||
else if ("content-type".equalsIgnoreCase(name))
|
||||
{
|
||||
|
@ -185,7 +180,7 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
super.addHeader(name,value);
|
||||
if (!isCommitted())
|
||||
{
|
||||
noGzip();
|
||||
noCompression();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -194,8 +189,119 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#setHeader(java.lang.String, java.lang.String)
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#flushBuffer()
|
||||
*/
|
||||
@Override
|
||||
public void flushBuffer() throws IOException
|
||||
{
|
||||
if (_writer!=null)
|
||||
_writer.flush();
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.finish();
|
||||
else
|
||||
getResponse().flushBuffer();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#reset()
|
||||
*/
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.resetBuffer();
|
||||
_writer=null;
|
||||
_compressedStream=null;
|
||||
_noCompression=false;
|
||||
_contentLength=-1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#resetBuffer()
|
||||
*/
|
||||
@Override
|
||||
public void resetBuffer()
|
||||
{
|
||||
super.resetBuffer();
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.resetBuffer();
|
||||
_writer=null;
|
||||
_compressedStream=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#sendError(int, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void sendError(int sc, String msg) throws IOException
|
||||
{
|
||||
resetBuffer();
|
||||
super.sendError(sc,msg);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#sendError(int)
|
||||
*/
|
||||
@Override
|
||||
public void sendError(int sc) throws IOException
|
||||
{
|
||||
resetBuffer();
|
||||
super.sendError(sc);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#sendRedirect(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void sendRedirect(String location) throws IOException
|
||||
{
|
||||
resetBuffer();
|
||||
super.sendRedirect(location);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#noCompression()
|
||||
*/
|
||||
public void noCompression()
|
||||
{
|
||||
_noCompression=true;
|
||||
if (_compressedStream!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_compressedStream.doNotCompress();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#finish()
|
||||
*/
|
||||
public void finish() throws IOException
|
||||
{
|
||||
if (_writer!=null && !_compressedStream.isClosed())
|
||||
_writer.flush();
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.finish();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setHeader(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
if ("content-length".equalsIgnoreCase(name))
|
||||
|
@ -211,197 +317,77 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
super.setHeader(name,value);
|
||||
if (!isCommitted())
|
||||
{
|
||||
noGzip();
|
||||
noCompression();
|
||||
}
|
||||
}
|
||||
else
|
||||
super.setHeader(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#setIntHeader(java.lang.String, int)
|
||||
*/
|
||||
public void setIntHeader(String name, int value)
|
||||
{
|
||||
if ("content-length".equalsIgnoreCase(name))
|
||||
{
|
||||
_contentLength=value;
|
||||
if (_gzStream!=null)
|
||||
_gzStream.setContentLength(_contentLength);
|
||||
}
|
||||
else
|
||||
super.setIntHeader(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#flushBuffer()
|
||||
*/
|
||||
public void flushBuffer() throws IOException
|
||||
{
|
||||
if (_writer!=null)
|
||||
_writer.flush();
|
||||
if (_gzStream!=null)
|
||||
_gzStream.finish();
|
||||
else
|
||||
getResponse().flushBuffer();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#reset()
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
if (_gzStream!=null)
|
||||
_gzStream.resetBuffer();
|
||||
_writer=null;
|
||||
_gzStream=null;
|
||||
_noGzip=false;
|
||||
_contentLength=-1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#resetBuffer()
|
||||
*/
|
||||
public void resetBuffer()
|
||||
{
|
||||
super.resetBuffer();
|
||||
if (_gzStream!=null)
|
||||
_gzStream.resetBuffer();
|
||||
_writer=null;
|
||||
_gzStream=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#sendError(int, java.lang.String)
|
||||
*/
|
||||
public void sendError(int sc, String msg) throws IOException
|
||||
{
|
||||
resetBuffer();
|
||||
super.sendError(sc,msg);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#sendError(int)
|
||||
*/
|
||||
public void sendError(int sc) throws IOException
|
||||
{
|
||||
resetBuffer();
|
||||
super.sendError(sc);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.http.HttpServletResponseWrapper#sendRedirect(java.lang.String)
|
||||
*/
|
||||
public void sendRedirect(String location) throws IOException
|
||||
{
|
||||
resetBuffer();
|
||||
super.sendRedirect(location);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#getOutputStream()
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#getOutputStream()
|
||||
*/
|
||||
@Override
|
||||
public ServletOutputStream getOutputStream() throws IOException
|
||||
{
|
||||
if (_gzStream==null)
|
||||
if (_compressedStream==null)
|
||||
{
|
||||
if (getResponse().isCommitted() || _noGzip)
|
||||
if (getResponse().isCommitted() || _noCompression)
|
||||
{
|
||||
setContentLength(_contentLength);
|
||||
return getResponse().getOutputStream();
|
||||
}
|
||||
|
||||
_gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize);
|
||||
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
|
||||
}
|
||||
else if (_writer!=null)
|
||||
throw new IllegalStateException("getWriter() called");
|
||||
|
||||
return _gzStream;
|
||||
return (ServletOutputStream)_compressedStream;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.ServletResponseWrapper#getWriter()
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#getWriter()
|
||||
*/
|
||||
@Override
|
||||
public PrintWriter getWriter() throws IOException
|
||||
{
|
||||
if (_writer==null)
|
||||
{
|
||||
if (_gzStream!=null)
|
||||
if (_compressedStream!=null)
|
||||
throw new IllegalStateException("getOutputStream() called");
|
||||
|
||||
if (getResponse().isCommitted() || _noGzip)
|
||||
if (getResponse().isCommitted() || _noCompression)
|
||||
{
|
||||
setContentLength(_contentLength);
|
||||
return getResponse().getWriter();
|
||||
}
|
||||
|
||||
_gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize);
|
||||
_writer=newWriter(_gzStream,getCharacterEncoding());
|
||||
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
|
||||
_writer=newWriter((OutputStream)_compressedStream,getCharacterEncoding());
|
||||
}
|
||||
return _writer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* No gzip.
|
||||
*/
|
||||
public void noGzip()
|
||||
{
|
||||
_noGzip=true;
|
||||
if (_gzStream!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_gzStream.doNotGzip();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Finish.
|
||||
*
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setIntHeader(java.lang.String, int)
|
||||
*/
|
||||
public void finish() throws IOException
|
||||
@Override
|
||||
public void setIntHeader(String name, int value)
|
||||
{
|
||||
if (_writer!=null && !_gzStream._closed)
|
||||
_writer.flush();
|
||||
if (_gzStream!=null)
|
||||
_gzStream.finish();
|
||||
if ("content-length".equalsIgnoreCase(name))
|
||||
{
|
||||
_contentLength=value;
|
||||
if (_compressedStream!=null)
|
||||
_compressedStream.setContentLength(_contentLength);
|
||||
}
|
||||
else
|
||||
super.setIntHeader(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Allows derived implementations to replace GzipStream implementation.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param contentLength the content length
|
||||
* @param bufferSize the buffer size
|
||||
* @param minGzipSize the min gzip size
|
||||
* @return the gzip stream
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
|
||||
{
|
||||
return new GzipStream(request,response,contentLength,bufferSize,minGzipSize);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Allows derived implementations to replace PrintWriter implementation.
|
||||
|
@ -415,5 +401,11 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
|
|||
{
|
||||
return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*@return the underlying CompressedStream implementation
|
||||
*/
|
||||
protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response, long _contentLength2, int _bufferSize2, int _minCompressedSize2) throws IOException;
|
||||
|
||||
}
|
|
@ -1,305 +0,0 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) Webtide LLC
|
||||
// ------------------------------------------------------------------------
|
||||
// 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.http.gzip;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class GzipStream extends ServletOutputStream
|
||||
{
|
||||
protected HttpServletRequest _request;
|
||||
protected HttpServletResponse _response;
|
||||
protected OutputStream _out;
|
||||
protected ByteArrayOutputStream2 _bOut;
|
||||
protected GZIPOutputStream _gzOut;
|
||||
protected boolean _closed;
|
||||
protected int _bufferSize;
|
||||
protected int _minGzipSize;
|
||||
protected long _contentLength;
|
||||
protected boolean _doNotGzip;
|
||||
|
||||
/**
|
||||
* Instantiates a new gzip stream.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @param contentLength the content length
|
||||
* @param bufferSize the buffer size
|
||||
* @param minGzipSize the min gzip size
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public GzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
|
||||
{
|
||||
_request=request;
|
||||
_response=response;
|
||||
_contentLength=contentLength;
|
||||
_bufferSize=bufferSize;
|
||||
_minGzipSize=minGzipSize;
|
||||
if (minGzipSize==0)
|
||||
doGzip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset buffer.
|
||||
*/
|
||||
public void resetBuffer()
|
||||
{
|
||||
if (_response.isCommitted())
|
||||
throw new IllegalStateException("Committed");
|
||||
_closed=false;
|
||||
_out=null;
|
||||
_bOut=null;
|
||||
if (_gzOut!=null)
|
||||
_response.setHeader("Content-Encoding",null);
|
||||
_gzOut=null;
|
||||
_doNotGzip=false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content length.
|
||||
*
|
||||
* @param length the new content length
|
||||
*/
|
||||
public void setContentLength(long length)
|
||||
{
|
||||
_contentLength=length;
|
||||
if (_doNotGzip && length>=0)
|
||||
{
|
||||
if(_contentLength<Integer.MAX_VALUE)
|
||||
_response.setContentLength((int)_contentLength);
|
||||
else
|
||||
_response.setHeader("Content-Length",Long.toString(_contentLength));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#flush()
|
||||
*/
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (_out==null || _bOut!=null)
|
||||
{
|
||||
if (_contentLength>0 && _contentLength<_minGzipSize)
|
||||
doNotGzip();
|
||||
else
|
||||
doGzip();
|
||||
}
|
||||
|
||||
_out.flush();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#close()
|
||||
*/
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
return;
|
||||
|
||||
if (_request.getAttribute("javax.servlet.include.request_uri")!=null)
|
||||
flush();
|
||||
else
|
||||
{
|
||||
if (_bOut!=null)
|
||||
{
|
||||
if (_contentLength<0)
|
||||
_contentLength=_bOut.getCount();
|
||||
if (_contentLength<_minGzipSize)
|
||||
doNotGzip();
|
||||
else
|
||||
doGzip();
|
||||
}
|
||||
else if (_out==null)
|
||||
{
|
||||
doNotGzip();
|
||||
}
|
||||
|
||||
if (_gzOut!=null)
|
||||
_gzOut.close();
|
||||
else
|
||||
_out.close();
|
||||
_closed=true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish.
|
||||
*
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public void finish() throws IOException
|
||||
{
|
||||
if (!_closed)
|
||||
{
|
||||
if (_out==null || _bOut!=null)
|
||||
{
|
||||
if (_contentLength>0 && _contentLength<_minGzipSize)
|
||||
doNotGzip();
|
||||
else
|
||||
doGzip();
|
||||
}
|
||||
|
||||
if (_gzOut!=null && !_closed)
|
||||
{
|
||||
_closed=true;
|
||||
_gzOut.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#write(int)
|
||||
*/
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
checkOut(1);
|
||||
_out.write(b);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#write(byte[])
|
||||
*/
|
||||
public void write(byte b[]) throws IOException
|
||||
{
|
||||
checkOut(b.length);
|
||||
_out.write(b);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see java.io.OutputStream#write(byte[], int, int)
|
||||
*/
|
||||
public void write(byte b[], int off, int len) throws IOException
|
||||
{
|
||||
checkOut(len);
|
||||
_out.write(b,off,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the content encoding gzip.
|
||||
*
|
||||
* @return true, if successful
|
||||
*/
|
||||
protected boolean setContentEncodingGzip()
|
||||
{
|
||||
_response.setHeader("Content-Encoding", "gzip");
|
||||
return _response.containsHeader("Content-Encoding");
|
||||
}
|
||||
|
||||
/**
|
||||
* Do gzip.
|
||||
*
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public void doGzip() throws IOException
|
||||
{
|
||||
if (_gzOut==null)
|
||||
{
|
||||
if (_response.isCommitted())
|
||||
throw new IllegalStateException();
|
||||
|
||||
if (setContentEncodingGzip())
|
||||
{
|
||||
_out=_gzOut=new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||
|
||||
if (_bOut!=null)
|
||||
{
|
||||
_out.write(_bOut.getBuf(),0,_bOut.getCount());
|
||||
_bOut=null;
|
||||
}
|
||||
}
|
||||
else
|
||||
doNotGzip();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not gzip.
|
||||
*
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public void doNotGzip() throws IOException
|
||||
{
|
||||
if (_gzOut!=null)
|
||||
throw new IllegalStateException();
|
||||
if (_out==null || _bOut!=null )
|
||||
{
|
||||
_doNotGzip = true;
|
||||
|
||||
_out=_response.getOutputStream();
|
||||
setContentLength(_contentLength);
|
||||
|
||||
if (_bOut!=null)
|
||||
_out.write(_bOut.getBuf(),0,_bOut.getCount());
|
||||
_bOut=null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check out.
|
||||
*
|
||||
* @param length the length
|
||||
* @throws IOException Signals that an I/O exception has occurred.
|
||||
*/
|
||||
private void checkOut(int length) throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new IOException("CLOSED");
|
||||
|
||||
if (_out==null)
|
||||
{
|
||||
if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize))
|
||||
doNotGzip();
|
||||
else if (length>_minGzipSize)
|
||||
doGzip();
|
||||
else
|
||||
_out=_bOut=new ByteArrayOutputStream2(_bufferSize);
|
||||
}
|
||||
else if (_bOut!=null)
|
||||
{
|
||||
if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize))
|
||||
doNotGzip();
|
||||
else if (length>=(_bOut.getBuf().length -_bOut.getCount()))
|
||||
doGzip();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows derived implementations to replace PrintWriter implementation.
|
||||
*/
|
||||
protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,35 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-project</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
<artifactId>jetty-parent</artifactId>
|
||||
<version>19</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>1.0.1-SNAPSHOT</version>
|
||||
<name>Jetty :: Next Protocol Negotiation :: API</name>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:http://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</connection>
|
||||
<developerConnection>scm:git:ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</developerConnection>
|
||||
<url>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-npn</url>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<configuration>
|
||||
<useReleaseProfile>false</useReleaseProfile>
|
||||
<goals>deploy</goals>
|
||||
<arguments>-Peclipse-release</arguments>
|
||||
<preparationGoals>clean install</preparationGoals>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: Jetty-OSGi-Jasper integration
|
||||
Fragment-Host: org.eclipse.jetty.osgi.boot
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.jsp
|
||||
Bundle-Version: 7.6.2.qualifier
|
||||
Bundle-Version: 7.6.3.qualifier
|
||||
Bundle-Vendor: Mort Bay Consulting
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
Import-Package: com.sun.el;resolution:=optional,
|
||||
|
|
|
@ -28,98 +28,106 @@ import org.osgi.framework.Bundle;
|
|||
import org.osgi.framework.FrameworkUtil;
|
||||
|
||||
/**
|
||||
* Plug bundles that contains tld files so that jasper will discover them
|
||||
* and set them up in jetty.
|
||||
* Plug bundles that contains tld files so that jasper will discover them and
|
||||
* set them up in jetty.
|
||||
*
|
||||
* For example: -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
|
||||
* Otherwise use an attribute to the WebAppDeployer
|
||||
* <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
|
||||
* ....
|
||||
* <Set name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldsbundles" default="" /></Set>
|
||||
* <New>
|
||||
* For example:
|
||||
* -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet
|
||||
* ,com.opensymphony.module.sitemesh Otherwise use an attribute to the
|
||||
* WebAppDeployer <New
|
||||
* class="org.eclipse.jetty.deploy.providers.WebAppProvider"> .... <Set
|
||||
* name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldsbundles"
|
||||
* default="" /></Set> <New>
|
||||
*/
|
||||
public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistrationCustomizer
|
||||
{
|
||||
/**
|
||||
* To plug into jasper bundles that contain tld files
|
||||
* please use a list of bundle's symbolic names:
|
||||
* -Djetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
|
||||
*/
|
||||
public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
|
||||
|
||||
/**
|
||||
* Union of the tld bundles defined system wide and the one defines as an attribute of the AppProvider.
|
||||
* @param provider
|
||||
* @return
|
||||
*/
|
||||
private static Collection<String> getTldBundles(OSGiAppProvider provider)
|
||||
{
|
||||
String sysprop = System.getProperty(SYS_PROP_TLD_BUNDLES);
|
||||
String att = (String)provider.getTldBundles();
|
||||
if (sysprop == null && att == null)
|
||||
{
|
||||
return Collections.emptySet();
|
||||
}
|
||||
if (att == null)
|
||||
{
|
||||
att = sysprop;
|
||||
}
|
||||
else if (sysprop != null)
|
||||
{
|
||||
att = att + "," + sysprop;
|
||||
}
|
||||
|
||||
Collection<String> tldbundles = new HashSet<String>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(att, ", \n\r\t", false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
tldbundles.add(tokenizer.nextToken());
|
||||
}
|
||||
return tldbundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The location of the jars that contain tld files.
|
||||
* Jasper will discover them.
|
||||
*/
|
||||
/**
|
||||
* To plug into jasper bundles that contain tld files please use a list of
|
||||
* bundle's symbolic names:
|
||||
* -Djetty.osgi.tldbundles=org.springframework.web.servlet
|
||||
* ,com.opensymphony.module.sitemesh
|
||||
*/
|
||||
public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
|
||||
|
||||
/**
|
||||
* Union of the tld bundles defined system wide and the one defines as an
|
||||
* attribute of the AppProvider.
|
||||
*
|
||||
* @param provider
|
||||
* @return
|
||||
*/
|
||||
private static Collection<String> getTldBundles(OSGiAppProvider provider)
|
||||
{
|
||||
String sysprop = System.getProperty(SYS_PROP_TLD_BUNDLES);
|
||||
String att = (String) provider.getTldBundles();
|
||||
if (sysprop == null && att == null) { return Collections.emptySet(); }
|
||||
if (att == null)
|
||||
{
|
||||
att = sysprop;
|
||||
}
|
||||
else if (sysprop != null)
|
||||
{
|
||||
att = att + "," + sysprop;
|
||||
}
|
||||
|
||||
Collection<String> tldbundles = new HashSet<String>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(att, ", \n\r\t", false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
tldbundles.add(tokenizer.nextToken());
|
||||
}
|
||||
return tldbundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The location of the jars that contain tld files. Jasper will
|
||||
* discover them.
|
||||
*/
|
||||
public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception
|
||||
{
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
//naive way of finding those bundles.
|
||||
//lots of assumptions: for example we assume a single version of each bundle that would contain tld files.
|
||||
//this is probably good enough as those tlds are loaded system-wide on jetty.
|
||||
//to do better than this we need to do it on a per webapp basis.
|
||||
//probably using custom properties in the ContextHandler service
|
||||
//and mirroring those in the MANIFEST.MF
|
||||
|
||||
Bundle[] bundles = FrameworkUtil.getBundle(PluggableWebAppRegistrationCustomizerImpl.class).getBundleContext().getBundles();
|
||||
Collection<String> tldbundles = getTldBundles(provider);
|
||||
for (Bundle bundle : bundles)
|
||||
{
|
||||
if (tldbundles.contains(bundle.getSymbolicName()))
|
||||
{
|
||||
registerTldBundle(locatorHelper, bundle, urls);
|
||||
}
|
||||
}
|
||||
|
||||
return urls.toArray(new URL[urls.size()]);
|
||||
List<URL> urls = new ArrayList<URL>();
|
||||
// naive way of finding those bundles.
|
||||
// lots of assumptions: for example we assume a single version of each
|
||||
// bundle that would contain tld files.
|
||||
// this is probably good enough as those tlds are loaded system-wide on
|
||||
// jetty.
|
||||
// to do better than this we need to do it on a per webapp basis.
|
||||
// probably using custom properties in the ContextHandler service
|
||||
// and mirroring those in the MANIFEST.MF
|
||||
|
||||
Bundle[] bundles = FrameworkUtil.getBundle(PluggableWebAppRegistrationCustomizerImpl.class).getBundleContext().getBundles();
|
||||
Collection<String> tldbundles = getTldBundles(provider);
|
||||
for (Bundle bundle : bundles)
|
||||
{
|
||||
if (tldbundles.contains(bundle.getSymbolicName()))
|
||||
{
|
||||
registerTldBundle(locatorHelper, bundle, urls);
|
||||
}
|
||||
}
|
||||
|
||||
return urls.toArray(new URL[urls.size()]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the bundle that contains tld files as a set of URLs that will be
|
||||
* passed to jasper as a URLClassLoader later on.
|
||||
* Usually that would be a single URL per bundle.
|
||||
* But we do some more work if there are jars embedded in the bundle.
|
||||
* passed to jasper as a URLClassLoader later on. Usually that would be a
|
||||
* single URL per bundle. But we do some more work if there are jars
|
||||
* embedded in the bundle.
|
||||
*
|
||||
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
|
||||
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
|
||||
* implemenation.
|
||||
* The jasper TldScanner expects a URLClassloader to parse a jar for the
|
||||
* /META-INF/*.tld it may contain. We place the bundles that we know contain
|
||||
* such tag-libraries. Please note that it will work if and only if the
|
||||
* bundle is a jar (!) Currently we just hardcode the bundle that contains
|
||||
* the jstl implemenation.
|
||||
*
|
||||
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
|
||||
* A workaround when the tld cannot be parsed with this method is to copy
|
||||
* and paste it inside the WEB-INF of the webapplication where it is used.
|
||||
*
|
||||
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
|
||||
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
|
||||
* Support only 2 types of packaging for the bundle: - the bundle is a jar
|
||||
* (recommended for runtime.) - the bundle is a folder and contain jars in
|
||||
* the root and/or in the lib folder (nice for PDE developement situations)
|
||||
* Unsupported: the bundle is a jar that embeds more jars.
|
||||
*
|
||||
* @param locatorHelper
|
||||
* @param bundle
|
||||
|
@ -152,9 +160,9 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
|
|||
}
|
||||
else
|
||||
{
|
||||
urls.add(jasperLocation.toURI().toURL());
|
||||
urls.add(jasperLocation.toURI().toURL());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -36,48 +36,52 @@ import org.xml.sax.InputSource;
|
|||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Fix various shortcomings with the way jasper parses the tld files.
|
||||
* Plugs the JSTL tlds assuming that they are packaged with the bundle that contains the JSTL classes.
|
||||
* Fix various shortcomings with the way jasper parses the tld files. Plugs the
|
||||
* JSTL tlds assuming that they are packaged with the bundle that contains the
|
||||
* JSTL classes.
|
||||
* <p>
|
||||
* Pluggable tlds at the server level are handled by {@link PluggableWebAppRegistrationCustomizerImpl}.
|
||||
* Pluggable tlds at the server level are handled by
|
||||
* {@link PluggableWebAppRegistrationCustomizerImpl}.
|
||||
* </p>
|
||||
*/
|
||||
public class WebappRegistrationCustomizerImpl implements WebappRegistrationCustomizer
|
||||
{
|
||||
|
||||
/**
|
||||
* Default name of a class that belongs to the jstl bundle.
|
||||
* From that class we locate the corresponding bundle and register it
|
||||
* as a bundle that contains tld files.
|
||||
*/
|
||||
private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag";
|
||||
//used to be "org.apache.jasper.runtime.JspFactoryImpl" but now
|
||||
//the standard tag library implementation are stored in a separate bundle.
|
||||
|
||||
//DISABLED please use the tld bundle argument for the OSGiAppProvider
|
||||
// /**
|
||||
// * Default name of a class that belongs to the bundle where the Java server Faces tld files are defined.
|
||||
// * This is the sun's reference implementation.
|
||||
// */
|
||||
// private static String DEFAUT_JSF_IMPL_CLASS = "com.sun.faces.config.ConfigureListener";
|
||||
|
||||
/**
|
||||
* Default jsp factory implementation.
|
||||
* Idally jasper is osgified and we can use services.
|
||||
* In the mean time we statically set the jsp factory implementation.
|
||||
* bug #299733
|
||||
*/
|
||||
private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl";
|
||||
|
||||
/**
|
||||
* Default name of a class that belongs to the jstl bundle. From that class
|
||||
* we locate the corresponding bundle and register it as a bundle that
|
||||
* contains tld files.
|
||||
*/
|
||||
private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag";
|
||||
|
||||
// used to be "org.apache.jasper.runtime.JspFactoryImpl" but now
|
||||
// the standard tag library implementation are stored in a separate bundle.
|
||||
|
||||
// DISABLED please use the tld bundle argument for the OSGiAppProvider
|
||||
// /**
|
||||
// * Default name of a class that belongs to the bundle where the Java
|
||||
// server Faces tld files are defined.
|
||||
// * This is the sun's reference implementation.
|
||||
// */
|
||||
// private static String DEFAUT_JSF_IMPL_CLASS =
|
||||
// "com.sun.faces.config.ConfigureListener";
|
||||
|
||||
/**
|
||||
* Default jsp factory implementation. Idally jasper is osgified and we can
|
||||
* use services. In the mean time we statically set the jsp factory
|
||||
* implementation. bug #299733
|
||||
*/
|
||||
private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl";
|
||||
|
||||
public WebappRegistrationCustomizerImpl()
|
||||
{
|
||||
fixupDtdResolution();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
//sanity check:
|
||||
// sanity check:
|
||||
Class cl = getClass().getClassLoader().loadClass("org.apache.jasper.servlet.JspServlet");
|
||||
//System.err.println("found the jsp servlet: " + cl.getName());
|
||||
// System.err.println("found the jsp servlet: " + cl.getName());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -87,18 +91,18 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
|
|||
}
|
||||
try
|
||||
{
|
||||
//bug #299733
|
||||
// bug #299733
|
||||
JspFactory fact = JspFactory.getDefaultFactory();
|
||||
if (fact == null)
|
||||
{ //bug #299733
|
||||
//JspFactory does a simple Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
|
||||
//however its bundles does not import the jasper package
|
||||
//so it fails. let's help things out:
|
||||
fact = (JspFactory)JettyBootstrapActivator.class.getClassLoader()
|
||||
.loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance();
|
||||
{ // bug #299733
|
||||
// JspFactory does a simple
|
||||
// Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
|
||||
// however its bundles does not import the jasper package
|
||||
// so it fails. let's help things out:
|
||||
fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader().loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance();
|
||||
JspFactory.setDefaultFactory(fact);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -106,85 +110,90 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
|
||||
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
|
||||
* implemenation.
|
||||
* The jasper TldScanner expects a URLClassloader to parse a jar for the
|
||||
* /META-INF/*.tld it may contain. We place the bundles that we know contain
|
||||
* such tag-libraries. Please note that it will work if and only if the
|
||||
* bundle is a jar (!) Currently we just hardcode the bundle that contains
|
||||
* the jstl implemenation.
|
||||
*
|
||||
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
|
||||
* A workaround when the tld cannot be parsed with this method is to copy
|
||||
* and paste it inside the WEB-INF of the webapplication where it is used.
|
||||
*
|
||||
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
|
||||
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
|
||||
* Support only 2 types of packaging for the bundle: - the bundle is a jar
|
||||
* (recommended for runtime.) - the bundle is a folder and contain jars in
|
||||
* the root and/or in the lib folder (nice for PDE developement situations)
|
||||
* Unsupported: the bundle is a jar that embeds more jars.
|
||||
*
|
||||
* @return array of URLs
|
||||
* @throws Exception
|
||||
*/
|
||||
public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception
|
||||
{
|
||||
|
||||
HashSet<Class<?>> classesToAddToTheTldBundles = new HashSet<Class<?>>();
|
||||
|
||||
//Look for the jstl bundle
|
||||
//We assume the jstl's tlds are defined there.
|
||||
//We assume that the jstl bundle is imported by this bundle
|
||||
//So we can look for this class using this bundle's classloader:
|
||||
Class<?> jstlClass = WebappRegistrationCustomizerImpl.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS);
|
||||
|
||||
classesToAddToTheTldBundles.add(jstlClass);
|
||||
|
||||
HashSet<Class<?>> classesToAddToTheTldBundles = new HashSet<Class<?>>();
|
||||
|
||||
// Look for the jstl bundle
|
||||
// We assume the jstl's tlds are defined there.
|
||||
// We assume that the jstl bundle is imported by this bundle
|
||||
// So we can look for this class using this bundle's classloader:
|
||||
Class<?> jstlClass = WebappRegistrationCustomizerImpl.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS);
|
||||
|
||||
classesToAddToTheTldBundles.add(jstlClass);
|
||||
|
||||
ArrayList<URL> urls = new ArrayList<URL>();
|
||||
for (Class<?> cl : classesToAddToTheTldBundles)
|
||||
{
|
||||
Bundle tldBundle = FrameworkUtil.getBundle(cl);
|
||||
File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle);
|
||||
if (tldBundleLocation != null && tldBundleLocation.isDirectory())
|
||||
{
|
||||
// try to find the jar files inside this folder
|
||||
for (File f : tldBundleLocation.listFiles())
|
||||
{
|
||||
if (f.getName().endsWith(".jar") && f.isFile())
|
||||
{
|
||||
urls.add(f.toURI().toURL());
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
for (File f2 : tldBundleLocation.listFiles())
|
||||
{
|
||||
if (f2.getName().endsWith(".jar") && f2.isFile())
|
||||
{
|
||||
urls.add(f2.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (tldBundleLocation != null)
|
||||
{
|
||||
urls.add(tldBundleLocation.toURI().toURL());
|
||||
}
|
||||
}
|
||||
return urls.toArray(new URL[urls.size()]);
|
||||
for (Class<?> cl : classesToAddToTheTldBundles)
|
||||
{
|
||||
Bundle tldBundle = FrameworkUtil.getBundle(cl);
|
||||
File tldBundleLocation = locatorHelper.getBundleInstallLocation(tldBundle);
|
||||
if (tldBundleLocation != null && tldBundleLocation.isDirectory())
|
||||
{
|
||||
// try to find the jar files inside this folder
|
||||
for (File f : tldBundleLocation.listFiles())
|
||||
{
|
||||
if (f.getName().endsWith(".jar") && f.isFile())
|
||||
{
|
||||
urls.add(f.toURI().toURL());
|
||||
}
|
||||
else if (f.isDirectory() && f.getName().equals("lib"))
|
||||
{
|
||||
for (File f2 : tldBundleLocation.listFiles())
|
||||
{
|
||||
if (f2.getName().endsWith(".jar") && f2.isFile())
|
||||
{
|
||||
urls.add(f2.toURI().toURL());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (tldBundleLocation != null)
|
||||
{
|
||||
urls.add(tldBundleLocation.toURI().toURL());
|
||||
}
|
||||
}
|
||||
return urls.toArray(new URL[urls.size()]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Jasper resolves the dtd when it parses a taglib descriptor.
|
||||
* It uses this code to do that: ParserUtils.getClass().getResourceAsStream(resourcePath); where
|
||||
* resourcePath is for example: /javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd Unfortunately,
|
||||
* the dtd file is not in the exact same classloader as
|
||||
* ParserUtils class and the dtds are packaged in 2 separate bundles.
|
||||
* OSGi does not look in the dependencies' classloader when a resource is searched.
|
||||
* Jasper resolves the dtd when it parses a taglib descriptor. It uses this
|
||||
* code to do that:
|
||||
* ParserUtils.getClass().getResourceAsStream(resourcePath); where
|
||||
* resourcePath is for example:
|
||||
* /javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd Unfortunately, the
|
||||
* dtd file is not in the exact same classloader as ParserUtils class and
|
||||
* the dtds are packaged in 2 separate bundles. OSGi does not look in the
|
||||
* dependencies' classloader when a resource is searched.
|
||||
* <p>
|
||||
* The workaround consists of setting the entity resolver. That is a patch
|
||||
* added to the version of glassfish-jasper-jetty. IT is also present in the latest
|
||||
* version of glassfish jasper. Could not use introspection to set new value
|
||||
* on a static friendly field :(
|
||||
* The workaround consists of setting the entity resolver. That is a patch
|
||||
* added to the version of glassfish-jasper-jetty. IT is also present in the
|
||||
* latest version of glassfish jasper. Could not use introspection to set
|
||||
* new value on a static friendly field :(
|
||||
* </p>
|
||||
*/
|
||||
void fixupDtdResolution()
|
||||
void fixupDtdResolution()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -199,29 +208,23 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
|
|||
}
|
||||
|
||||
/**
|
||||
* Instead of using the ParserUtil's classloader, we use a class that is indeed next to the resource for sure.
|
||||
* Instead of using the ParserUtil's classloader, we use a class that is
|
||||
* indeed next to the resource for sure.
|
||||
*/
|
||||
static class MyFixedupEntityResolver implements EntityResolver
|
||||
{
|
||||
/**
|
||||
* Same values than in ParserUtils...
|
||||
*/
|
||||
static final String[] CACHED_DTD_PUBLIC_IDS =
|
||||
{ Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12,
|
||||
Constants.WEBAPP_DTD_PUBLIC_ID_22, Constants.WEBAPP_DTD_PUBLIC_ID_23, };
|
||||
static final String[] CACHED_DTD_PUBLIC_IDS = { Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12,
|
||||
Constants.WEBAPP_DTD_PUBLIC_ID_22, Constants.WEBAPP_DTD_PUBLIC_ID_23, };
|
||||
|
||||
static final String[] CACHED_DTD_RESOURCE_PATHS =
|
||||
{ Constants.TAGLIB_DTD_RESOURCE_PATH_11,
|
||||
Constants.TAGLIB_DTD_RESOURCE_PATH_12,
|
||||
Constants.WEBAPP_DTD_RESOURCE_PATH_22,
|
||||
Constants.WEBAPP_DTD_RESOURCE_PATH_23, };
|
||||
static final String[] CACHED_DTD_RESOURCE_PATHS = { Constants.TAGLIB_DTD_RESOURCE_PATH_11, Constants.TAGLIB_DTD_RESOURCE_PATH_12,
|
||||
Constants.WEBAPP_DTD_RESOURCE_PATH_22, Constants.WEBAPP_DTD_RESOURCE_PATH_23, };
|
||||
|
||||
static final String[] CACHED_SCHEMA_RESOURCE_PATHS = { Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20, Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21,
|
||||
Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24, Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25, };
|
||||
|
||||
static final String[] CACHED_SCHEMA_RESOURCE_PATHS = {
|
||||
Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20,
|
||||
Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21,
|
||||
Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24,
|
||||
Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25,
|
||||
};
|
||||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException
|
||||
{
|
||||
for (int i = 0; i < CACHED_DTD_PUBLIC_IDS.length; i++)
|
||||
|
@ -242,10 +245,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
|
|||
input = this.getClass().getResourceAsStream(resourcePath);
|
||||
}
|
||||
}
|
||||
if (input == null)
|
||||
{
|
||||
throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound",resourcePath));
|
||||
}
|
||||
if (input == null) { throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound", resourcePath)); }
|
||||
InputSource isrc = new InputSource(input);
|
||||
return isrc;
|
||||
}
|
||||
|
@ -254,5 +254,5 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -19,15 +19,14 @@ import org.osgi.framework.BundleActivator;
|
|||
import org.osgi.framework.BundleContext;
|
||||
|
||||
/**
|
||||
* Pseudo fragment activator.
|
||||
* Called by the main org.eclipse.jetty.osgi.boot bundle.
|
||||
* Please note: this is not a real BundleActivator. Simply something called back by
|
||||
* the host bundle.
|
||||
* Pseudo fragment activator. Called by the main org.eclipse.jetty.osgi.boot
|
||||
* bundle. Please note: this is not a real BundleActivator. Simply something
|
||||
* called back by the host bundle.
|
||||
* <p>
|
||||
* It must be placed in the org.eclipse.jetty.osgi.boot.jsp package:
|
||||
* this is because org.eclipse.jetty.osgi.boot.jsp is the sympbolic-name
|
||||
* of this fragment. From that name, the PackageadminTracker will call
|
||||
* this class. IN a different package it won't be called.
|
||||
* It must be placed in the org.eclipse.jetty.osgi.boot.jsp package: this is
|
||||
* because org.eclipse.jetty.osgi.boot.jsp is the sympbolic-name of this
|
||||
* fragment. From that name, the PackageadminTracker will call this class. IN a
|
||||
* different package it won't be called.
|
||||
* </p>
|
||||
*/
|
||||
public class FragmentActivator implements BundleActivator
|
||||
|
@ -35,7 +34,8 @@ public class FragmentActivator implements BundleActivator
|
|||
/**
|
||||
*
|
||||
*/
|
||||
public void start(BundleContext context) throws Exception {
|
||||
public void start(BundleContext context) throws Exception
|
||||
{
|
||||
System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString());
|
||||
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl());
|
||||
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl());
|
||||
|
@ -44,7 +44,8 @@ public class FragmentActivator implements BundleActivator
|
|||
/**
|
||||
*
|
||||
*/
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
|
||||
public void stop(BundleContext context) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,123 +35,120 @@ import org.osgi.util.tracker.ServiceTracker;
|
|||
* Replacement for {@link TagLibConfiguration} for the OSGi integration.
|
||||
* </p>
|
||||
* <p>
|
||||
* In the case of a WAB, tlds can be located in OSGi bundles that are dependencies
|
||||
* of the WAB.
|
||||
* It is expected that each WAB lists the symbolic-names of the bundles that contain
|
||||
* tld files. The list is defined as the value of the header 'Require-TldBundle'
|
||||
* In the case of a WAB, tlds can be located in OSGi bundles that are
|
||||
* dependencies of the WAB. It is expected that each WAB lists the
|
||||
* symbolic-names of the bundles that contain tld files. The list is defined as
|
||||
* the value of the header 'Require-TldBundle'
|
||||
* </p>
|
||||
* <p>
|
||||
* Discussions about this are logged in https://bugs.eclipse.org/bugs/show_bug.cgi?id=306971
|
||||
* Discussions about this are logged in
|
||||
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=306971
|
||||
* </p>
|
||||
*/
|
||||
public class TagLibOSGiConfiguration extends TagLibConfiguration
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(TagLibOSGiConfiguration.class);
|
||||
|
||||
private ServiceTracker packageAdminServiceTracker = null;
|
||||
|
||||
/**
|
||||
* Override the preConfigure; locates the bundles that contain
|
||||
* tld files according to the value of the manifest header Require-TldBundle.
|
||||
* <p>
|
||||
* Set or add to the property TldProcessor.TLDResources the list of located jars
|
||||
* so that the super class will scan those.
|
||||
* </p>
|
||||
*/
|
||||
private ServiceTracker packageAdminServiceTracker = null;
|
||||
|
||||
/**
|
||||
* Override the preConfigure; locates the bundles that contain tld files
|
||||
* according to the value of the manifest header Require-TldBundle.
|
||||
* <p>
|
||||
* Set or add to the property TldProcessor.TLDResources the list of located
|
||||
* jars so that the super class will scan those.
|
||||
* </p>
|
||||
*/
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
String requireTldBundle = (String)context.getAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
|
||||
if (requireTldBundle != null)
|
||||
{
|
||||
Collection<Resource> resources = getRequireTldBundleAsJettyResources(context, requireTldBundle);
|
||||
if (resources != null && !resources.isEmpty())
|
||||
{
|
||||
Collection<Resource> previouslySet = (Collection<Resource>)
|
||||
context.getAttribute(TagLibConfiguration.TLD_RESOURCES);
|
||||
if (previouslySet != null)
|
||||
{
|
||||
resources.addAll(previouslySet);
|
||||
}
|
||||
context.setAttribute(TagLibConfiguration.TLD_RESOURCES, resources);
|
||||
}
|
||||
}
|
||||
super.preConfigure(context);
|
||||
String requireTldBundle = (String) context.getAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
|
||||
if (requireTldBundle != null)
|
||||
{
|
||||
Collection<Resource> resources = getRequireTldBundleAsJettyResources(context, requireTldBundle);
|
||||
if (resources != null && !resources.isEmpty())
|
||||
{
|
||||
Collection<Resource> previouslySet = (Collection<Resource>) context.getAttribute(TagLibConfiguration.TLD_RESOURCES);
|
||||
if (previouslySet != null)
|
||||
{
|
||||
resources.addAll(previouslySet);
|
||||
}
|
||||
context.setAttribute(TagLibConfiguration.TLD_RESOURCES, resources);
|
||||
}
|
||||
}
|
||||
super.preConfigure(context);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requireTldBundle The comma separated list of bundles' symbolic names
|
||||
* that contain tld for this osgi webapp.
|
||||
* @param requireTldBundle The comma separated list of bundles' symbolic
|
||||
* names that contain tld for this osgi webapp.
|
||||
* @return The collection of jars or folders that match those bundles.
|
||||
*/
|
||||
private Collection<Resource> getRequireTldBundleAsJettyResources(
|
||||
WebAppContext context, String requireTldBundle)
|
||||
private Collection<Resource> getRequireTldBundleAsJettyResources(WebAppContext context, String requireTldBundle)
|
||||
{
|
||||
Bundle bundle = (Bundle)
|
||||
context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
|
||||
PackageAdmin packAdmin = getBundleAdmin();
|
||||
String[] symbNames = requireTldBundle.split(", ");
|
||||
Collection<Resource> tlds = new LinkedHashSet<Resource>();
|
||||
for (String symbName : symbNames)
|
||||
{
|
||||
Bundle[] bs = packAdmin.getBundles(symbName, null);
|
||||
if (bs == null || bs.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate the bundle '"
|
||||
+ symbName + "' specified in the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName());
|
||||
}
|
||||
//take the first one as it is the most recent version?
|
||||
Enumeration<URL> en = bs[0].findEntries("META-INF", "*.tld", false);
|
||||
boolean atLeastOneTldFound = false;
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
atLeastOneTldFound = true;
|
||||
URL oriUrl = en.nextElement();
|
||||
URL url = DefaultFileLocatorHelper.getLocalURL(oriUrl);
|
||||
Resource tldResource;
|
||||
try
|
||||
{
|
||||
tldResource = Resource.newResource(url);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate the "
|
||||
+ "tld resource in '"
|
||||
+ url.toString()
|
||||
+ "' in the bundle '" + bs[0].getSymbolicName()
|
||||
+ "' while registering the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName(), e);
|
||||
}
|
||||
tlds.add(tldResource);
|
||||
}
|
||||
if (!atLeastOneTldFound)
|
||||
{
|
||||
LOG.warn("No '/META-INF/*.tld' resources were found "
|
||||
+ " in the bundle '" + bs[0].getSymbolicName()
|
||||
+ "' while registering the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName());
|
||||
}
|
||||
}
|
||||
return tlds;
|
||||
Bundle bundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
|
||||
PackageAdmin packAdmin = getBundleAdmin();
|
||||
String[] symbNames = requireTldBundle.split(", ");
|
||||
Collection<Resource> tlds = new LinkedHashSet<Resource>();
|
||||
for (String symbName : symbNames)
|
||||
{
|
||||
Bundle[] bs = packAdmin.getBundles(symbName, null);
|
||||
if (bs == null || bs.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
|
||||
+ "' specified in the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName());
|
||||
}
|
||||
// take the first one as it is the most recent version?
|
||||
Enumeration<URL> en = bs[0].findEntries("META-INF", "*.tld", false);
|
||||
boolean atLeastOneTldFound = false;
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
atLeastOneTldFound = true;
|
||||
URL oriUrl = en.nextElement();
|
||||
URL url = DefaultFileLocatorHelper.getLocalURL(oriUrl);
|
||||
Resource tldResource;
|
||||
try
|
||||
{
|
||||
tldResource = Resource.newResource(url);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate the " + "tld resource in '"
|
||||
+ url.toString()
|
||||
+ "' in the bundle '"
|
||||
+ bs[0].getSymbolicName()
|
||||
+ "' while registering the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName(), e);
|
||||
}
|
||||
tlds.add(tldResource);
|
||||
}
|
||||
if (!atLeastOneTldFound)
|
||||
{
|
||||
LOG.warn("No '/META-INF/*.tld' resources were found " + " in the bundle '"
|
||||
+ bs[0].getSymbolicName()
|
||||
+ "' while registering the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName());
|
||||
}
|
||||
}
|
||||
return tlds;
|
||||
}
|
||||
|
||||
private PackageAdmin getBundleAdmin()
|
||||
{
|
||||
if (packageAdminServiceTracker == null)
|
||||
{
|
||||
Bundle bootBundle = ((BundleReference)OSGiWebappConstants.class.getClassLoader()).getBundle();
|
||||
packageAdminServiceTracker = new ServiceTracker(bootBundle.getBundleContext(),
|
||||
PackageAdmin.class.getName(), null);
|
||||
packageAdminServiceTracker.open();
|
||||
}
|
||||
return (PackageAdmin) packageAdminServiceTracker.getService();
|
||||
}
|
||||
|
||||
|
||||
private PackageAdmin getBundleAdmin()
|
||||
{
|
||||
if (packageAdminServiceTracker == null)
|
||||
{
|
||||
Bundle bootBundle = ((BundleReference) OSGiWebappConstants.class.getClassLoader()).getBundle();
|
||||
packageAdminServiceTracker = new ServiceTracker(bootBundle.getBundleContext(), PackageAdmin.class.getName(), null);
|
||||
packageAdminServiceTracker.open();
|
||||
}
|
||||
return (PackageAdmin) packageAdminServiceTracker.getService();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: Jetty-OSGi-Logback integration
|
||||
Fragment-Host: org.eclipse.jetty.osgi.boot
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.logback;singleton:=true
|
||||
Bundle-Version: 7.6.2.qualifier
|
||||
Bundle-Version: 7.6.3.qualifier
|
||||
Bundle-Vendor: Mort Bay Consulting
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
Import-Package: ch.qos.logback.classic,
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Support for rfc66 war url scheme
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.warurl;singleton:=true
|
||||
Bundle-Version: 7.6.2.qualifier
|
||||
Bundle-Version: 7.6.3.qualifier
|
||||
Bundle-Activator: org.eclipse.jetty.osgi.boot.warurl.WarUrlActivator
|
||||
Bundle-Vendor: Mort Bay Consulting
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
|
|
|
@ -24,12 +24,13 @@ import java.util.jar.Manifest;
|
|||
import org.eclipse.jetty.osgi.boot.warurl.internal.WarBundleManifestGenerator;
|
||||
import org.eclipse.jetty.osgi.boot.warurl.internal.WarURLConnection;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.osgi.service.url.AbstractURLStreamHandlerService;
|
||||
|
||||
/**
|
||||
* RFC-66: support for the "war" protocol
|
||||
* We are reusing the parsing of the query string from jetty.
|
||||
* If we wanted to not depend on jetty at all we could duplicate that method here
|
||||
* RFC-66: support for the "war" protocol We are reusing the parsing of the
|
||||
* query string from jetty. If we wanted to not depend on jetty at all we could
|
||||
* duplicate that method here
|
||||
*/
|
||||
public class WarUrlStreamHandler extends AbstractURLStreamHandlerService
|
||||
{
|
||||
|
@ -40,11 +41,11 @@ public class WarUrlStreamHandler extends AbstractURLStreamHandlerService
|
|||
@Override
|
||||
public URLConnection openConnection(URL url) throws IOException
|
||||
{
|
||||
//remove the war scheme.
|
||||
// remove the war scheme.
|
||||
URL actual = new URL(url.toString().substring("war:".length()));
|
||||
|
||||
//let's do some basic tests: see if this is a folder or not.
|
||||
//if it is a folder. we will try to support it.
|
||||
|
||||
// let's do some basic tests: see if this is a folder or not.
|
||||
// if it is a folder. we will try to support it.
|
||||
if (actual.getProtocol().equals("file"))
|
||||
{
|
||||
File file = new File(URIUtil.encodePath(actual.getPath()));
|
||||
|
@ -52,34 +53,48 @@ public class WarUrlStreamHandler extends AbstractURLStreamHandlerService
|
|||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
//TODO (not mandatory for rfc66 though)
|
||||
// TODO (not mandatory for rfc66 though)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (actual.toString().startsWith("file:/") && ! actual.to)
|
||||
|
||||
// if (actual.toString().startsWith("file:/") && ! actual.to)
|
||||
URLConnection ori = (URLConnection) actual.openConnection();
|
||||
ori.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
JarURLConnection jarOri = null;
|
||||
try {
|
||||
try
|
||||
{
|
||||
if (ori instanceof JarURLConnection)
|
||||
{
|
||||
jarOri = (JarURLConnection)ori;
|
||||
jarOri = (JarURLConnection) ori;
|
||||
}
|
||||
else
|
||||
{
|
||||
jarOri = (JarURLConnection) new URL("jar:"+actual.toString() + "!/").openConnection();
|
||||
jarOri = (JarURLConnection) new URL("jar:" + actual.toString() + "!/").openConnection();
|
||||
jarOri.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
}
|
||||
Manifest mf = WarBundleManifestGenerator.createBundleManifest(
|
||||
jarOri.getManifest(), url, jarOri.getJarFile());
|
||||
try { jarOri.getJarFile().close(); jarOri = null; } catch (Throwable t) {}
|
||||
return new WarURLConnection(actual,mf);
|
||||
Manifest mf = WarBundleManifestGenerator.createBundleManifest(jarOri.getManifest(), url, jarOri.getJarFile());
|
||||
try
|
||||
{
|
||||
jarOri.getJarFile().close();
|
||||
jarOri = null;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
}
|
||||
return new WarURLConnection(actual, mf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (jarOri != null) try { jarOri.getJarFile().close(); } catch (Throwable t) {}
|
||||
if (jarOri != null) try
|
||||
{
|
||||
jarOri.getJarFile().close();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.jar.Manifest;
|
|||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
||||
/**
|
||||
* Facade for a URLConnection that will read a jar and substitute its
|
||||
|
@ -106,6 +107,7 @@ public class WarURLConnection extends URLConnection
|
|||
{
|
||||
super(url);
|
||||
_conn = url.openConnection();
|
||||
_conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
_mf = mf;
|
||||
}
|
||||
@Override
|
||||
|
|
|
@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: Jetty OSGi bootstrap
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.boot;singleton:=true
|
||||
Bundle-Vendor: Mort Bay Consulting
|
||||
Bundle-Version: 7.6.2.qualifier
|
||||
Bundle-Version: 7.6.3.qualifier
|
||||
Bundle-Activator: org.eclipse.jetty.osgi.boot.JettyBootstrapActivator
|
||||
Import-Package: javax.mail;version="1.4.0";resolution:=optional,
|
||||
javax.mail.event;version="1.4.0";resolution:=optional,
|
||||
|
@ -14,19 +14,19 @@ Import-Package: javax.mail;version="1.4.0";resolution:=optional,
|
|||
javax.servlet.http;version="2.5.0",
|
||||
javax.transaction;version="1.1.0";resolution:=optional,
|
||||
javax.transaction.xa;version="1.1.0";resolution:=optional,
|
||||
org.eclipse.jetty.deploy;version="7.6.2",
|
||||
org.eclipse.jetty.deploy.providers;version="7.6.2",
|
||||
org.eclipse.jetty.http;version="7.6.2",
|
||||
org.eclipse.jetty.nested;version="7.6.2";resolution:=optional,
|
||||
org.eclipse.jetty.server;version="7.6.2",
|
||||
org.eclipse.jetty.server.handler;version="7.6.2",
|
||||
org.eclipse.jetty.servlet;version="7.6.2",
|
||||
org.eclipse.jetty.util;version="7.6.2",
|
||||
org.eclipse.jetty.util.component;version="7.6.2",
|
||||
org.eclipse.jetty.util.log;version="7.6.2",
|
||||
org.eclipse.jetty.util.resource;version="7.6.2",
|
||||
org.eclipse.jetty.webapp;version="7.6.2",
|
||||
org.eclipse.jetty.xml;version="7.6.2",
|
||||
org.eclipse.jetty.deploy;version="7.6.3",
|
||||
org.eclipse.jetty.deploy.providers;version="7.6.3",
|
||||
org.eclipse.jetty.http;version="7.6.3",
|
||||
org.eclipse.jetty.nested;version="7.6.3";resolution:=optional,
|
||||
org.eclipse.jetty.server;version="7.6.3",
|
||||
org.eclipse.jetty.server.handler;version="7.6.3",
|
||||
org.eclipse.jetty.servlet;version="7.6.3",
|
||||
org.eclipse.jetty.util;version="7.6.3",
|
||||
org.eclipse.jetty.util.component;version="7.6.3",
|
||||
org.eclipse.jetty.util.log;version="7.6.3",
|
||||
org.eclipse.jetty.util.resource;version="7.6.3",
|
||||
org.eclipse.jetty.webapp;version="7.6.3",
|
||||
org.eclipse.jetty.xml;version="7.6.3",
|
||||
org.osgi.framework,
|
||||
org.osgi.service.cm;version="1.2.0",
|
||||
org.osgi.service.packageadmin,
|
||||
|
@ -40,7 +40,7 @@ Import-Package: javax.mail;version="1.4.0";resolution:=optional,
|
|||
org.xml.sax.helpers
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
Bundle-Classpath: .
|
||||
Export-Package: org.eclipse.jetty.osgi.boot;version="7.6.2",
|
||||
org.eclipse.jetty.osgi.nested;version="7.6.2",
|
||||
org.eclipse.jetty.osgi.boot.utils;version="7.6.2"
|
||||
Export-Package: org.eclipse.jetty.osgi.boot;version="7.6.3",
|
||||
org.eclipse.jetty.osgi.nested;version="7.6.3",
|
||||
org.eclipse.jetty.osgi.boot.utils;version="7.6.3"
|
||||
DynamicImport-Package: org.eclipse.jetty.*;version="[7.3,8)"
|
||||
|
|
|
@ -66,15 +66,19 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
}
|
||||
|
||||
private ServiceRegistration _registeredServer;
|
||||
|
||||
private Server _server;
|
||||
|
||||
private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
|
||||
|
||||
private PackageAdminServiceTracker _packageAdminServiceTracker;
|
||||
|
||||
private BundleTracker _webBundleTracker;
|
||||
|
||||
private BundleContext _bundleContext;
|
||||
|
||||
// private ServiceRegistration _jettyServerFactoryService;
|
||||
|
||||
// private ServiceRegistration _jettyServerFactoryService;
|
||||
private JettyServerServiceTracker _jettyServerServiceTracker;
|
||||
|
||||
|
||||
/**
|
||||
* Setup a new jetty Server, registers it as a service. Setup the Service
|
||||
|
@ -93,30 +97,31 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
// should activate.
|
||||
_packageAdminServiceTracker = new PackageAdminServiceTracker(context);
|
||||
|
||||
_jettyServerServiceTracker = new JettyServerServiceTracker();
|
||||
context.addServiceListener(_jettyServerServiceTracker,"(objectclass=" + Server.class.getName() + ")");
|
||||
_jettyServerServiceTracker = new JettyServerServiceTracker();
|
||||
context.addServiceListener(_jettyServerServiceTracker, "(objectclass=" + Server.class.getName() + ")");
|
||||
|
||||
// Register the Jetty Server Factory as a ManagedServiceFactory:
|
||||
// Properties jettyServerMgdFactoryServiceProps = new Properties();
|
||||
// jettyServerMgdFactoryServiceProps.put("pid",
|
||||
// OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID);
|
||||
// _jettyServerFactoryService = context.registerService(
|
||||
// ManagedServiceFactory.class.getName(), new
|
||||
// JettyServersManagedFactory(),
|
||||
// jettyServerMgdFactoryServiceProps);
|
||||
|
||||
//Register the Jetty Server Factory as a ManagedServiceFactory:
|
||||
// Properties jettyServerMgdFactoryServiceProps = new Properties();
|
||||
// jettyServerMgdFactoryServiceProps.put("pid", OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID);
|
||||
// _jettyServerFactoryService = context.registerService(
|
||||
// ManagedServiceFactory.class.getName(), new JettyServersManagedFactory(),
|
||||
// jettyServerMgdFactoryServiceProps);
|
||||
|
||||
_jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker);
|
||||
|
||||
// the tracker in charge of the actual deployment
|
||||
// and that will configure and start the jetty server.
|
||||
context.addServiceListener(_jettyContextHandlerTracker,"(objectclass=" + ContextHandler.class.getName() + ")");
|
||||
context.addServiceListener(_jettyContextHandlerTracker, "(objectclass=" + ContextHandler.class.getName() + ")");
|
||||
|
||||
//see if we shoult start a default jetty instance right now.
|
||||
// see if we shoult start a default jetty instance right now.
|
||||
DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
|
||||
|
||||
// now ready to support the Extender pattern:
|
||||
_webBundleTracker = new BundleTracker(context,
|
||||
Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
|
||||
|
||||
// now ready to support the Extender pattern:
|
||||
_webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
|
||||
_webBundleTracker.open();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -129,12 +134,12 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (_webBundleTracker != null)
|
||||
{
|
||||
_webBundleTracker.close();
|
||||
_webBundleTracker = null;
|
||||
}
|
||||
|
||||
if (_webBundleTracker != null)
|
||||
{
|
||||
_webBundleTracker.close();
|
||||
_webBundleTracker = null;
|
||||
}
|
||||
if (_jettyContextHandlerTracker != null)
|
||||
{
|
||||
_jettyContextHandlerTracker.stop();
|
||||
|
@ -143,7 +148,7 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
}
|
||||
if (_jettyServerServiceTracker != null)
|
||||
{
|
||||
_jettyServerServiceTracker.stop();
|
||||
_jettyServerServiceTracker.stop();
|
||||
context.removeServiceListener(_jettyServerServiceTracker);
|
||||
_jettyServerServiceTracker = null;
|
||||
}
|
||||
|
@ -165,31 +170,31 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
}
|
||||
finally
|
||||
{
|
||||
_registeredServer = null;
|
||||
_registeredServer = null;
|
||||
}
|
||||
}
|
||||
// if (_jettyServerFactoryService != null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// _jettyServerFactoryService.unregister();
|
||||
// }
|
||||
// catch (IllegalArgumentException ill)
|
||||
// {
|
||||
// // already unregistered.
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// _jettyServerFactoryService = null;
|
||||
// }
|
||||
// }
|
||||
// if (_jettyServerFactoryService != null)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// _jettyServerFactoryService.unregister();
|
||||
// }
|
||||
// catch (IllegalArgumentException ill)
|
||||
// {
|
||||
// // already unregistered.
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// _jettyServerFactoryService = null;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
_server.stop();
|
||||
}
|
||||
INSTANCE = null;
|
||||
}
|
||||
|
@ -200,27 +205,25 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
* registers it as an OSGi service. The tracker
|
||||
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
|
||||
*
|
||||
* @param contributor
|
||||
* The bundle
|
||||
* @param webappFolderPath
|
||||
* The path to the root of the webapp. Must be a path relative to
|
||||
* bundle; either an absolute path.
|
||||
* @param contextPath
|
||||
* The context path. Must start with "/"
|
||||
* @param contributor The bundle
|
||||
* @param webappFolderPath The path to the root of the webapp. Must be a
|
||||
* path relative to bundle; either an absolute path.
|
||||
* @param contextPath The context path. Must start with "/"
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception
|
||||
{
|
||||
checkBundleActivated();
|
||||
WebAppContext contextHandler = new WebAppContext();
|
||||
checkBundleActivated();
|
||||
WebAppContext contextHandler = new WebAppContext();
|
||||
Dictionary dic = new Hashtable();
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath);
|
||||
String requireTldBundle = (String)contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
|
||||
if (requireTldBundle != null) {
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
|
||||
String requireTldBundle = (String) contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
|
||||
if (requireTldBundle != null)
|
||||
{
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle);
|
||||
}
|
||||
contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
|
||||
contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,24 +231,20 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
* registers it as an OSGi service. The tracker
|
||||
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
|
||||
*
|
||||
* @param contributor
|
||||
* The bundle
|
||||
* @param webappFolderPath
|
||||
* The path to the root of the webapp. Must be a path relative to
|
||||
* bundle; either an absolute path.
|
||||
* @param contextPath
|
||||
* The context path. Must start with "/"
|
||||
* @param dic
|
||||
* TODO: parameter description
|
||||
* @param contributor The bundle
|
||||
* @param webappFolderPath The path to the root of the webapp. Must be a
|
||||
* path relative to bundle; either an absolute path.
|
||||
* @param contextPath The context path. Must start with "/"
|
||||
* @param dic TODO: parameter description
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception
|
||||
{
|
||||
checkBundleActivated();
|
||||
checkBundleActivated();
|
||||
WebAppContext contextHandler = new WebAppContext();
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath);
|
||||
contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
|
||||
contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,16 +252,14 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
* registers it as an OSGi service. The tracker
|
||||
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
|
||||
*
|
||||
* @param contributor
|
||||
* The bundle that registers a new context
|
||||
* @param contextFilePath
|
||||
* The path to the file inside the bundle that defines the
|
||||
* context.
|
||||
* @param contributor The bundle that registers a new context
|
||||
* @param contextFilePath The path to the file inside the bundle that
|
||||
* defines the context.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void registerContext(Bundle contributor, String contextFilePath) throws Exception
|
||||
{
|
||||
registerContext(contributor,contextFilePath,new Hashtable<String, String>());
|
||||
registerContext(contributor, contextFilePath, new Hashtable<String, String>());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,33 +267,30 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
* registers it as an OSGi service. The tracker
|
||||
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
|
||||
*
|
||||
* @param contributor
|
||||
* The bundle that registers a new context
|
||||
* @param contextFilePath
|
||||
* The path to the file inside the bundle that defines the
|
||||
* context.
|
||||
* @param dic
|
||||
* TODO: parameter description
|
||||
* @param contributor The bundle that registers a new context
|
||||
* @param contextFilePath The path to the file inside the bundle that
|
||||
* defines the context.
|
||||
* @param dic TODO: parameter description
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception
|
||||
{
|
||||
checkBundleActivated();
|
||||
checkBundleActivated();
|
||||
ContextHandler contextHandler = new ContextHandler();
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH,contextFilePath);
|
||||
dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE,Boolean.TRUE.toString());
|
||||
contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
|
||||
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH, contextFilePath);
|
||||
dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE, Boolean.TRUE.toString());
|
||||
contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
|
||||
}
|
||||
|
||||
public static void unregister(String contextPath)
|
||||
{
|
||||
// todo
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Since org.eclipse.jetty.osgi.boot does not have a lazy activation policy
|
||||
* when one fo the static methods to register a webapp is called we should make sure that
|
||||
* the bundle is started.
|
||||
* when one fo the static methods to register a webapp is called we should
|
||||
* make sure that the bundle is started.
|
||||
*/
|
||||
private static void checkBundleActivated()
|
||||
{
|
||||
|
@ -313,7 +307,7 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The bundle context for this bundle.
|
||||
*/
|
||||
|
@ -322,6 +316,5 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
checkBundleActivated();
|
||||
return INSTANCE._bundleContext;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -349,7 +349,7 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -370,11 +370,11 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isExtract()
|
||||
{
|
||||
return _extractWars;
|
||||
|
|
|
@ -39,7 +39,7 @@ import org.osgi.framework.BundleContext;
|
|||
public class DefaultJettyAtJettyHomeHelper {
|
||||
private static final Logger LOG = Log.getLogger(DefaultJettyAtJettyHomeHelper.class);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* contains a comma separated list of pathes to the etc/jetty-*.xml files
|
||||
* used to configure jetty. By default the value is 'etc/jetty.xml' when the
|
||||
|
@ -69,7 +69,7 @@ public class DefaultJettyAtJettyHomeHelper {
|
|||
* Usual system property used as the port for https for a typical jetty configuration.
|
||||
*/
|
||||
public static final String SYS_PROP_JETTY_PORT_SSL = "jetty.port.ssl";
|
||||
|
||||
|
||||
/**
|
||||
* Called by the JettyBootStrapActivator.
|
||||
* If the system property jetty.home is defined and points to a folder,
|
||||
|
@ -88,81 +88,76 @@ public class DefaultJettyAtJettyHomeHelper {
|
|||
* that might use them as part of their properties.
|
||||
* </p>
|
||||
*/
|
||||
public static void startJettyAtJettyHome(BundleContext bundleContext)
|
||||
public static void startJettyAtJettyHome(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
String jettyHomeSysProp = System.getProperty(SYS_PROP_JETTY_HOME);
|
||||
String jettyHomeBundleSysProp = System.getProperty(SYS_PROP_JETTY_HOME_BUNDLE);
|
||||
File jettyHome = null;
|
||||
Bundle jettyHomeBundle = null;
|
||||
if (jettyHomeSysProp != null)
|
||||
{
|
||||
jettyHomeSysProp = resolvePropertyValue(jettyHomeSysProp);
|
||||
//bug 329621
|
||||
if (jettyHomeSysProp.startsWith("\"") && jettyHomeSysProp.endsWith("\"")
|
||||
|| (jettyHomeSysProp.startsWith("'") && jettyHomeSysProp.endsWith("'"))) {
|
||||
jettyHomeSysProp = jettyHomeSysProp.substring(1, jettyHomeSysProp.length() - 1);
|
||||
}
|
||||
if (jettyHomeBundleSysProp != null)
|
||||
{
|
||||
LOG.warn("Both the jetty.home property and the jetty.home.bundle property are defined."
|
||||
+ " jetty.home.bundle is not taken into account.");
|
||||
}
|
||||
jettyHome = new File(jettyHomeSysProp);
|
||||
if (!jettyHome.exists() || !jettyHome.isDirectory())
|
||||
{
|
||||
LOG.warn("Unable to locate the jetty.home folder " + jettyHomeSysProp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (jettyHomeBundleSysProp != null)
|
||||
{
|
||||
jettyHomeBundleSysProp = resolvePropertyValue(jettyHomeBundleSysProp);
|
||||
for (Bundle b : bundleContext.getBundles())
|
||||
{
|
||||
if (b.getSymbolicName().equals(jettyHomeBundleSysProp))
|
||||
{
|
||||
jettyHomeBundle = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jettyHomeBundle == null)
|
||||
{
|
||||
LOG.warn("Unable to find the jetty.home.bundle named " + jettyHomeSysProp);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if (jettyHome == null && jettyHomeBundle == null)
|
||||
{
|
||||
LOG.warn("No default jetty started.");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
Server server = new Server();
|
||||
Dictionary properties = new Hashtable();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME);
|
||||
|
||||
String configURLs = jettyHome != null ? getJettyConfigurationURLs(jettyHome) : getJettyConfigurationURLs(jettyHomeBundle);
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS, configURLs);
|
||||
String jettyHomeSysProp = System.getProperty(SYS_PROP_JETTY_HOME);
|
||||
String jettyHomeBundleSysProp = System.getProperty(SYS_PROP_JETTY_HOME_BUNDLE);
|
||||
File jettyHome = null;
|
||||
Bundle jettyHomeBundle = null;
|
||||
if (jettyHomeSysProp != null)
|
||||
{
|
||||
jettyHomeSysProp = resolvePropertyValue(jettyHomeSysProp);
|
||||
//bug 329621
|
||||
if (jettyHomeSysProp.startsWith("\"") && jettyHomeSysProp.endsWith("\"")
|
||||
|| (jettyHomeSysProp.startsWith("'") && jettyHomeSysProp.endsWith("'"))) {
|
||||
jettyHomeSysProp = jettyHomeSysProp.substring(1, jettyHomeSysProp.length() - 1);
|
||||
}
|
||||
if (jettyHomeBundleSysProp != null)
|
||||
{
|
||||
LOG.warn("Both the jetty.home property and the jetty.home.bundle property are defined."
|
||||
+ " jetty.home.bundle is not taken into account.");
|
||||
}
|
||||
jettyHome = new File(jettyHomeSysProp);
|
||||
if (!jettyHome.exists() || !jettyHome.isDirectory())
|
||||
{
|
||||
LOG.warn("Unable to locate the jetty.home folder " + jettyHomeSysProp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (jettyHomeBundleSysProp != null)
|
||||
{
|
||||
jettyHomeBundleSysProp = resolvePropertyValue(jettyHomeBundleSysProp);
|
||||
for (Bundle b : bundleContext.getBundles())
|
||||
{
|
||||
if (b.getSymbolicName().equals(jettyHomeBundleSysProp))
|
||||
{
|
||||
jettyHomeBundle = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jettyHomeBundle == null)
|
||||
{
|
||||
LOG.warn("Unable to find the jetty.home.bundle named " + jettyHomeSysProp);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.info("Configuring the default jetty server with " + configURLs);
|
||||
|
||||
//these properties usually are the ones passed to this type of configuration.
|
||||
setProperty(properties,SYS_PROP_JETTY_HOME,System.getProperty(SYS_PROP_JETTY_HOME));
|
||||
setProperty(properties,SYS_PROP_JETTY_HOST,System.getProperty(SYS_PROP_JETTY_HOST));
|
||||
setProperty(properties,SYS_PROP_JETTY_PORT,System.getProperty(SYS_PROP_JETTY_PORT));
|
||||
setProperty(properties,SYS_PROP_JETTY_PORT_SSL,System.getProperty(SYS_PROP_JETTY_PORT_SSL));
|
||||
}
|
||||
if (jettyHome == null && jettyHomeBundle == null)
|
||||
{
|
||||
LOG.warn("No default jetty started.");
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = new Server();
|
||||
Dictionary properties = new Hashtable();
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME);
|
||||
|
||||
String configURLs = jettyHome != null ? getJettyConfigurationURLs(jettyHome) : getJettyConfigurationURLs(jettyHomeBundle);
|
||||
properties.put(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS, configURLs);
|
||||
|
||||
LOG.info("Configuring the default jetty server with " + configURLs);
|
||||
|
||||
//these properties usually are the ones passed to this type of configuration.
|
||||
setProperty(properties,SYS_PROP_JETTY_HOME,System.getProperty(SYS_PROP_JETTY_HOME));
|
||||
setProperty(properties,SYS_PROP_JETTY_HOST,System.getProperty(SYS_PROP_JETTY_HOST));
|
||||
setProperty(properties,SYS_PROP_JETTY_PORT,System.getProperty(SYS_PROP_JETTY_PORT));
|
||||
setProperty(properties,SYS_PROP_JETTY_PORT_SSL,System.getProperty(SYS_PROP_JETTY_PORT_SSL));
|
||||
|
||||
bundleContext.registerService(Server.class.getName(), server, properties);
|
||||
// hookNestedConnectorToBridgeServlet(server);
|
||||
|
||||
bundleContext.registerService(Server.class.getName(), server, properties);
|
||||
// hookNestedConnectorToBridgeServlet(server);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Minimum setup for the location of the configuration files given a jettyhome folder.
|
||||
* Reads the system property jetty.etc.config.urls and look for the corresponding jetty
|
||||
|
@ -172,22 +167,25 @@ public class DefaultJettyAtJettyHomeHelper {
|
|||
*/
|
||||
private static String getJettyConfigurationURLs(File jettyhome)
|
||||
{
|
||||
String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES,"etc/jetty.xml");
|
||||
StringTokenizer tokenizer = new StringTokenizer(jettyetc,";,", false);
|
||||
String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES, "etc/jetty.xml");
|
||||
StringTokenizer tokenizer = new StringTokenizer(jettyetc, ";,", false);
|
||||
StringBuilder res = new StringBuilder();
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String next = tokenizer.nextToken().trim();
|
||||
if (!next.startsWith("/") && next.indexOf(':') == -1)
|
||||
{
|
||||
try {
|
||||
next = new File(jettyhome, next).toURI().toURL().toString();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
appendToCommaSeparatedList(res, next);
|
||||
String next = tokenizer.nextToken().trim();
|
||||
if (!next.startsWith("/") && next.indexOf(':') == -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
next = new File(jettyhome, next).toURI().toURL().toString();
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
appendToCommaSeparatedList(res, next);
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
@ -202,108 +200,108 @@ public class DefaultJettyAtJettyHomeHelper {
|
|||
*/
|
||||
private static String getJettyConfigurationURLs(Bundle configurationBundle)
|
||||
{
|
||||
String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES,"etc/jetty.xml");
|
||||
String jettyetc = System.getProperty(SYS_PROP_JETTY_ETC_FILES,"etc/jetty.xml");
|
||||
StringTokenizer tokenizer = new StringTokenizer(jettyetc,";,", false);
|
||||
StringBuilder res = new StringBuilder();
|
||||
|
||||
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String etcFile = tokenizer.nextToken().trim();
|
||||
if (etcFile.startsWith("/") || etcFile.indexOf(":") != -1)
|
||||
{
|
||||
appendToCommaSeparatedList(res, etcFile);
|
||||
appendToCommaSeparatedList(res, etcFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
Enumeration<URL> enUrls = BundleFileLocatorHelper.DEFAULT
|
||||
.findEntries(configurationBundle, etcFile);
|
||||
|
||||
//default for org.eclipse.osgi.boot where we look inside jettyhome for the default embedded configuration.
|
||||
//default inside jettyhome. this way fragments to the bundle can define their own configuration.
|
||||
if ((enUrls == null || !enUrls.hasMoreElements()) && etcFile.endsWith("etc/jetty.xml"))
|
||||
{
|
||||
enUrls = BundleFileLocatorHelper.DEFAULT
|
||||
.findEntries(configurationBundle, "/jettyhome/etc/jetty-osgi-default.xml");
|
||||
System.err.println("Configuring jetty with the default embedded configuration:" +
|
||||
"bundle: " + configurationBundle.getSymbolicName() +
|
||||
" config: /jettyhome/etc/jetty-osgi-default.xml");
|
||||
}
|
||||
if (enUrls == null || !enUrls.hasMoreElements())
|
||||
{
|
||||
System.err.println("Unable to locate a jetty configuration file for " + etcFile);
|
||||
}
|
||||
if (enUrls != null)
|
||||
{
|
||||
while (enUrls.hasMoreElements())
|
||||
{
|
||||
appendToCommaSeparatedList(res, enUrls.nextElement().toString());
|
||||
}
|
||||
}
|
||||
Enumeration<URL> enUrls = BundleFileLocatorHelper.DEFAULT
|
||||
.findEntries(configurationBundle, etcFile);
|
||||
|
||||
//default for org.eclipse.osgi.boot where we look inside jettyhome for the default embedded configuration.
|
||||
//default inside jettyhome. this way fragments to the bundle can define their own configuration.
|
||||
if ((enUrls == null || !enUrls.hasMoreElements()) && etcFile.endsWith("etc/jetty.xml"))
|
||||
{
|
||||
enUrls = BundleFileLocatorHelper.DEFAULT
|
||||
.findEntries(configurationBundle, "/jettyhome/etc/jetty-osgi-default.xml");
|
||||
System.err.println("Configuring jetty with the default embedded configuration:" +
|
||||
"bundle: " + configurationBundle.getSymbolicName() +
|
||||
" config: /jettyhome/etc/jetty-osgi-default.xml");
|
||||
}
|
||||
if (enUrls == null || !enUrls.hasMoreElements())
|
||||
{
|
||||
LOG.warn("Unable to locate a jetty configuration file for " + etcFile);
|
||||
}
|
||||
if (enUrls != null)
|
||||
{
|
||||
while (enUrls.hasMoreElements())
|
||||
{
|
||||
appendToCommaSeparatedList(res, enUrls.nextElement().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
private static void appendToCommaSeparatedList(StringBuilder buffer, String value)
|
||||
{
|
||||
if (buffer.length() != 0)
|
||||
{
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append(value);
|
||||
}
|
||||
|
||||
private static void setProperty(Dictionary properties, String key, String value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively substitute the ${sysprop} by their actual system property.
|
||||
* ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no sysprop is defined.
|
||||
* Not the most efficient code but we are shooting for simplicity and speed of development here.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static String resolvePropertyValue(String value)
|
||||
{
|
||||
int ind = value.indexOf("${");
|
||||
if (ind == -1) {
|
||||
return value;
|
||||
}
|
||||
int ind2 = value.indexOf('}', ind);
|
||||
if (ind2 == -1) {
|
||||
return value;
|
||||
}
|
||||
String sysprop = value.substring(ind+2, ind2);
|
||||
String defaultValue = null;
|
||||
int comma = sysprop.indexOf(',');
|
||||
if (comma != -1 && comma+1 != sysprop.length())
|
||||
{
|
||||
defaultValue = sysprop.substring(comma+1);
|
||||
defaultValue = resolvePropertyValue(defaultValue);
|
||||
sysprop = sysprop.substring(0,comma);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = "${" + sysprop + "}";
|
||||
}
|
||||
|
||||
String v = System.getProperty(sysprop);
|
||||
|
||||
String reminder = value.length() > ind2 + 1 ? value.substring(ind2+1) : "";
|
||||
reminder = resolvePropertyValue(reminder);
|
||||
if (v != null)
|
||||
{
|
||||
return value.substring(0, ind) + v + reminder;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.substring(0, ind) + defaultValue + reminder;
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendToCommaSeparatedList(StringBuilder buffer, String value)
|
||||
{
|
||||
if (buffer.length() != 0)
|
||||
{
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append(value);
|
||||
}
|
||||
|
||||
private static void setProperty(Dictionary properties, String key, String value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
properties.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively substitute the ${sysprop} by their actual system property.
|
||||
* ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no sysprop is defined.
|
||||
* Not the most efficient code but we are shooting for simplicity and speed of development here.
|
||||
*
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static String resolvePropertyValue(String value)
|
||||
{
|
||||
int ind = value.indexOf("${");
|
||||
if (ind == -1) {
|
||||
return value;
|
||||
}
|
||||
int ind2 = value.indexOf('}', ind);
|
||||
if (ind2 == -1) {
|
||||
return value;
|
||||
}
|
||||
String sysprop = value.substring(ind+2, ind2);
|
||||
String defaultValue = null;
|
||||
int comma = sysprop.indexOf(',');
|
||||
if (comma != -1 && comma+1 != sysprop.length())
|
||||
{
|
||||
defaultValue = sysprop.substring(comma+1);
|
||||
defaultValue = resolvePropertyValue(defaultValue);
|
||||
sysprop = sysprop.substring(0,comma);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = "${" + sysprop + "}";
|
||||
}
|
||||
|
||||
String v = System.getProperty(sysprop);
|
||||
|
||||
String reminder = value.length() > ind2 + 1 ? value.substring(ind2+1) : "";
|
||||
reminder = resolvePropertyValue(reminder);
|
||||
if (v != null)
|
||||
{
|
||||
return value.substring(0, ind) + v + reminder;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.substring(0, ind) + defaultValue + reminder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,50 +18,53 @@ import java.util.Properties;
|
|||
|
||||
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.ServiceEvent;
|
||||
import org.osgi.framework.ServiceListener;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
* Deploy the jetty server instances when they are registered as an OSGi service.
|
||||
* Deploy the jetty server instances when they are registered as an OSGi
|
||||
* service.
|
||||
*/
|
||||
public class JettyServerServiceTracker implements ServiceListener, IManagedJettyServerRegistry
|
||||
{
|
||||
|
||||
private static Logger LOG = Log.getLogger(JettyServerServiceTracker.class.getName());
|
||||
|
||||
/**
|
||||
* Servers indexed by PIDs. PIDs are generated by the ConfigurationAdmin service.
|
||||
* Servers indexed by PIDs. PIDs are generated by the ConfigurationAdmin
|
||||
* service.
|
||||
*/
|
||||
private Map<String, ServerInstanceWrapper> _serversIndexedByName = new HashMap<String, ServerInstanceWrapper>();
|
||||
|
||||
/** The context-handler to deactivate indexed by ServerInstanceWrapper */
|
||||
private Map<ServiceReference, ServerInstanceWrapper> _indexByServiceReference = new HashMap<ServiceReference, ServerInstanceWrapper>();
|
||||
|
||||
|
||||
/**
|
||||
* Stops each one of the registered servers.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
//not sure that this is really useful but here we go.
|
||||
for (ServerInstanceWrapper wrapper : _serversIndexedByName.values())
|
||||
{
|
||||
try
|
||||
{
|
||||
wrapper.stop();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
// not sure that this is really useful but here we go.
|
||||
for (ServerInstanceWrapper wrapper : _serversIndexedByName.values())
|
||||
{
|
||||
try
|
||||
{
|
||||
wrapper.stop();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Receives notification that a service has had a lifecycle change.
|
||||
*
|
||||
* @param ev
|
||||
* The <code>ServiceEvent</code> object.
|
||||
* @param ev The <code>ServiceEvent</code> object.
|
||||
*/
|
||||
public void serviceChanged(ServiceEvent ev)
|
||||
{
|
||||
|
@ -71,17 +74,16 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
|
|||
case ServiceEvent.MODIFIED:
|
||||
case ServiceEvent.UNREGISTERING:
|
||||
{
|
||||
ServerInstanceWrapper instance = unregisterInIndex(ev.getServiceReference());
|
||||
ServerInstanceWrapper instance = unregisterInIndex(ev.getServiceReference());
|
||||
if (instance != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
instance.stop();
|
||||
instance.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,32 +98,35 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
|
|||
}
|
||||
case ServiceEvent.REGISTERED:
|
||||
{
|
||||
Bundle contributor = sr.getBundle();
|
||||
Server server = (Server)contributor.getBundleContext().getService(sr);
|
||||
ServerInstanceWrapper wrapper = registerInIndex(server, sr);
|
||||
Properties props = new Properties();
|
||||
for (String key : sr.getPropertyKeys())
|
||||
{
|
||||
Object value = sr.getProperty(key);
|
||||
props.put(key, value);
|
||||
}
|
||||
wrapper.start(server, props);
|
||||
break;
|
||||
try
|
||||
{
|
||||
Bundle contributor = sr.getBundle();
|
||||
Server server = (Server) contributor.getBundleContext().getService(sr);
|
||||
ServerInstanceWrapper wrapper = registerInIndex(server, sr);
|
||||
Properties props = new Properties();
|
||||
for (String key : sr.getPropertyKeys())
|
||||
{
|
||||
Object value = sr.getProperty(key);
|
||||
props.put(key, value);
|
||||
}
|
||||
wrapper.start(server, props);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ServerInstanceWrapper registerInIndex(Server server, ServiceReference sr)
|
||||
{
|
||||
String name = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if (name == null)
|
||||
{
|
||||
throw new IllegalArgumentException("The property " +
|
||||
OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory");
|
||||
}
|
||||
String name = (String) sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if (name == null) { throw new IllegalArgumentException("The property " + OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory"); }
|
||||
ServerInstanceWrapper wrapper = new ServerInstanceWrapper(name);
|
||||
_indexByServiceReference.put(sr,wrapper);
|
||||
_serversIndexedByName.put(name,wrapper);
|
||||
_indexByServiceReference.put(sr, wrapper);
|
||||
_serversIndexedByName.put(name, wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
@ -133,7 +138,7 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
|
|||
*/
|
||||
private ServerInstanceWrapper unregisterInIndex(ServiceReference sr)
|
||||
{
|
||||
ServerInstanceWrapper handler = _indexByServiceReference.remove(sr);
|
||||
ServerInstanceWrapper handler = _indexByServiceReference.remove(sr);
|
||||
if (handler == null)
|
||||
{
|
||||
// a warning?
|
||||
|
@ -149,13 +154,12 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
|
|||
|
||||
/**
|
||||
* @param managedServerName The server name
|
||||
* @return the corresponding jetty server wrapped with its deployment properties.
|
||||
* @return the corresponding jetty server wrapped with its deployment
|
||||
* properties.
|
||||
*/
|
||||
public ServerInstanceWrapper getServerInstanceWrapper(String managedServerName)
|
||||
{
|
||||
return _serversIndexedByName.get(managedServerName == null
|
||||
? OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME : managedServerName);
|
||||
return _serversIndexedByName.get(managedServerName == null ? OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME : managedServerName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -99,14 +99,21 @@ public class JettyServersManagedFactory implements ManagedServiceFactory, IManag
|
|||
String name = (String)properties.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
if (name == null)
|
||||
{
|
||||
throw new ConfigurationException(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME,
|
||||
"The name of the server is mandatory");
|
||||
throw new ConfigurationException(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME,
|
||||
"The name of the server is mandatory");
|
||||
}
|
||||
serverInstanceWrapper = new ServerInstanceWrapper(name);
|
||||
_serversIndexedByPID.put(pid, serverInstanceWrapper);
|
||||
_serversNameIndexedByPID.put(pid, name);
|
||||
_serversPIDIndexedByName.put(name, pid);
|
||||
serverInstanceWrapper.start(new Server(), properties);
|
||||
try
|
||||
{
|
||||
serverInstanceWrapper.start(new Server(), properties);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ConfigurationException(null, "Error starting jetty server instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void deleted(String pid)
|
||||
|
|
|
@ -44,28 +44,29 @@ import org.eclipse.jetty.util.resource.Resource;
|
|||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
|
||||
/**
|
||||
* Exposes a Jetty Server to be managed by an OSGi ManagedServiceFactory
|
||||
* Configure and start it.
|
||||
* Can also be used from the ManagedServiceFactory
|
||||
* Configure and start it. Can also be used from the ManagedServiceFactory
|
||||
*/
|
||||
public class ServerInstanceWrapper {
|
||||
public class ServerInstanceWrapper
|
||||
{
|
||||
|
||||
/** The value of this property points to the parent director of
|
||||
* the jetty.xml configuration file currently executed.
|
||||
* Everything is passed as a URL to support the
|
||||
* case where the bundle is zipped. */
|
||||
/**
|
||||
* The value of this property points to the parent director of the jetty.xml
|
||||
* configuration file currently executed. Everything is passed as a URL to
|
||||
* support the case where the bundle is zipped.
|
||||
*/
|
||||
public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url";
|
||||
|
||||
private static Logger __logger = Log.getLogger(ServerInstanceWrapper.class.getName());
|
||||
|
||||
private static Logger LOG = Log.getLogger(ServerInstanceWrapper.class.getName());
|
||||
|
||||
private final String _managedServerName;
|
||||
|
||||
|
||||
/**
|
||||
* The managed jetty server
|
||||
*/
|
||||
private Server _server;
|
||||
|
||||
private ContextHandlerCollection _ctxtHandler;
|
||||
|
||||
/**
|
||||
|
@ -74,32 +75,34 @@ public class ServerInstanceWrapper {
|
|||
* let the TldScanner find the jars where the tld files are.
|
||||
*/
|
||||
private ClassLoader _commonParentClassLoaderForWebapps;
|
||||
|
||||
private DeploymentManager _deploymentManager;
|
||||
|
||||
private OSGiAppProvider _provider;
|
||||
|
||||
|
||||
private WebBundleDeployerHelper _webBundleDeployerHelper;
|
||||
|
||||
|
||||
|
||||
public ServerInstanceWrapper(String managedServerName)
|
||||
{
|
||||
_managedServerName = managedServerName;
|
||||
}
|
||||
|
||||
|
||||
public String getManagedServerName()
|
||||
{
|
||||
return _managedServerName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The classloader that should be the parent classloader for
|
||||
* each webapp deployed on this server.
|
||||
* The classloader that should be the parent classloader for each webapp
|
||||
* deployed on this server.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ClassLoader getParentClassLoaderForWebapps()
|
||||
{
|
||||
return _commonParentClassLoaderForWebapps;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The deployment manager registered on this server.
|
||||
*/
|
||||
|
@ -107,7 +110,7 @@ public class ServerInstanceWrapper {
|
|||
{
|
||||
return _deploymentManager;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The app provider registered on this server.
|
||||
*/
|
||||
|
@ -115,19 +118,17 @@ public class ServerInstanceWrapper {
|
|||
{
|
||||
return _provider;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Server getServer()
|
||||
{
|
||||
return _server;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public WebBundleDeployerHelper getWebBundleDeployerHelp()
|
||||
{
|
||||
return _webBundleDeployerHelper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The collection of context handlers
|
||||
*/
|
||||
|
@ -136,8 +137,7 @@ public class ServerInstanceWrapper {
|
|||
return _ctxtHandler;
|
||||
}
|
||||
|
||||
|
||||
public void start(Server server, Dictionary props)
|
||||
public void start(Server server, Dictionary props) throws Exception
|
||||
{
|
||||
_server = server;
|
||||
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
|
||||
|
@ -146,62 +146,61 @@ public class ServerInstanceWrapper {
|
|||
// passing this bundle's classloader as the context classlaoder
|
||||
// makes sure there is access to all the jetty's bundles
|
||||
ClassLoader libExtClassLoader = null;
|
||||
String sharedURLs = (String)props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS);
|
||||
try
|
||||
{
|
||||
List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null;
|
||||
libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(
|
||||
shared, null, server, JettyBootstrapActivator.class.getClassLoader());
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
String sharedURLs = (String) props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS);
|
||||
|
||||
List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null;
|
||||
libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(shared, null, server, JettyBootstrapActivator.class.getClassLoader());
|
||||
|
||||
Thread.currentThread().setContextClassLoader(libExtClassLoader);
|
||||
|
||||
|
||||
configure(server, props);
|
||||
|
||||
init();
|
||||
|
||||
//now that we have an app provider we can call the registration customizer.
|
||||
try
|
||||
{
|
||||
URL[] jarsWithTlds = getJarsWithTlds();
|
||||
_commonParentClassLoaderForWebapps = jarsWithTlds == null
|
||||
? libExtClassLoader
|
||||
:new TldLocatableURLClassloader(libExtClassLoader,jarsWithTlds);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
// now that we have an app provider we can call the registration
|
||||
// customizer.
|
||||
|
||||
URL[] jarsWithTlds = getJarsWithTlds();
|
||||
_commonParentClassLoaderForWebapps = jarsWithTlds == null ? libExtClassLoader : new TldLocatableURLClassloader(libExtClassLoader, jarsWithTlds);
|
||||
|
||||
|
||||
server.start();
|
||||
_webBundleDeployerHelper = new WebBundleDeployerHelper(this);
|
||||
}
|
||||
catch (Throwable t)
|
||||
catch (Exception e)
|
||||
{
|
||||
t.printStackTrace();
|
||||
if (server != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
catch (Exception x)
|
||||
{
|
||||
LOG.ignore(x);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(contextCl);
|
||||
}
|
||||
_webBundleDeployerHelper = new WebBundleDeployerHelper(this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void stop()
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
if (_server.isRunning())
|
||||
{
|
||||
_server.stop();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,14 +228,13 @@ public class ServerInstanceWrapper {
|
|||
private URL[] getJarsWithTlds() throws Exception
|
||||
{
|
||||
ArrayList<URL> res = new ArrayList<URL>();
|
||||
WebBundleDeployerHelper.staticInit();//that is not looking great.
|
||||
WebBundleDeployerHelper.staticInit();// that is not looking great.
|
||||
for (WebappRegistrationCustomizer regCustomizer : WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS)
|
||||
{
|
||||
URL[] urls = regCustomizer.getJarsWithTlds(_provider, WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER);
|
||||
for (URL url : urls)
|
||||
{
|
||||
if (!res.contains(url))
|
||||
res.add(url);
|
||||
if (!res.contains(url)) res.add(url);
|
||||
}
|
||||
}
|
||||
if (!res.isEmpty())
|
||||
|
@ -244,19 +242,15 @@ public class ServerInstanceWrapper {
|
|||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void configure(Server server, Dictionary props) throws Exception
|
||||
{
|
||||
String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
|
||||
List<URL> jettyConfigurations = jettyConfigurationUrls != null
|
||||
? extractResources(jettyConfigurationUrls) : null;
|
||||
if (jettyConfigurations == null || jettyConfigurations.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Map<String,Object> id_map = new HashMap<String,Object>();
|
||||
id_map.put("Server",server);
|
||||
Map<String,String> properties = new HashMap<String,String>();
|
||||
List<URL> jettyConfigurations = jettyConfigurationUrls != null ? extractResources(jettyConfigurationUrls) : null;
|
||||
if (jettyConfigurations == null || jettyConfigurations.isEmpty()) { return; }
|
||||
Map<String, Object> id_map = new HashMap<String, Object>();
|
||||
id_map.put("Server", server);
|
||||
Map<String, String> properties = new HashMap<String, String>();
|
||||
Enumeration<Object> en = props.keys();
|
||||
while (en.hasMoreElements())
|
||||
{
|
||||
|
@ -275,15 +269,17 @@ public class ServerInstanceWrapper {
|
|||
is = r.getInputStream();
|
||||
XmlConfiguration config = new XmlConfiguration(is);
|
||||
config.getIdMap().putAll(id_map);
|
||||
|
||||
//#334062 compute the URL of the folder that contains the jetty.xml conf file
|
||||
//and set it as a property so we can compute relative paths from it.
|
||||
|
||||
// #334062 compute the URL of the folder that contains the
|
||||
// jetty.xml conf file
|
||||
// and set it as a property so we can compute relative paths
|
||||
// from it.
|
||||
String urlPath = jettyConfiguration.toString();
|
||||
int lastSlash = urlPath.lastIndexOf('/');
|
||||
if (lastSlash > 4)
|
||||
{
|
||||
urlPath = urlPath.substring(0, lastSlash);
|
||||
Map<String,String> properties2 = new HashMap<String,String>(properties);
|
||||
Map<String, String> properties2 = new HashMap<String, String>(properties);
|
||||
properties2.put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
|
||||
config.getProperties().putAll(properties2);
|
||||
}
|
||||
|
@ -292,11 +288,11 @@ public class ServerInstanceWrapper {
|
|||
config.getProperties().putAll(properties);
|
||||
}
|
||||
config.configure();
|
||||
id_map=config.getIdMap();
|
||||
id_map = config.getIdMap();
|
||||
}
|
||||
catch (SAXParseException saxparse)
|
||||
{
|
||||
__logger.warn("Unable to configure the jetty/etc file " + jettyConfiguration,saxparse);
|
||||
LOG.warn("Unable to configure the jetty/etc file " + jettyConfiguration, saxparse);
|
||||
throw saxparse;
|
||||
}
|
||||
finally
|
||||
|
@ -306,8 +302,7 @@ public class ServerInstanceWrapper {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Must be called after the server is configured.
|
||||
*
|
||||
|
@ -319,50 +314,48 @@ public class ServerInstanceWrapper {
|
|||
private void init()
|
||||
{
|
||||
// Get the context handler
|
||||
_ctxtHandler = (ContextHandlerCollection)_server.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
|
||||
_ctxtHandler = (ContextHandlerCollection) _server.getChildHandlerByClass(ContextHandlerCollection.class);
|
||||
|
||||
// get a deployerManager
|
||||
List<DeploymentManager> deployers = _server.getBeans(DeploymentManager.class);
|
||||
if (deployers != null && !deployers.isEmpty())
|
||||
{
|
||||
_deploymentManager = deployers.get(0);
|
||||
|
||||
|
||||
for (AppProvider provider : _deploymentManager.getAppProviders())
|
||||
{
|
||||
if (provider instanceof OSGiAppProvider)
|
||||
{
|
||||
_provider=(OSGiAppProvider)provider;
|
||||
_provider = (OSGiAppProvider) provider;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_provider == null)
|
||||
{
|
||||
//create it on the fly with reasonable default values.
|
||||
// create it on the fly with reasonable default values.
|
||||
try
|
||||
{
|
||||
_provider = new OSGiAppProvider();
|
||||
_provider.setMonitoredDirResource(
|
||||
Resource.newResource(getDefaultOSGiContextsHome(
|
||||
new File(System.getProperty("jetty.home"))).toURI()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
_provider.setMonitoredDirResource(Resource.newResource(getDefaultOSGiContextsHome(new File(System.getProperty("jetty.home"))).toURI()));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
_deploymentManager.addAppProvider(_provider);
|
||||
}
|
||||
}
|
||||
|
||||
if (_ctxtHandler == null || _provider==null)
|
||||
throw new IllegalStateException("ERROR: No ContextHandlerCollection or OSGiAppProvider configured");
|
||||
|
||||
if (_ctxtHandler == null || _provider == null) throw new IllegalStateException("ERROR: No ContextHandlerCollection or OSGiAppProvider configured");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The default folder in which the context files of the osgi bundles
|
||||
* are located and watched. Or null when the system property
|
||||
* "jetty.osgi.contexts.home" is not defined.
|
||||
* If the configuration file defines the OSGiAppProvider's context.
|
||||
* This will not be taken into account.
|
||||
* "jetty.osgi.contexts.home" is not defined. If the configuration
|
||||
* file defines the OSGiAppProvider's context. This will not be
|
||||
* taken into account.
|
||||
*/
|
||||
File getDefaultOSGiContextsHome(File jettyHome)
|
||||
{
|
||||
|
@ -370,20 +363,19 @@ public class ServerInstanceWrapper {
|
|||
if (jettyContextsHome != null)
|
||||
{
|
||||
File contextsHome = new File(jettyContextsHome);
|
||||
if (!contextsHome.exists() || !contextsHome.isDirectory())
|
||||
{
|
||||
throw new IllegalArgumentException("the ${jetty.osgi.contexts.home} '" + jettyContextsHome + " must exist and be a folder");
|
||||
}
|
||||
if (!contextsHome.exists() || !contextsHome.isDirectory()) { throw new IllegalArgumentException(
|
||||
"the ${jetty.osgi.contexts.home} '" + jettyContextsHome
|
||||
+ " must exist and be a folder"); }
|
||||
return contextsHome;
|
||||
}
|
||||
return new File(jettyHome, "/contexts");
|
||||
}
|
||||
|
||||
|
||||
File getOSGiContextsHome()
|
||||
{
|
||||
return _provider.getContextXmlDirAsFile();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the urls in this string.
|
||||
*/
|
||||
|
@ -396,19 +388,19 @@ public class ServerInstanceWrapper {
|
|||
String tok = tokenizer.nextToken();
|
||||
try
|
||||
{
|
||||
urls.add(((DefaultFileLocatorHelper) WebBundleDeployerHelper
|
||||
.BUNDLE_FILE_LOCATOR_HELPER).getLocalURL(new URL(tok)));
|
||||
urls.add(((DefaultFileLocatorHelper) WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER).getLocalURL(new URL(tok)));
|
||||
}
|
||||
catch (Throwable mfe)
|
||||
{
|
||||
|
||||
LOG.warn(mfe);
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the folders that might contain jars for the legacy J2EE shared libraries
|
||||
* Get the folders that might contain jars for the legacy J2EE shared
|
||||
* libraries
|
||||
*/
|
||||
private List<File> extractFiles(String propertyValue)
|
||||
{
|
||||
|
@ -420,8 +412,7 @@ public class ServerInstanceWrapper {
|
|||
try
|
||||
{
|
||||
URL url = new URL(tok);
|
||||
url = ((DefaultFileLocatorHelper) WebBundleDeployerHelper
|
||||
.BUNDLE_FILE_LOCATOR_HELPER).getFileURL(url);
|
||||
url = ((DefaultFileLocatorHelper) WebBundleDeployerHelper.BUNDLE_FILE_LOCATOR_HELPER).getFileURL(url);
|
||||
if (url.getProtocol().equals("file"))
|
||||
{
|
||||
Resource res = Resource.newResource(url);
|
||||
|
@ -434,11 +425,10 @@ public class ServerInstanceWrapper {
|
|||
}
|
||||
catch (Throwable mfe)
|
||||
{
|
||||
|
||||
LOG.warn(mfe);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHom
|
|||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry;
|
||||
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
@ -52,15 +54,17 @@ import org.osgi.framework.ServiceReference;
|
|||
*/
|
||||
public class JettyContextHandlerServiceTracker implements ServiceListener
|
||||
{
|
||||
|
||||
/** New style: ability to manage multiple jetty instances */
|
||||
private final IManagedJettyServerRegistry _registry;
|
||||
private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
|
||||
|
||||
/** New style: ability to manage multiple jetty instances */
|
||||
private final IManagedJettyServerRegistry _registry;
|
||||
|
||||
/** The context-handler to deactivate indexed by context handler */
|
||||
private Map<ServiceReference, ContextHandler> _indexByServiceReference = new HashMap<ServiceReference, ContextHandler>();
|
||||
|
||||
/**
|
||||
* The index is the bundle-symbolic-name/path/to/context/file when there is such thing
|
||||
* The index is the bundle-symbolic-name/path/to/context/file when there is
|
||||
* such thing
|
||||
*/
|
||||
private Map<String, ServiceReference> _indexByContextFile = new HashMap<String, ServiceReference>();
|
||||
|
||||
|
@ -72,7 +76,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
*/
|
||||
public JettyContextHandlerServiceTracker(IManagedJettyServerRegistry registry) throws Exception
|
||||
{
|
||||
_registry = registry;
|
||||
_registry = registry;
|
||||
}
|
||||
|
||||
public void stop() throws Exception
|
||||
|
@ -85,19 +89,16 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
// nothing to stop in the WebappRegistrationHelper
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param contextHome Parent folder where the context files can override the context files
|
||||
* defined in the web bundles: equivalent to the contexts folder in a traditional
|
||||
* jetty installation.
|
||||
* when null, just do nothing.
|
||||
* @param contextHome Parent folder where the context files can override the
|
||||
* context files defined in the web bundles: equivalent to the
|
||||
* contexts folder in a traditional jetty installation. when
|
||||
* null, just do nothing.
|
||||
*/
|
||||
protected void setupContextHomeScanner(File contextHome) throws IOException
|
||||
{
|
||||
if (contextHome == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (contextHome == null) { return; }
|
||||
final String osgiContextHomeFolderCanonicalPath = contextHome.getCanonicalPath();
|
||||
_scanner = new Scanner();
|
||||
_scanner.setRecursive(true);
|
||||
|
@ -132,8 +133,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
/**
|
||||
* Receives notification that a service has had a lifecycle change.
|
||||
*
|
||||
* @param ev
|
||||
* The <code>ServiceEvent</code> object.
|
||||
* @param ev The <code>ServiceEvent</code> object.
|
||||
*/
|
||||
public void serviceChanged(ServiceEvent ev)
|
||||
{
|
||||
|
@ -148,12 +148,11 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
{
|
||||
try
|
||||
{
|
||||
getWebBundleDeployerHelp(sr).unregister(ctxtHandler);
|
||||
getWebBundleDeployerHelp(sr).unregister(ctxtHandler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,30 +169,32 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
{
|
||||
Bundle contributor = sr.getBundle();
|
||||
BundleContext context = FrameworkUtil.getBundle(JettyBootstrapActivator.class).getBundleContext();
|
||||
ContextHandler contextHandler = (ContextHandler)context.getService(sr);
|
||||
ContextHandler contextHandler = (ContextHandler) context.getService(sr);
|
||||
if (contextHandler.getServer() != null)
|
||||
{
|
||||
// is configured elsewhere.
|
||||
return;
|
||||
}
|
||||
String contextFilePath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
if (contextHandler instanceof WebAppContext && contextFilePath == null)
|
||||
//it could be a web-application that will in fact be configured via a context file.
|
||||
//that case is identified by the fact that the contextFilePath is not null
|
||||
//in that case we must use the register context methods.
|
||||
// it could be a web-application that will in fact be configured
|
||||
// via a context file.
|
||||
// that case is identified by the fact that the contextFilePath
|
||||
// is not null
|
||||
// in that case we must use the register context methods.
|
||||
{
|
||||
WebAppContext webapp = (WebAppContext)contextHandler;
|
||||
String contextPath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
|
||||
WebAppContext webapp = (WebAppContext) contextHandler;
|
||||
String contextPath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
|
||||
if (contextPath == null)
|
||||
{
|
||||
contextPath = webapp.getContextPath();
|
||||
}
|
||||
String webXmlPath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_WEB_XML_PATH);
|
||||
String webXmlPath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_WEB_XML_PATH);
|
||||
if (webXmlPath == null)
|
||||
{
|
||||
webXmlPath = webapp.getDescriptor();
|
||||
}
|
||||
String defaultWebXmlPath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_DEFAULT_WEB_XML_PATH);
|
||||
String defaultWebXmlPath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_DEFAULT_WEB_XML_PATH);
|
||||
if (defaultWebXmlPath == null)
|
||||
{
|
||||
String jettyHome = System.getProperty(DefaultJettyAtJettyHomeHelper.SYS_PROP_JETTY_HOME);
|
||||
|
@ -202,7 +203,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
File etc = new File(jettyHome, "etc");
|
||||
if (etc.exists() && etc.isDirectory())
|
||||
{
|
||||
File webDefault = new File (etc, "webdefault.xml");
|
||||
File webDefault = new File(etc, "webdefault.xml");
|
||||
if (webDefault.exists())
|
||||
defaultWebXmlPath = webDefault.getAbsolutePath();
|
||||
else
|
||||
|
@ -212,83 +213,80 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
defaultWebXmlPath = webapp.getDefaultsDescriptor();
|
||||
}
|
||||
}
|
||||
String war = (String)sr.getProperty("war");
|
||||
String war = (String) sr.getProperty("war");
|
||||
try
|
||||
{
|
||||
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
|
||||
if (deployerHelper == null)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
WebAppContext handler = deployerHelper
|
||||
.registerWebapplication(contributor,war,contextPath,
|
||||
(String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
|
||||
(String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
|
||||
(String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
|
||||
webXmlPath,defaultWebXmlPath,webapp);
|
||||
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
|
||||
if (deployerHelper == null)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
WebAppContext handler = deployerHelper.registerWebapplication(contributor,
|
||||
war,
|
||||
contextPath,
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
|
||||
webXmlPath, defaultWebXmlPath, webapp);
|
||||
if (handler != null)
|
||||
{
|
||||
registerInIndex(handler,sr);
|
||||
registerInIndex(handler, sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// consider this just an empty skeleton:
|
||||
if (contextFilePath == null)
|
||||
{
|
||||
throw new IllegalArgumentException("the property contextFilePath is required");
|
||||
}
|
||||
if (contextFilePath == null) { throw new IllegalArgumentException("the property contextFilePath is required"); }
|
||||
try
|
||||
{
|
||||
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
|
||||
if (deployerHelper == null)
|
||||
{
|
||||
//more warnings?
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Boolean.TRUE.toString().equals(sr.getProperty(
|
||||
IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE)))
|
||||
{
|
||||
contextHandler = null;
|
||||
}
|
||||
ContextHandler handler = deployerHelper.registerContext(contributor,contextFilePath,
|
||||
(String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
|
||||
(String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
|
||||
(String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
|
||||
contextHandler);
|
||||
if (handler != null)
|
||||
{
|
||||
registerInIndex(handler,sr);
|
||||
}
|
||||
}
|
||||
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
|
||||
if (deployerHelper == null)
|
||||
{
|
||||
// more warnings?
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Boolean.TRUE.toString().equals(sr.getProperty(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE)))
|
||||
{
|
||||
contextHandler = null;
|
||||
}
|
||||
ContextHandler handler = deployerHelper.registerContext(contributor,
|
||||
contextFilePath,
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
|
||||
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
|
||||
contextHandler);
|
||||
if (handler != null)
|
||||
{
|
||||
registerInIndex(handler, sr);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerInIndex(ContextHandler handler, ServiceReference sr)
|
||||
{
|
||||
_indexByServiceReference.put(sr,handler);
|
||||
_indexByServiceReference.put(sr, handler);
|
||||
String key = getSymbolicNameAndContextFileKey(sr);
|
||||
if (key != null)
|
||||
{
|
||||
_indexByContextFile.put(key,sr);
|
||||
_indexByContextFile.put(key, sr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,11 +318,8 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
*/
|
||||
private String getSymbolicNameAndContextFileKey(ServiceReference sr)
|
||||
{
|
||||
String contextFilePath = (String)sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
if (contextFilePath != null)
|
||||
{
|
||||
return sr.getBundle().getSymbolicName() + "/" + contextFilePath;
|
||||
}
|
||||
String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
|
||||
if (contextFilePath != null) { return sr.getBundle().getSymbolicName() + "/" + contextFilePath; }
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -336,17 +331,14 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
public void reloadJettyContextHandler(String canonicalNameOfFileChanged, String osgiContextHomeFolderCanonicalPath)
|
||||
{
|
||||
String key = getNormalizedRelativePath(canonicalNameOfFileChanged, osgiContextHomeFolderCanonicalPath);
|
||||
if (key == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (key == null) { return; }
|
||||
ServiceReference sr = _indexByContextFile.get(key);
|
||||
if (sr == null)
|
||||
{
|
||||
// nothing to do?
|
||||
return;
|
||||
}
|
||||
serviceChanged(new ServiceEvent(ServiceEvent.MODIFIED,sr));
|
||||
serviceChanged(new ServiceEvent(ServiceEvent.MODIFIED, sr));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -362,36 +354,31 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
|
|||
// warning?
|
||||
return null;
|
||||
}
|
||||
return canFilename.substring(osgiContextHomeFolderCanonicalPath.length()).replace('\\','/');
|
||||
return canFilename.substring(osgiContextHomeFolderCanonicalPath.length()).replace('\\', '/');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The server on which this webapp is meant to be deployed
|
||||
*/
|
||||
private ServerInstanceWrapper getServerInstanceWrapper(String managedServerName)
|
||||
{
|
||||
if (_registry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (managedServerName == null)
|
||||
{
|
||||
managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
|
||||
}
|
||||
ServerInstanceWrapper wrapper = _registry.getServerInstanceWrapper(managedServerName);
|
||||
//System.err.println("Returning " + managedServerName + " = " + wrapper);
|
||||
return wrapper;
|
||||
if (_registry == null) { return null; }
|
||||
if (managedServerName == null)
|
||||
{
|
||||
managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
|
||||
}
|
||||
ServerInstanceWrapper wrapper = _registry.getServerInstanceWrapper(managedServerName);
|
||||
// System.err.println("Returning " + managedServerName + " = " +
|
||||
// wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
|
||||
private IWebBundleDeployerHelper getWebBundleDeployerHelp(ServiceReference sr)
|
||||
{
|
||||
if (_registry == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String managedServerName = (String)sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
ServerInstanceWrapper wrapper = getServerInstanceWrapper(managedServerName);
|
||||
return wrapper != null ? wrapper.getWebBundleDeployerHelp() : null;
|
||||
if (_registry == null) { return null; }
|
||||
String managedServerName = (String) sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
|
||||
ServerInstanceWrapper wrapper = getServerInstanceWrapper(managedServerName);
|
||||
return wrapper != null ? wrapper.getWebBundleDeployerHelp() : null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
|
|||
catch (IOException e)
|
||||
{
|
||||
// nevermind. just trying our best
|
||||
e.printStackTrace();
|
||||
__logger.ignore(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
|
|||
catch (Throwable t)
|
||||
{
|
||||
// humf that will hurt if it does not work.
|
||||
t.printStackTrace();
|
||||
__logger.warn("Unable to set webappcontext", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,13 +78,14 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
|
||||
|
||||
private static boolean INITIALIZED = false;
|
||||
|
||||
|
||||
/**
|
||||
* By default set to: {@link DefaultBundleClassLoaderHelper}. It supports
|
||||
* equinox and apache-felix fragment bundles that are specific to an OSGi
|
||||
* implementation should set a different implementation.
|
||||
*/
|
||||
public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null;
|
||||
|
||||
/**
|
||||
* By default set to: {@link DefaultBundleClassLoaderHelper}. It supports
|
||||
* equinox and apache-felix fragment bundles that are specific to an OSGi
|
||||
|
@ -97,8 +98,9 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
* equinox and apache-felix fragment bundles that are specific to an OSGi
|
||||
* implementation should set a different implementation.
|
||||
* <p>
|
||||
* Several of those objects can be added here: For example we could have an optional fragment that setups
|
||||
* a specific implementation of JSF for the whole of jetty-osgi.
|
||||
* Several of those objects can be added here: For example we could have an
|
||||
* optional fragment that setups a specific implementation of JSF for the
|
||||
* whole of jetty-osgi.
|
||||
* </p>
|
||||
*/
|
||||
public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>();
|
||||
|
@ -127,7 +129,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
// setup the custom BundleClassLoaderHelper
|
||||
try
|
||||
{
|
||||
BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper)Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
|
||||
BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper) Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -137,7 +139,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
// setup the custom FileLocatorHelper
|
||||
try
|
||||
{
|
||||
BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper)Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
|
||||
BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper) Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -150,34 +152,28 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
/**
|
||||
* Deploy a new web application on the jetty server.
|
||||
*
|
||||
* @param bundle
|
||||
* The bundle
|
||||
* @param webappFolderPath
|
||||
* The path to the root of the webapp. Must be a path relative to
|
||||
* bundle; either an absolute path.
|
||||
* @param contextPath
|
||||
* The context path. Must start with "/"
|
||||
* @param bundle The bundle
|
||||
* @param webappFolderPath The path to the root of the webapp. Must be a
|
||||
* path relative to bundle; either an absolute path.
|
||||
* @param contextPath The context path. Must start with "/"
|
||||
* @param extraClasspath
|
||||
* @param overrideBundleInstallLocation
|
||||
* @param requireTldBundle The list of bundles's symbolic names that contain
|
||||
* tld files that are required by this WAB.
|
||||
* tld files that are required by this WAB.
|
||||
* @param webXmlPath
|
||||
* @param defaultWebXmlPath
|
||||
* TODO: parameter description
|
||||
* @param defaultWebXmlPath TODO: parameter description
|
||||
* @return The contexthandler created and started
|
||||
* @throws Exception
|
||||
*/
|
||||
public WebAppContext registerWebapplication(Bundle bundle,
|
||||
String webappFolderPath, String contextPath, String extraClasspath,
|
||||
String overrideBundleInstallLocation,
|
||||
String requireTldBundle, String webXmlPath,
|
||||
String defaultWebXmlPath, WebAppContext webAppContext) throws Exception
|
||||
public WebAppContext registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle, String webXmlPath, String defaultWebXmlPath,
|
||||
WebAppContext webAppContext) throws Exception
|
||||
{
|
||||
File bundleInstall = overrideBundleInstallLocation == null?BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle):new File(
|
||||
overrideBundleInstallLocation);
|
||||
File bundleInstall = overrideBundleInstallLocation == null ? BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle) : new File(
|
||||
overrideBundleInstallLocation);
|
||||
File webapp = null;
|
||||
URL baseWebappInstallURL = null;
|
||||
|
||||
|
||||
if (webappFolderPath != null && webappFolderPath.length() != 0 && !webappFolderPath.equals("."))
|
||||
{
|
||||
if (webappFolderPath.startsWith("/") || webappFolderPath.startsWith("file:"))
|
||||
|
@ -186,7 +182,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
}
|
||||
else if (bundleInstall != null && bundleInstall.isDirectory())
|
||||
{
|
||||
webapp = new File(bundleInstall,webappFolderPath);
|
||||
webapp = new File(bundleInstall, webappFolderPath);
|
||||
}
|
||||
else if (bundleInstall != null)
|
||||
{
|
||||
|
@ -201,37 +197,48 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
{
|
||||
webapp = bundleInstall;
|
||||
}
|
||||
if (baseWebappInstallURL == null && (webapp == null || !webapp.exists()))
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + webappFolderPath + " inside "
|
||||
+ (bundleInstall != null?bundleInstall.getAbsolutePath():"unlocated bundle '" + bundle.getSymbolicName() + "'"));
|
||||
}
|
||||
if (baseWebappInstallURL == null && (webapp == null || !webapp.exists())) { throw new IllegalArgumentException(
|
||||
"Unable to locate " + webappFolderPath
|
||||
+ " inside "
|
||||
+ (bundleInstall != null ? bundleInstall.getAbsolutePath() : "unlocated bundle '" + bundle.getSymbolicName()
|
||||
+ "'")); }
|
||||
if (baseWebappInstallURL == null && webapp != null)
|
||||
{
|
||||
baseWebappInstallURL = webapp.toURI().toURL();
|
||||
}
|
||||
return registerWebapplication(bundle,webappFolderPath,baseWebappInstallURL,contextPath,
|
||||
extraClasspath,bundleInstall,requireTldBundle,webXmlPath,defaultWebXmlPath,webAppContext);
|
||||
return registerWebapplication(bundle, webappFolderPath, baseWebappInstallURL, contextPath, extraClasspath, bundleInstall, requireTldBundle, webXmlPath,
|
||||
defaultWebXmlPath, webAppContext);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerWebapplication(org.osgi.framework.Bundle, java.lang.String, java.io.File, java.lang.String, java.lang.String, java.io.File, java.lang.String, java.lang.String)
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
|
||||
* registerWebapplication(org.osgi.framework.Bundle, java.lang.String,
|
||||
* java.io.File, java.lang.String, java.lang.String, java.io.File,
|
||||
* java.lang.String, java.lang.String)
|
||||
*/
|
||||
private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp,
|
||||
URL baseWebappInstallURL, String contextPath, String extraClasspath, File bundleInstall,
|
||||
String requireTldBundle, String webXmlPath, String defaultWebXmlPath, WebAppContext context)
|
||||
throws Exception
|
||||
private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp, URL baseWebappInstallURL, String contextPath,
|
||||
String extraClasspath, File bundleInstall, String requireTldBundle, String webXmlPath,
|
||||
String defaultWebXmlPath, WebAppContext context) throws Exception
|
||||
{
|
||||
|
||||
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
|
||||
String[] oldServerClasses = null;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
//apply any META-INF/context.xml file that is found to configure the webapp first
|
||||
applyMetaInfContextXml (contributor, context);
|
||||
|
||||
// make sure we provide access to all the jetty bundles by going
|
||||
// through this bundle.
|
||||
OSGiWebappClassLoader composite = createWebappClassLoader(contributor);
|
||||
// configure with access to all jetty classes and also all the classes
|
||||
// configure with access to all jetty classes and also all the
|
||||
// classes
|
||||
// that the contributor gives access to.
|
||||
Thread.currentThread().setContextClassLoader(composite);
|
||||
|
||||
|
@ -248,7 +255,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
}
|
||||
else
|
||||
{
|
||||
webXml = new File(bundleInstall,webXmlPath);
|
||||
webXml = new File(bundleInstall, webXmlPath);
|
||||
}
|
||||
if (webXml.exists())
|
||||
{
|
||||
|
@ -258,7 +265,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
|
||||
if (defaultWebXmlPath == null || defaultWebXmlPath.length() == 0)
|
||||
{
|
||||
//use the one defined by the OSGiAppProvider.
|
||||
// use the one defined by the OSGiAppProvider.
|
||||
defaultWebXmlPath = _wrapper.getOSGiAppProvider().getDefaultsDescriptor();
|
||||
}
|
||||
if (defaultWebXmlPath != null && defaultWebXmlPath.length() != 0)
|
||||
|
@ -270,20 +277,19 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
}
|
||||
else
|
||||
{
|
||||
defaultWebXml = new File(bundleInstall,defaultWebXmlPath);
|
||||
defaultWebXml = new File(bundleInstall, defaultWebXmlPath);
|
||||
}
|
||||
if (defaultWebXml.exists())
|
||||
{
|
||||
context.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
//other parameters that might be defines on the OSGiAppProvider:
|
||||
|
||||
// other parameters that might be defines on the OSGiAppProvider:
|
||||
context.setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
|
||||
|
||||
configureWebappClassLoader(contributor,context,composite, requireTldBundle);
|
||||
configureWebAppContext(context,contributor,requireTldBundle);
|
||||
|
||||
configureWebappClassLoader(contributor, context, composite, requireTldBundle);
|
||||
configureWebAppContext(context, contributor, requireTldBundle);
|
||||
|
||||
// @see
|
||||
// org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
|
||||
|
@ -292,36 +298,36 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
// through the webapp classloader.
|
||||
oldServerClasses = context.getServerClasses();
|
||||
context.setServerClasses(null);
|
||||
|
||||
_wrapper.getOSGiAppProvider().addContext(contributor,pathInBundleToWebApp,context);
|
||||
|
||||
//support for patch resources. ideally this should be done inside a configurator.
|
||||
List<Resource> patchResources =
|
||||
(List<Resource>)context.getAttribute(WebInfConfiguration.RESOURCE_URLS+".patch");
|
||||
|
||||
_wrapper.getOSGiAppProvider().addContext(contributor, pathInBundleToWebApp, context);
|
||||
|
||||
// support for patch resources. ideally this should be done inside a
|
||||
// configurator.
|
||||
List<Resource> patchResources = (List<Resource>) context.getAttribute(WebInfConfiguration.RESOURCE_URLS + ".patch");
|
||||
if (patchResources != null)
|
||||
{
|
||||
LinkedList<Resource> resourcesPath = new LinkedList<Resource>();
|
||||
//place the patch resources at the beginning of the lookup path.
|
||||
resourcesPath.addAll(patchResources);
|
||||
//then place the ones from the host web bundle.
|
||||
Resource hostResources = context.getBaseResource();
|
||||
if (hostResources instanceof ResourceCollection)
|
||||
{
|
||||
for (Resource re : ((ResourceCollection)hostResources).getResources())
|
||||
{
|
||||
resourcesPath.add(re);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resourcesPath.add(hostResources);
|
||||
}
|
||||
|
||||
ResourceCollection rc = new ResourceCollection(resourcesPath.toArray(
|
||||
new Resource[resourcesPath.size()]));
|
||||
context.setBaseResource(rc);
|
||||
LinkedList<Resource> resourcesPath = new LinkedList<Resource>();
|
||||
// place the patch resources at the beginning of the lookup
|
||||
// path.
|
||||
resourcesPath.addAll(patchResources);
|
||||
// then place the ones from the host web bundle.
|
||||
Resource hostResources = context.getBaseResource();
|
||||
if (hostResources instanceof ResourceCollection)
|
||||
{
|
||||
for (Resource re : ((ResourceCollection) hostResources).getResources())
|
||||
{
|
||||
resourcesPath.add(re);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resourcesPath.add(hostResources);
|
||||
}
|
||||
|
||||
ResourceCollection rc = new ResourceCollection(resourcesPath.toArray(new Resource[resourcesPath.size()]));
|
||||
context.setBaseResource(rc);
|
||||
}
|
||||
|
||||
|
||||
return context;
|
||||
}
|
||||
finally
|
||||
|
@ -335,38 +341,41 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#unregister(org.eclipse.jetty.server.handler.ContextHandler)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
|
||||
* unregister(org.eclipse.jetty.server.handler.ContextHandler)
|
||||
*/
|
||||
public void unregister(ContextHandler contextHandler) throws Exception
|
||||
{
|
||||
_wrapper.getOSGiAppProvider().removeContext(contextHandler);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerContext(org.osgi.framework.Bundle, java.lang.String, java.lang.String, java.lang.String)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
|
||||
* registerContext(org.osgi.framework.Bundle, java.lang.String,
|
||||
* java.lang.String, java.lang.String)
|
||||
*/
|
||||
public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler)
|
||||
throws Exception
|
||||
public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath, String overrideBundleInstallLocation,
|
||||
String requireTldBundle, ContextHandler handler) throws Exception
|
||||
{
|
||||
File contextsHome = _wrapper.getOSGiAppProvider().getContextXmlDirAsFile();
|
||||
if (contextsHome != null)
|
||||
{
|
||||
File prodContextFile = new File(contextsHome,contributor.getSymbolicName() + "/" + contextFileRelativePath);
|
||||
if (prodContextFile.exists())
|
||||
{
|
||||
return registerContext(contributor,contextFileRelativePath,prodContextFile,extraClasspath,
|
||||
overrideBundleInstallLocation,requireTldBundle,handler);
|
||||
}
|
||||
File prodContextFile = new File(contextsHome, contributor.getSymbolicName() + "/" + contextFileRelativePath);
|
||||
if (prodContextFile.exists()) { return registerContext(contributor, contextFileRelativePath, prodContextFile, extraClasspath,
|
||||
overrideBundleInstallLocation, requireTldBundle, handler); }
|
||||
}
|
||||
File rootFolder = overrideBundleInstallLocation != null
|
||||
? Resource.newResource(overrideBundleInstallLocation).getFile()
|
||||
: BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor);
|
||||
File contextFile = rootFolder != null?new File(rootFolder,contextFileRelativePath):null;
|
||||
File rootFolder = overrideBundleInstallLocation != null ? Resource.newResource(overrideBundleInstallLocation).getFile() : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor);
|
||||
File contextFile = rootFolder != null ? new File(rootFolder, contextFileRelativePath) : null;
|
||||
if (contextFile != null && contextFile.exists())
|
||||
{
|
||||
return registerContext(contributor,contextFileRelativePath,contextFile,extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
|
||||
return registerContext(contributor, contextFileRelativePath, contextFile, extraClasspath, overrideBundleInstallLocation, requireTldBundle, handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -378,15 +387,19 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
{
|
||||
contextFileRelativePath = "/" + contextFileRelativePath;
|
||||
}
|
||||
|
||||
|
||||
URL contextURL = contributor.getEntry(contextFileRelativePath);
|
||||
if (contextURL != null)
|
||||
{
|
||||
Resource r = Resource.newResource(contextURL);
|
||||
return registerContext(contributor,contextFileRelativePath,r.getInputStream(),extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
|
||||
Resource r = Resource.newResource(contextURL);
|
||||
return registerContext(contributor, contextFileRelativePath, r.getInputStream(), extraClasspath, overrideBundleInstallLocation,
|
||||
requireTldBundle, handler);
|
||||
}
|
||||
throw new IllegalArgumentException("Could not find the context " + "file " + contextFileRelativePath + " for the bundle "
|
||||
+ contributor.getSymbolicName() + (overrideBundleInstallLocation != null?" using the install location " + overrideBundleInstallLocation:""));
|
||||
throw new IllegalArgumentException("Could not find the context " + "file "
|
||||
+ contextFileRelativePath
|
||||
+ " for the bundle "
|
||||
+ contributor.getSymbolicName()
|
||||
+ (overrideBundleInstallLocation != null ? " using the install location " + overrideBundleInstallLocation : ""));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,16 +413,14 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
* @param classInBundle
|
||||
* @throws Exception
|
||||
*/
|
||||
private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile,
|
||||
String extraClasspath, String overrideBundleInstallLocation,
|
||||
String requireTldBundle, ContextHandler handler) throws Exception
|
||||
private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler) throws Exception
|
||||
{
|
||||
InputStream contextFileInputStream = null;
|
||||
try
|
||||
{
|
||||
contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile));
|
||||
return registerContext(contributor, pathInBundle, contextFileInputStream,
|
||||
extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
|
||||
return registerContext(contributor, pathInBundle, contextFileInputStream, extraClasspath, overrideBundleInstallLocation, requireTldBundle, handler);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -424,11 +435,8 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
* happen.
|
||||
* @throws Exception
|
||||
*/
|
||||
private ContextHandler registerContext(Bundle contributor,
|
||||
String pathInsideBundle, InputStream contextFileInputStream,
|
||||
String extraClasspath, String overrideBundleInstallLocation,
|
||||
String requireTldBundle, ContextHandler handler)
|
||||
throws Exception
|
||||
private ContextHandler registerContext(Bundle contributor, String pathInsideBundle, InputStream contextFileInputStream, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler) throws Exception
|
||||
{
|
||||
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
|
||||
String[] oldServerClasses = null;
|
||||
|
@ -442,24 +450,23 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
// classes
|
||||
// that the contributor gives access to.
|
||||
Thread.currentThread().setContextClassLoader(composite);
|
||||
ContextHandler context = createContextHandler(handler, contributor,
|
||||
contextFileInputStream,extraClasspath,
|
||||
overrideBundleInstallLocation,requireTldBundle);
|
||||
if (context == null)
|
||||
{
|
||||
ContextHandler context = createContextHandler(handler, contributor, contextFileInputStream, extraClasspath, overrideBundleInstallLocation,
|
||||
requireTldBundle);
|
||||
if (context == null)
|
||||
{
|
||||
return null;// did not happen
|
||||
}
|
||||
|
||||
// ok now register this webapp. we checked when we started jetty
|
||||
// that there
|
||||
// was at least one such handler for webapps.
|
||||
//the actual registration must happen via the new Deployment API.
|
||||
// _ctxtHandler.addHandler(context);
|
||||
// the actual registration must happen via the new Deployment API.
|
||||
// _ctxtHandler.addHandler(context);
|
||||
|
||||
configureWebappClassLoader(contributor,context,composite, requireTldBundle);
|
||||
configureWebappClassLoader(contributor, context, composite, requireTldBundle);
|
||||
if (context instanceof WebAppContext)
|
||||
{
|
||||
webAppContext = (WebAppContext)context;
|
||||
webAppContext = (WebAppContext) context;
|
||||
// @see
|
||||
// org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
|
||||
oldServerClasses = webAppContext.getServerClasses();
|
||||
|
@ -485,53 +492,58 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
* @see {WebAppDeployer#scan} around the comment
|
||||
* <code>// configure it</code>
|
||||
*/
|
||||
protected void configureWebAppContext(ContextHandler wah, Bundle contributor,
|
||||
String requireTldBundle) throws IOException
|
||||
protected void configureWebAppContext(ContextHandler wah, Bundle contributor, String requireTldBundle) throws IOException
|
||||
{
|
||||
// rfc66
|
||||
wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT,contributor.getBundleContext());
|
||||
wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, contributor.getBundleContext());
|
||||
|
||||
//spring-dm-1.2.1 looks for the BundleContext as a different attribute.
|
||||
//not a spec... but if we want to support
|
||||
//org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
|
||||
//then we need to do this to:
|
||||
wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(),
|
||||
contributor.getBundleContext());
|
||||
|
||||
//also pass the bundle directly. sometimes a bundle does not have a bundlecontext.
|
||||
//it is still useful to have access to the Bundle from the servlet context.
|
||||
// spring-dm-1.2.1 looks for the BundleContext as a different attribute.
|
||||
// not a spec... but if we want to support
|
||||
// org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
|
||||
// then we need to do this to:
|
||||
wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), contributor.getBundleContext());
|
||||
|
||||
// also pass the bundle directly. sometimes a bundle does not have a
|
||||
// bundlecontext.
|
||||
// it is still useful to have access to the Bundle from the servlet
|
||||
// context.
|
||||
wah.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, contributor);
|
||||
|
||||
//pass the value of the require tld bundle so that the TagLibOSGiConfiguration
|
||||
//can pick it up.
|
||||
|
||||
// pass the value of the require tld bundle so that the
|
||||
// TagLibOSGiConfiguration
|
||||
// can pick it up.
|
||||
wah.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundle);
|
||||
|
||||
|
||||
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(contributor);
|
||||
if (fragments != null && fragments.length != 0)
|
||||
{
|
||||
//sorted extra resource base found in the fragments.
|
||||
//the resources are either overriding the resourcebase found in the web-bundle
|
||||
//or appended.
|
||||
//amongst each resource we sort them according to the alphabetical order
|
||||
//of the name of the internal folder and the symbolic name of the fragment.
|
||||
//this is useful to make sure that the lookup path of those
|
||||
//resource base defined by fragments is always the same.
|
||||
//This natural order could be abused to define the order in which the base resources are
|
||||
//looked up.
|
||||
TreeMap<String,Resource> patchResourcesPath = new TreeMap<String,Resource>();
|
||||
TreeMap<String,Resource> appendedResourcesPath = new TreeMap<String,Resource>();
|
||||
for (Bundle frag : fragments) {
|
||||
String fragFolder = (String)frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH);
|
||||
String patchFragFolder = (String)frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH);
|
||||
// sorted extra resource base found in the fragments.
|
||||
// the resources are either overriding the resourcebase found in the
|
||||
// web-bundle
|
||||
// or appended.
|
||||
// amongst each resource we sort them according to the alphabetical
|
||||
// order
|
||||
// of the name of the internal folder and the symbolic name of the
|
||||
// fragment.
|
||||
// this is useful to make sure that the lookup path of those
|
||||
// resource base defined by fragments is always the same.
|
||||
// This natural order could be abused to define the order in which
|
||||
// the base resources are
|
||||
// looked up.
|
||||
TreeMap<String, Resource> patchResourcesPath = new TreeMap<String, Resource>();
|
||||
TreeMap<String, Resource> appendedResourcesPath = new TreeMap<String, Resource>();
|
||||
for (Bundle frag : fragments)
|
||||
{
|
||||
String fragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH);
|
||||
String patchFragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH);
|
||||
if (fragFolder != null)
|
||||
{
|
||||
URL fragUrl = frag.getEntry(fragFolder);
|
||||
if (fragUrl == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + fragFolder + " inside "
|
||||
+ " the fragment '" + frag.getSymbolicName() + "'");
|
||||
}
|
||||
if (fragUrl == null) { throw new IllegalArgumentException("Unable to locate " + fragFolder
|
||||
+ " inside "
|
||||
+ " the fragment '"
|
||||
+ frag.getSymbolicName()
|
||||
+ "'"); }
|
||||
fragUrl = DefaultFileLocatorHelper.getLocalURL(fragUrl);
|
||||
String key = fragFolder.startsWith("/") ? fragFolder.substring(1) : fragFolder;
|
||||
appendedResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(fragUrl));
|
||||
|
@ -539,11 +551,11 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
if (patchFragFolder != null)
|
||||
{
|
||||
URL patchFragUrl = frag.getEntry(patchFragFolder);
|
||||
if (patchFragUrl == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + patchFragUrl + " inside "
|
||||
+ " the fragment '" + frag.getSymbolicName() + "'");
|
||||
}
|
||||
if (patchFragUrl == null) { throw new IllegalArgumentException("Unable to locate " + patchFragUrl
|
||||
+ " inside "
|
||||
+ " the fragment '"
|
||||
+ frag.getSymbolicName()
|
||||
+ "'"); }
|
||||
patchFragUrl = DefaultFileLocatorHelper.getLocalURL(patchFragUrl);
|
||||
String key = patchFragFolder.startsWith("/") ? patchFragFolder.substring(1) : patchFragFolder;
|
||||
patchResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(patchFragUrl));
|
||||
|
@ -551,92 +563,92 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
}
|
||||
if (!appendedResourcesPath.isEmpty())
|
||||
{
|
||||
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, new ArrayList<Resource>(appendedResourcesPath.values()));
|
||||
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, new ArrayList<Resource>(appendedResourcesPath.values()));
|
||||
}
|
||||
if (!patchResourcesPath.isEmpty())
|
||||
{
|
||||
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS + ".patch", new ArrayList<Resource>(patchResourcesPath.values()));
|
||||
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS + ".patch", new ArrayList<Resource>(patchResourcesPath.values()));
|
||||
}
|
||||
|
||||
|
||||
if (wah instanceof WebAppContext)
|
||||
{
|
||||
//This is the equivalent of what MetaInfConfiguration does. For OSGi bundles without the JarScanner
|
||||
WebAppContext webappCtxt = (WebAppContext)wah;
|
||||
//take care of the web-fragments, meta-inf resources and tld resources:
|
||||
//similar to what MetaInfConfiguration does.
|
||||
List<Resource> frags = (List<Resource>)wah.getAttribute(FragmentConfiguration.FRAGMENT_RESOURCES);
|
||||
List<Resource> resfrags = (List<Resource>)wah.getAttribute(WebInfConfiguration.RESOURCE_URLS);
|
||||
List<Resource> tldfrags = (List<Resource>)wah.getAttribute(TagLibConfiguration.TLD_RESOURCES);
|
||||
for (Bundle frag : fragments)
|
||||
{
|
||||
URL webFrag = frag.getEntry("/META-INF/web-fragment.xml");
|
||||
Enumeration<URL> resEnum = frag.findEntries("/META-INF/resources", "*", true);
|
||||
Enumeration<URL> tldEnum = frag.findEntries("/META-INF", "*.tld", false);
|
||||
if (webFrag != null || (resEnum != null && resEnum.hasMoreElements())
|
||||
|| (tldEnum != null && tldEnum.hasMoreElements()))
|
||||
{
|
||||
try
|
||||
{
|
||||
File fragFile = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(frag);
|
||||
//add it to the webinf jars collection:
|
||||
//no need to check that it was not there yet: it was not there yet for sure.
|
||||
Resource fragFileAsResource = Resource.newResource(fragFile.toURI());
|
||||
webappCtxt.getMetaData().addWebInfJar(fragFileAsResource);
|
||||
|
||||
if (webFrag != null)
|
||||
{
|
||||
if (frags == null)
|
||||
{
|
||||
frags = new ArrayList<Resource>();
|
||||
wah.setAttribute(FragmentConfiguration.FRAGMENT_RESOURCES, frags);
|
||||
}
|
||||
frags.add(fragFileAsResource);
|
||||
}
|
||||
if (resEnum != null && resEnum.hasMoreElements())
|
||||
{
|
||||
URL resourcesEntry = frag.getEntry("/META-INF/resources/");
|
||||
if (resourcesEntry == null)
|
||||
{
|
||||
//probably we found some fragments to a bundle.
|
||||
//those are already contributed.
|
||||
//so we skip this.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resfrags == null)
|
||||
{
|
||||
resfrags = new ArrayList<Resource>();
|
||||
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, resfrags);
|
||||
}
|
||||
resfrags.add(Resource.newResource(
|
||||
DefaultFileLocatorHelper.getLocalURL(resourcesEntry)));
|
||||
}
|
||||
}
|
||||
if (tldEnum != null && tldEnum.hasMoreElements())
|
||||
{
|
||||
if (tldfrags == null)
|
||||
{
|
||||
tldfrags = new ArrayList<Resource>();
|
||||
wah.setAttribute(TagLibConfiguration.TLD_RESOURCES, tldfrags);
|
||||
}
|
||||
while (tldEnum.hasMoreElements())
|
||||
{
|
||||
URL tldUrl = tldEnum.nextElement();
|
||||
tldfrags.add(Resource.newResource(
|
||||
DefaultFileLocatorHelper.getLocalURL(tldUrl)));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__logger.warn("Unable to locate the bundle " + frag.getBundleId(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// This is the equivalent of what MetaInfConfiguration does. For
|
||||
// OSGi bundles without the JarScanner
|
||||
WebAppContext webappCtxt = (WebAppContext) wah;
|
||||
// take care of the web-fragments, meta-inf resources and tld
|
||||
// resources:
|
||||
// similar to what MetaInfConfiguration does.
|
||||
List<Resource> frags = (List<Resource>) wah.getAttribute(FragmentConfiguration.FRAGMENT_RESOURCES);
|
||||
List<Resource> resfrags = (List<Resource>) wah.getAttribute(WebInfConfiguration.RESOURCE_URLS);
|
||||
List<Resource> tldfrags = (List<Resource>) wah.getAttribute(TagLibConfiguration.TLD_RESOURCES);
|
||||
for (Bundle frag : fragments)
|
||||
{
|
||||
URL webFrag = frag.getEntry("/META-INF/web-fragment.xml");
|
||||
Enumeration<URL> resEnum = frag.findEntries("/META-INF/resources", "*", true);
|
||||
Enumeration<URL> tldEnum = frag.findEntries("/META-INF", "*.tld", false);
|
||||
if (webFrag != null || (resEnum != null && resEnum.hasMoreElements()) || (tldEnum != null && tldEnum.hasMoreElements()))
|
||||
{
|
||||
try
|
||||
{
|
||||
File fragFile = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(frag);
|
||||
// add it to the webinf jars collection:
|
||||
// no need to check that it was not there yet: it
|
||||
// was not there yet for sure.
|
||||
Resource fragFileAsResource = Resource.newResource(fragFile.toURI());
|
||||
webappCtxt.getMetaData().addWebInfJar(fragFileAsResource);
|
||||
|
||||
if (webFrag != null)
|
||||
{
|
||||
if (frags == null)
|
||||
{
|
||||
frags = new ArrayList<Resource>();
|
||||
wah.setAttribute(FragmentConfiguration.FRAGMENT_RESOURCES, frags);
|
||||
}
|
||||
frags.add(fragFileAsResource);
|
||||
}
|
||||
if (resEnum != null && resEnum.hasMoreElements())
|
||||
{
|
||||
URL resourcesEntry = frag.getEntry("/META-INF/resources/");
|
||||
if (resourcesEntry == null)
|
||||
{
|
||||
// probably we found some fragments to a
|
||||
// bundle.
|
||||
// those are already contributed.
|
||||
// so we skip this.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resfrags == null)
|
||||
{
|
||||
resfrags = new ArrayList<Resource>();
|
||||
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, resfrags);
|
||||
}
|
||||
resfrags.add(Resource.newResource(DefaultFileLocatorHelper.getLocalURL(resourcesEntry)));
|
||||
}
|
||||
}
|
||||
if (tldEnum != null && tldEnum.hasMoreElements())
|
||||
{
|
||||
if (tldfrags == null)
|
||||
{
|
||||
tldfrags = new ArrayList<Resource>();
|
||||
wah.setAttribute(TagLibConfiguration.TLD_RESOURCES, tldfrags);
|
||||
}
|
||||
while (tldEnum.hasMoreElements())
|
||||
{
|
||||
URL tldUrl = tldEnum.nextElement();
|
||||
tldfrags.add(Resource.newResource(DefaultFileLocatorHelper.getLocalURL(tldUrl)));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__logger.warn("Unable to locate the bundle " + frag.getBundleId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,19 +656,17 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
* @param contextFile
|
||||
* @return
|
||||
*/
|
||||
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure,
|
||||
Bundle bundle, File contextFile, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle)
|
||||
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, Bundle bundle, File contextFile, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle)
|
||||
{
|
||||
try
|
||||
{
|
||||
return createContextHandler(handlerToConfigure,bundle,
|
||||
new BufferedInputStream(new FileInputStream(contextFile)),
|
||||
extraClasspath,overrideBundleInstallLocation,requireTldBundle);
|
||||
return createContextHandler(handlerToConfigure, bundle, new BufferedInputStream(new FileInputStream(contextFile)), extraClasspath,
|
||||
overrideBundleInstallLocation, requireTldBundle);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -667,9 +677,8 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure,
|
||||
Bundle bundle, InputStream contextInputStream, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle)
|
||||
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, Bundle bundle, InputStream contextInputStream, String extraClasspath,
|
||||
String overrideBundleInstallLocation, String requireTldBundle)
|
||||
{
|
||||
/*
|
||||
* Do something identical to what the ContextProvider would have done:
|
||||
|
@ -686,30 +695,30 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
{
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextInputStream);
|
||||
HashMap properties = new HashMap();
|
||||
properties.put("Server",_wrapper.getServer());
|
||||
|
||||
properties.put("Server", _wrapper.getServer());
|
||||
|
||||
// insert the bundle's location as a property.
|
||||
setThisBundleHomeProperty(bundle,properties,overrideBundleInstallLocation);
|
||||
setThisBundleHomeProperty(bundle, properties, overrideBundleInstallLocation);
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
|
||||
ContextHandler context = null;
|
||||
if (handlerToConfigure == null)
|
||||
{
|
||||
context = (ContextHandler)xmlConfiguration.configure();
|
||||
context = (ContextHandler) xmlConfiguration.configure();
|
||||
}
|
||||
else
|
||||
{
|
||||
xmlConfiguration.configure(handlerToConfigure);
|
||||
context = handlerToConfigure;
|
||||
}
|
||||
|
||||
|
||||
if (context instanceof WebAppContext)
|
||||
{
|
||||
((WebAppContext)context).setExtraClasspath(extraClasspath);
|
||||
((WebAppContext)context).setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
|
||||
((WebAppContext) context).setExtraClasspath(extraClasspath);
|
||||
((WebAppContext) context).setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
|
||||
if (_wrapper.getOSGiAppProvider().getDefaultsDescriptor() != null && _wrapper.getOSGiAppProvider().getDefaultsDescriptor().length() != 0)
|
||||
{
|
||||
((WebAppContext)context).setDefaultsDescriptor(_wrapper.getOSGiAppProvider().getDefaultsDescriptor());
|
||||
((WebAppContext) context).setDefaultsDescriptor(_wrapper.getOSGiAppProvider().getDefaultsDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -722,18 +731,15 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
}
|
||||
catch (SAXException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
__logger.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -775,13 +781,12 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
{
|
||||
if (context instanceof WebAppContext)
|
||||
{
|
||||
WebAppContext webappCtxt = (WebAppContext)context;
|
||||
WebAppContext webappCtxt = (WebAppContext) context;
|
||||
context.setClassLoader(webappClassLoader);
|
||||
webappClassLoader.setWebappContext(webappCtxt);
|
||||
|
||||
String pathsToRequiredBundles = getPathsToRequiredBundles(context, requireTldBundle);
|
||||
if (pathsToRequiredBundles != null)
|
||||
webappClassLoader.addClassPath(pathsToRequiredBundles);
|
||||
if (pathsToRequiredBundles != null) webappClassLoader.addClassPath(pathsToRequiredBundles);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -797,23 +802,48 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
// we use a temporary WebAppContext object.
|
||||
// if this is a real webapp we will set it on it a bit later: once we
|
||||
// know.
|
||||
OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(
|
||||
_wrapper.getParentClassLoaderForWebapps(),new WebAppContext(),contributor,BUNDLE_CLASS_LOADER_HELPER);
|
||||
/* DEBUG
|
||||
try {
|
||||
Class c = webappClassLoader.loadClass("org.glassfish.jsp.api.ResourceInjector");
|
||||
System.err.println("LOADED org.glassfish.jsp.api.ResourceInjector from "+c.getClassLoader());
|
||||
}
|
||||
catch (Exception e) {e.printStackTrace();}
|
||||
try {
|
||||
Class c = webappClassLoader.loadClass("org.apache.jasper.xmlparser.ParserUtils");
|
||||
System.err.println("LOADED org.apache.jasper.xmlparser.ParserUtils from "+c.getClassLoader());
|
||||
}
|
||||
catch (Exception e) {e.printStackTrace();}
|
||||
*/
|
||||
OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(_wrapper.getParentClassLoaderForWebapps(), new WebAppContext(), contributor,
|
||||
BUNDLE_CLASS_LOADER_HELPER);
|
||||
return webappClassLoader;
|
||||
}
|
||||
|
||||
|
||||
protected void applyMetaInfContextXml (Bundle bundle, ContextHandler contextHandler)
|
||||
throws Exception
|
||||
{
|
||||
if (bundle == null)
|
||||
return;
|
||||
if (contextHandler == null)
|
||||
return;
|
||||
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
__logger.info("Context classloader = "+cl);
|
||||
try
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(_wrapper.getParentClassLoaderForWebapps());
|
||||
|
||||
//find if there is a META-INF/context.xml file
|
||||
URL contextXmlUrl = bundle.getEntry("/META-INF/jetty-webapp-context.xml");
|
||||
if (contextXmlUrl == null)
|
||||
return;
|
||||
|
||||
//Apply it just as the standard jetty ContextProvider would do
|
||||
__logger.info("Applying "+contextXmlUrl+" to "+contextHandler);
|
||||
|
||||
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
|
||||
HashMap properties = new HashMap();
|
||||
properties.put("Server", _wrapper.getServer());
|
||||
xmlConfiguration.getProperties().putAll(properties);
|
||||
xmlConfiguration.configure(contextHandler);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.currentThread().setContextClassLoader(cl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the property "this.bundle.install" to point to the location
|
||||
* of the bundle. Useful when <SystemProperty name="this.bundle.home"/> is
|
||||
|
@ -823,10 +853,9 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
{
|
||||
try
|
||||
{
|
||||
File location = overrideBundleInstallLocation != null?new File(overrideBundleInstallLocation):BUNDLE_FILE_LOCATOR_HELPER
|
||||
.getBundleInstallLocation(bundle);
|
||||
properties.put("this.bundle.install",location.getCanonicalPath());
|
||||
properties.put("this.bundle.install.url",bundle.getEntry("/").toString());
|
||||
File location = overrideBundleInstallLocation != null ? new File(overrideBundleInstallLocation) : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle);
|
||||
properties.put("this.bundle.install", location.getCanonicalPath());
|
||||
properties.put("this.bundle.install.url", bundle.getEntry("/").toString());
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -834,36 +863,30 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private String getPathsToRequiredBundles (ContextHandler context, String requireTldBundle) throws Exception
|
||||
private String getPathsToRequiredBundles(ContextHandler context, String requireTldBundle) throws Exception
|
||||
{
|
||||
if (requireTldBundle == null)
|
||||
return null;
|
||||
if (requireTldBundle == null) return null;
|
||||
|
||||
StringBuilder paths = new StringBuilder();
|
||||
Bundle bundle = (Bundle)context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
|
||||
Bundle bundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
|
||||
PackageAdmin packAdmin = getBundleAdmin();
|
||||
DefaultFileLocatorHelper fileLocatorHelper = new DefaultFileLocatorHelper();
|
||||
|
||||
|
||||
String[] symbNames = requireTldBundle.split(", ");
|
||||
|
||||
for (String symbName : symbNames)
|
||||
{
|
||||
Bundle[] bs = packAdmin.getBundles(symbName, null);
|
||||
if (bs == null || bs.length == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate the bundle '"
|
||||
+ symbName + "' specified in the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName());
|
||||
}
|
||||
if (bs == null || bs.length == 0) { throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
|
||||
+ "' specified in the "
|
||||
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
|
||||
+ " of the manifest of "
|
||||
+ bundle.getSymbolicName()); }
|
||||
|
||||
|
||||
File f = fileLocatorHelper.getBundleInstallLocation(bs[0]);
|
||||
if (paths.length() > 0)
|
||||
if (paths.length() > 0)
|
||||
paths.append(", ");
|
||||
System.err.println("getPathsToRequiredBundles: bundle path="+bs[0].getLocation()+" uri="+f.toURI());
|
||||
__logger.debug("getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI());
|
||||
paths.append(f.toURI().toURL().toString());
|
||||
}
|
||||
|
||||
|
@ -872,12 +895,11 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
|
|||
|
||||
private PackageAdmin getBundleAdmin()
|
||||
{
|
||||
Bundle bootBundle = ((BundleReference)OSGiWebappConstants.class.getClassLoader()).getBundle();
|
||||
Bundle bootBundle = ((BundleReference) OSGiWebappConstants.class.getClassLoader()).getBundle();
|
||||
ServiceTracker serviceTracker = new ServiceTracker(bootBundle.getBundleContext(), PackageAdmin.class.getName(), null);
|
||||
serviceTracker.open();
|
||||
|
||||
return (PackageAdmin) serviceTracker.getService();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.osgi.framework.BundleEvent;
|
|||
import org.osgi.util.tracker.BundleTracker;
|
||||
import org.osgi.util.tracker.BundleTrackerCustomizer;
|
||||
|
||||
|
||||
/**
|
||||
* Support bundles that declare the webapp directly through headers in their
|
||||
* manifest.
|
||||
|
@ -49,133 +48,131 @@ import org.osgi.util.tracker.BundleTrackerCustomizer;
|
|||
*
|
||||
* @author hmalphettes
|
||||
*/
|
||||
public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
|
||||
public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebBundleTrackerCustomizer.class);
|
||||
|
||||
|
||||
/**
|
||||
* A bundle is being added to the <code>BundleTracker</code>.
|
||||
*
|
||||
* <p>
|
||||
* This method is called before a bundle which matched the search parameters
|
||||
* of the <code>BundleTracker</code> is added to the
|
||||
* <code>BundleTracker</code>. This method should return the object to be
|
||||
* tracked for the specified <code>Bundle</code>. The returned object is
|
||||
* stored in the <code>BundleTracker</code> and is available from the
|
||||
* {@link BundleTracker#getObject(Bundle) getObject} method.
|
||||
*
|
||||
* @param bundle The <code>Bundle</code> being added to the
|
||||
* <code>BundleTracker</code>.
|
||||
* @param event The bundle event which caused this customizer method to be
|
||||
* called or <code>null</code> if there is no bundle event
|
||||
* associated with the call to this method.
|
||||
* @return The object to be tracked for the specified <code>Bundle</code>
|
||||
* object or <code>null</code> if the specified <code>Bundle</code>
|
||||
* object should not be tracked.
|
||||
*/
|
||||
public Object addingBundle(Bundle bundle, BundleEvent event)
|
||||
{
|
||||
if (bundle.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
boolean isWebBundle = register(bundle);
|
||||
return isWebBundle ? bundle : null;
|
||||
}
|
||||
else if (bundle.getState() == Bundle.STOPPING)
|
||||
{
|
||||
unregister(bundle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we should not be called in that state as
|
||||
// we are registered only for ACTIVE and STOPPING
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bundle is being added to the <code>BundleTracker</code>.
|
||||
*
|
||||
* <p>
|
||||
* This method is called before a bundle which matched the search parameters
|
||||
* of the <code>BundleTracker</code> is added to the
|
||||
* <code>BundleTracker</code>. This method should return the object to be
|
||||
* tracked for the specified <code>Bundle</code>. The returned object is
|
||||
* stored in the <code>BundleTracker</code> and is available from the
|
||||
* {@link BundleTracker#getObject(Bundle) getObject} method.
|
||||
*
|
||||
* @param bundle The <code>Bundle</code> being added to the
|
||||
* <code>BundleTracker</code>.
|
||||
* @param event The bundle event which caused this customizer method to be
|
||||
* called or <code>null</code> if there is no bundle event associated
|
||||
* with the call to this method.
|
||||
* @return The object to be tracked for the specified <code>Bundle</code>
|
||||
* object or <code>null</code> if the specified <code>Bundle</code>
|
||||
* object should not be tracked.
|
||||
*/
|
||||
public Object addingBundle(Bundle bundle, BundleEvent event)
|
||||
{
|
||||
if (bundle.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
boolean isWebBundle = register(bundle);
|
||||
return isWebBundle ? bundle : null;
|
||||
}
|
||||
else if (bundle.getState() == Bundle.STOPPING)
|
||||
{
|
||||
unregister(bundle);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we should not be called in that state as
|
||||
//we are registered only for ACTIVE and STOPPING
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* A bundle tracked by the <code>BundleTracker</code> has been modified.
|
||||
*
|
||||
* <p>
|
||||
* This method is called when a bundle being tracked by the
|
||||
* <code>BundleTracker</code> has had its state modified.
|
||||
*
|
||||
* @param bundle The <code>Bundle</code> whose state has been modified.
|
||||
* @param event The bundle event which caused this customizer method to be
|
||||
* called or <code>null</code> if there is no bundle event
|
||||
* associated with the call to this method.
|
||||
* @param object The tracked object for the specified bundle.
|
||||
*/
|
||||
public void modifiedBundle(Bundle bundle, BundleEvent event, Object object)
|
||||
{
|
||||
// nothing the web-bundle was already track. something changed.
|
||||
// we only reload the webapps if the bundle is stopped and restarted.
|
||||
if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
unregister(bundle);
|
||||
}
|
||||
if (bundle.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
register(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A bundle tracked by the <code>BundleTracker</code> has been modified.
|
||||
*
|
||||
* <p>
|
||||
* This method is called when a bundle being tracked by the
|
||||
* <code>BundleTracker</code> has had its state modified.
|
||||
*
|
||||
* @param bundle The <code>Bundle</code> whose state has been modified.
|
||||
* @param event The bundle event which caused this customizer method to be
|
||||
* called or <code>null</code> if there is no bundle event associated
|
||||
* with the call to this method.
|
||||
* @param object The tracked object for the specified bundle.
|
||||
*/
|
||||
public void modifiedBundle(Bundle bundle, BundleEvent event,
|
||||
Object object)
|
||||
{
|
||||
//nothing the web-bundle was already track. something changed.
|
||||
//we only reload the webapps if the bundle is stopped and restarted.
|
||||
// System.err.println(bundle.getSymbolicName());
|
||||
if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
unregister(bundle);
|
||||
}
|
||||
if (bundle.getState() == Bundle.ACTIVE)
|
||||
{
|
||||
register(bundle);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A bundle tracked by the <code>BundleTracker</code> has been removed.
|
||||
*
|
||||
* <p>
|
||||
* This method is called after a bundle is no longer being tracked by the
|
||||
* <code>BundleTracker</code>.
|
||||
*
|
||||
* @param bundle The <code>Bundle</code> that has been removed.
|
||||
* @param event The bundle event which caused this customizer method to be
|
||||
* called or <code>null</code> if there is no bundle event
|
||||
* associated with the call to this method.
|
||||
* @param object The tracked object for the specified bundle.
|
||||
*/
|
||||
public void removedBundle(Bundle bundle, BundleEvent event, Object object)
|
||||
{
|
||||
unregister(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* A bundle tracked by the <code>BundleTracker</code> has been removed.
|
||||
*
|
||||
* <p>
|
||||
* This method is called after a bundle is no longer being tracked by the
|
||||
* <code>BundleTracker</code>.
|
||||
*
|
||||
* @param bundle The <code>Bundle</code> that has been removed.
|
||||
* @param event The bundle event which caused this customizer method to be
|
||||
* called or <code>null</code> if there is no bundle event associated
|
||||
* with the call to this method.
|
||||
* @param object The tracked object for the specified bundle.
|
||||
*/
|
||||
public void removedBundle(Bundle bundle, BundleEvent event,
|
||||
Object object)
|
||||
{
|
||||
unregister(bundle);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param bundle
|
||||
* @return true if this bundle in indeed a web-bundle.
|
||||
*/
|
||||
/**
|
||||
* @param bundle
|
||||
* @return true if this bundle in indeed a web-bundle.
|
||||
*/
|
||||
private boolean register(Bundle bundle)
|
||||
{
|
||||
Dictionary<?, ?> dic = bundle.getHeaders();
|
||||
String warFolderRelativePath = (String)dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
|
||||
String warFolderRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
|
||||
if (warFolderRelativePath != null)
|
||||
{
|
||||
String contextPath = getWebContextPath(bundle, dic, false);//(String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
String contextPath = getWebContextPath(bundle, dic, false);// (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
if (contextPath == null || !contextPath.startsWith("/"))
|
||||
{
|
||||
LOG.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH +
|
||||
": " + warFolderRelativePath + "' in the bundle " + bundle.getSymbolicName() +
|
||||
" is not valid: there is no Web-ContextPath defined in the manifest.");
|
||||
return false;
|
||||
LOG.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
|
||||
+ ": "
|
||||
+ warFolderRelativePath
|
||||
+ "' in the bundle "
|
||||
+ bundle.getSymbolicName()
|
||||
+ " is not valid: there is no Web-ContextPath defined in the manifest.");
|
||||
return false;
|
||||
}
|
||||
// create the corresponding service and publish it in the context of
|
||||
// the contributor bundle.
|
||||
try
|
||||
{
|
||||
JettyBootstrapActivator.registerWebapplication(bundle,warFolderRelativePath,contextPath);
|
||||
JettyBootstrapActivator.registerWebapplication(bundle, warFolderRelativePath, contextPath);
|
||||
return true;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
LOG.warn("Starting the web-bundle " + bundle.getSymbolicName() + " threw an exception.", e);
|
||||
return true;//maybe it did not work maybe it did. safer to track this bundle.
|
||||
LOG.warn("Starting the web-bundle " + bundle.getSymbolicName() + " threw an exception.", e);
|
||||
return true;// maybe it did not work maybe it did. safer to track this bundle.
|
||||
}
|
||||
}
|
||||
else if (dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH) != null)
|
||||
{
|
||||
String contextFileRelativePath = (String)dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
String contextFileRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_CONTEXT_FILE_PATH);
|
||||
if (contextFileRelativePath == null)
|
||||
{
|
||||
// nothing to register here.
|
||||
|
@ -187,12 +184,11 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
|
|||
{
|
||||
try
|
||||
{
|
||||
JettyBootstrapActivator.registerContext(bundle,path.trim());
|
||||
JettyBootstrapActivator.registerContext(bundle, path.trim());
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -203,8 +199,8 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
|
|||
// (draft) of the spec: just a couple of posts on the
|
||||
// world-wide-web.
|
||||
URL rfc66Webxml = bundle.getEntry("/WEB-INF/web.xml");
|
||||
if (rfc66Webxml == null && dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) == null)
|
||||
{
|
||||
if (rfc66Webxml == null && dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) == null)
|
||||
{
|
||||
return false;// no webapp in here
|
||||
}
|
||||
// this is risky: should we make sure that there is no classes and
|
||||
|
@ -215,42 +211,39 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
|
|||
// pointing to files and folders inside WEB-INF. We should
|
||||
// filter-out
|
||||
// META-INF too
|
||||
String rfc66ContextPath = getWebContextPath(bundle,dic,rfc66Webxml==null);
|
||||
String rfc66ContextPath = getWebContextPath(bundle, dic, rfc66Webxml == null);
|
||||
try
|
||||
{
|
||||
JettyBootstrapActivator.registerWebapplication(bundle,".",rfc66ContextPath);
|
||||
JettyBootstrapActivator.registerWebapplication(bundle, ".", rfc66ContextPath);
|
||||
return true;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return true;//maybe it did not work maybe it did. safer to track this bundle.
|
||||
LOG.warn(e);
|
||||
return true;// maybe it did not work maybe it did. safer to track this bundle.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getWebContextPath(Bundle bundle, Dictionary<?, ?> dic, boolean webinfWebxmlExists)
|
||||
{
|
||||
String rfc66ContextPath = (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
String rfc66ContextPath = (String) dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
|
||||
if (rfc66ContextPath == null)
|
||||
{
|
||||
if (!webinfWebxmlExists) {
|
||||
return null;
|
||||
}
|
||||
if (!webinfWebxmlExists) { return null; }
|
||||
// extract from the last token of the bundle's location:
|
||||
// (really ?
|
||||
// could consider processing the symbolic name as an alternative
|
||||
// the location will often reflect the version.
|
||||
// maybe this is relevant when the file is a war)
|
||||
String location = bundle.getLocation();
|
||||
String toks[] = location.replace('\\','/').split("/");
|
||||
String toks[] = location.replace('\\', '/').split("/");
|
||||
rfc66ContextPath = toks[toks.length - 1];
|
||||
// remove .jar, .war etc:
|
||||
int lastDot = rfc66ContextPath.lastIndexOf('.');
|
||||
if (lastDot != -1)
|
||||
{
|
||||
rfc66ContextPath = rfc66ContextPath.substring(0,lastDot);
|
||||
rfc66ContextPath = rfc66ContextPath.substring(0, lastDot);
|
||||
}
|
||||
}
|
||||
if (!rfc66ContextPath.startsWith("/"))
|
||||
|
@ -259,7 +252,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
|
|||
}
|
||||
return rfc66ContextPath;
|
||||
}
|
||||
|
||||
|
||||
private void unregister(Bundle bundle)
|
||||
{
|
||||
// nothing to do: when the bundle is stopped, each one of its service
|
||||
|
@ -268,7 +261,4 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
|
|||
// webapps registered in that bundle.
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.zip.ZipFile;
|
|||
|
||||
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.FileResource;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
|
@ -43,11 +44,13 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
// The url nuxeo and felix return is created directly from the File so it
|
||||
// should work.
|
||||
private static Field BUNDLE_ENTRY_FIELD = null;
|
||||
|
||||
private static Field FILE_FIELD = null;
|
||||
|
||||
private static Field BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY = null;// ZipBundleFile
|
||||
// inside
|
||||
// DirZipBundleEntry
|
||||
|
||||
// inside
|
||||
// DirZipBundleEntry
|
||||
|
||||
private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null;// ZipFile
|
||||
|
||||
|
@ -56,8 +59,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
* spirit of OSGi but quite necessary to support self-contained webapps and
|
||||
* other situations.
|
||||
*
|
||||
* @param bundle
|
||||
* The bundle
|
||||
* @param bundle The bundle
|
||||
* @return Its installation location as a file.
|
||||
* @throws Exception
|
||||
*/
|
||||
|
@ -67,19 +69,23 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
// grab the MANIFEST.MF's url
|
||||
// and then do what it takes.
|
||||
URL url = bundle.getEntry("/META-INF/MANIFEST.MF");
|
||||
// System.err.println(url.toString() + " " + url.toURI() + " " + url.getProtocol());
|
||||
|
||||
if (url.getProtocol().equals("file"))
|
||||
{
|
||||
// some osgi frameworks do use the file protocole directly in some
|
||||
// situations. Do use the FileResource to transform the URL into a File: URL#toURI is broken
|
||||
return new FileResource(url).getFile().getParentFile().getParentFile();
|
||||
// situations. Do use the FileResource to transform the URL into a
|
||||
// File: URL#toURI is broken
|
||||
return new FileResource(url).getFile().getParentFile().getParentFile();
|
||||
}
|
||||
else if (url.getProtocol().equals("bundleentry"))
|
||||
{
|
||||
// say hello to equinox who has its own protocol.
|
||||
// we use introspection like there is no tomorrow to get access to
|
||||
// the File
|
||||
|
||||
URLConnection con = url.openConnection();
|
||||
con.setUseCaches(Resource.getDefaultUseCaches()); //work around problems where url connections cache references to jars
|
||||
|
||||
if (BUNDLE_ENTRY_FIELD == null)
|
||||
{
|
||||
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
|
||||
|
@ -93,13 +99,16 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
FILE_FIELD = bundleEntry.getClass().getDeclaredField("file");
|
||||
FILE_FIELD.setAccessible(true);
|
||||
}
|
||||
File f = (File)FILE_FIELD.get(bundleEntry);
|
||||
File f = (File) FILE_FIELD.get(bundleEntry);
|
||||
return f.getParentFile().getParentFile();
|
||||
}
|
||||
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry"))
|
||||
{
|
||||
url = bundle.getEntry("/");
|
||||
|
||||
con = url.openConnection();
|
||||
con.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
|
||||
if (BUNDLE_ENTRY_FIELD == null)
|
||||
{// this one will be a DirZipBundleEntry
|
||||
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
|
||||
|
@ -117,7 +126,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = zipBundleFile.getClass().getDeclaredField("zipFile");
|
||||
ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.setAccessible(true);
|
||||
}
|
||||
ZipFile zipFile = (ZipFile)ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile);
|
||||
ZipFile zipFile = (ZipFile) ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile);
|
||||
return new File(zipFile.getName());
|
||||
}
|
||||
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry"))
|
||||
|
@ -130,7 +139,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
{
|
||||
// observed this on felix-2.0.0
|
||||
String location = bundle.getLocation();
|
||||
// System.err.println("location " + location);
|
||||
// System.err.println("location " + location);
|
||||
if (location.startsWith("file:/"))
|
||||
{
|
||||
URI uri = new URI(URIUtil.encodePath(location));
|
||||
|
@ -138,27 +147,32 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
}
|
||||
else if (location.startsWith("file:"))
|
||||
{
|
||||
//location defined in the BundleArchive m_bundleArchive
|
||||
//it is relative to relative to the BundleArchive's m_archiveRootDir
|
||||
File res = new File(location.substring("file:".length()));
|
||||
if (!res.exists())
|
||||
{
|
||||
return null;
|
||||
// Object bundleArchive = getFelixBundleArchive(bundle);
|
||||
// File archiveRoot = getFelixBundleArchiveRootDir(bundleArchive);
|
||||
// String currentLocation = getFelixBundleArchiveCurrentLocation(bundleArchive);
|
||||
// System.err.println("Got the archive root " + archiveRoot.getAbsolutePath()
|
||||
// + " current location " + currentLocation + " is directory ?");
|
||||
// res = new File(archiveRoot, currentLocation != null
|
||||
// ? currentLocation : location.substring("file:".length()));
|
||||
}
|
||||
return res;
|
||||
// location defined in the BundleArchive m_bundleArchive
|
||||
// it is relative to relative to the BundleArchive's
|
||||
// m_archiveRootDir
|
||||
File res = new File(location.substring("file:".length()));
|
||||
if (!res.exists())
|
||||
{
|
||||
return null;
|
||||
// Object bundleArchive = getFelixBundleArchive(bundle);
|
||||
// File archiveRoot =
|
||||
// getFelixBundleArchiveRootDir(bundleArchive);
|
||||
// String currentLocation =
|
||||
// getFelixBundleArchiveCurrentLocation(bundleArchive);
|
||||
// System.err.println("Got the archive root " +
|
||||
// archiveRoot.getAbsolutePath()
|
||||
// + " current location " + currentLocation +
|
||||
// " is directory ?");
|
||||
// res = new File(archiveRoot, currentLocation != null
|
||||
// ? currentLocation : location.substring("file:".length()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
else if (location.startsWith("reference:file:"))
|
||||
{
|
||||
location = URLDecoder.decode(location.substring("reference:".length()), "UTF-8");
|
||||
File file = new File(location.substring("file:".length()));
|
||||
return file;
|
||||
location = URLDecoder.decode(location.substring("reference:".length()), "UTF-8");
|
||||
File file = new File(location.substring("file:".length()));
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -179,37 +193,40 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
path = path.substring(1);
|
||||
}
|
||||
File bundleInstall = getBundleInstallLocation(bundle);
|
||||
File webapp = path != null && path.length() != 0?new File(bundleInstall,path):bundleInstall;
|
||||
if (!webapp.exists())
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + path + " inside " + bundle.getSymbolicName() + " ("
|
||||
+ (bundleInstall != null?bundleInstall.getAbsolutePath():" no_bundle_location ") + ")");
|
||||
File webapp = path != null && path.length() != 0 ? new File(bundleInstall, path) : bundleInstall;
|
||||
if (!webapp.exists())
|
||||
{
|
||||
throw new IllegalArgumentException("Unable to locate " + path
|
||||
+ " inside "
|
||||
+ bundle.getSymbolicName()
|
||||
+ " ("
|
||||
+ (bundleInstall != null ? bundleInstall.getAbsolutePath() : " no_bundle_location ")
|
||||
+ ")");
|
||||
}
|
||||
return webapp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method equivalent to Bundle#getEntry(String entryPath) except that
|
||||
* it searches for entries in the fragments by using the Bundle#findEntries method.
|
||||
*
|
||||
* @param bundle
|
||||
* @param entryPath
|
||||
* @return null or all the entries found for that path.
|
||||
*/
|
||||
public Enumeration<URL> findEntries(Bundle bundle, String entryPath)
|
||||
{
|
||||
int last = entryPath.lastIndexOf('/');
|
||||
String path = last != -1 && last < entryPath.length() -2
|
||||
? entryPath.substring(0, last) : "/";
|
||||
if (!path.startsWith("/"))
|
||||
{
|
||||
path = "/" + path;
|
||||
}
|
||||
String pattern = last != -1 && last < entryPath.length() -2
|
||||
? entryPath.substring(last+1) : entryPath;
|
||||
Enumeration<URL> enUrls = bundle.findEntries(path, pattern, false);
|
||||
return enUrls;
|
||||
}
|
||||
* Helper method equivalent to Bundle#getEntry(String entryPath) except that
|
||||
* it searches for entries in the fragments by using the Bundle#findEntries
|
||||
* method.
|
||||
*
|
||||
* @param bundle
|
||||
* @param entryPath
|
||||
* @return null or all the entries found for that path.
|
||||
*/
|
||||
public Enumeration<URL> findEntries(Bundle bundle, String entryPath)
|
||||
{
|
||||
int last = entryPath.lastIndexOf('/');
|
||||
String path = last != -1 && last < entryPath.length() - 2 ? entryPath.substring(0, last) : "/";
|
||||
if (!path.startsWith("/"))
|
||||
{
|
||||
path = "/" + path;
|
||||
}
|
||||
String pattern = last != -1 && last < entryPath.length() - 2 ? entryPath.substring(last + 1) : entryPath;
|
||||
Enumeration<URL> enUrls = bundle.findEntries(path, pattern, false);
|
||||
return enUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the bundle is a jar, returns the jar. If the bundle is a folder, look
|
||||
|
@ -256,76 +273,84 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
|
|||
return new File[] { jasperLocation };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//introspection on equinox to invoke the getLocalURL method on BundleURLConnection
|
||||
//equivalent to using the FileLocator without depending on an equinox class.
|
||||
private static Method BUNDLE_URL_CONNECTION_getLocalURL = null;
|
||||
private static Method BUNDLE_URL_CONNECTION_getFileURL = null;
|
||||
/**
|
||||
* Only useful for equinox: on felix we get the file:// or jar:// url already.
|
||||
* Other OSGi implementations have not been tested
|
||||
* <p>
|
||||
* Get a URL to the bundle entry that uses a common protocol (i.e. file:
|
||||
* jar: or http: etc.).
|
||||
* </p>
|
||||
* @return a URL to the bundle entry that uses a common protocol
|
||||
*/
|
||||
public static URL getLocalURL(URL url) {
|
||||
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol())) {
|
||||
try {
|
||||
URLConnection conn = url.openConnection();
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL == null &&
|
||||
conn.getClass().getName().equals(
|
||||
"org.eclipse.osgi.framework.internal.core.BundleURLConnection")) {
|
||||
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null);
|
||||
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
|
||||
}
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL != null) {
|
||||
return (URL)BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn, null);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
System.err.println("Unable to locate the OSGi url: '" + url + "'.");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
/**
|
||||
* Only useful for equinox: on felix we get the file:// url already.
|
||||
* Other OSGi implementations have not been tested
|
||||
* <p>
|
||||
* Get a URL to the content of the bundle entry that uses the file: protocol.
|
||||
* The content of the bundle entry may be downloaded or extracted to the local
|
||||
* file system in order to create a file: URL.
|
||||
* @return a URL to the content of the bundle entry that uses the file: protocol
|
||||
* </p>
|
||||
*/
|
||||
public static URL getFileURL(URL url)
|
||||
{
|
||||
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
|
||||
{
|
||||
try
|
||||
{
|
||||
URLConnection conn = url.openConnection();
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL == null &&
|
||||
conn.getClass().getName().equals(
|
||||
"org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null);
|
||||
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);
|
||||
}
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL != null)
|
||||
{
|
||||
return (URL)BUNDLE_URL_CONNECTION_getFileURL.invoke(conn, null);
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
// introspection on equinox to invoke the getLocalURL method on
|
||||
// BundleURLConnection
|
||||
// equivalent to using the FileLocator without depending on an equinox
|
||||
// class.
|
||||
private static Method BUNDLE_URL_CONNECTION_getLocalURL = null;
|
||||
|
||||
private static Method BUNDLE_URL_CONNECTION_getFileURL = null;
|
||||
|
||||
/**
|
||||
* Only useful for equinox: on felix we get the file:// or jar:// url
|
||||
* already. Other OSGi implementations have not been tested
|
||||
* <p>
|
||||
* Get a URL to the bundle entry that uses a common protocol (i.e. file:
|
||||
* jar: or http: etc.).
|
||||
* </p>
|
||||
*
|
||||
* @return a URL to the bundle entry that uses a common protocol
|
||||
*/
|
||||
public static URL getLocalURL(URL url)
|
||||
{
|
||||
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
|
||||
{
|
||||
try
|
||||
{
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL == null && conn.getClass().getName()
|
||||
.equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null);
|
||||
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
|
||||
}
|
||||
if (BUNDLE_URL_CONNECTION_getLocalURL != null) { return (URL) BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn, null); }
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
System.err.println("Unable to locate the OSGi url: '" + url + "'.");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only useful for equinox: on felix we get the file:// url already. Other
|
||||
* OSGi implementations have not been tested
|
||||
* <p>
|
||||
* Get a URL to the content of the bundle entry that uses the file:
|
||||
* protocol. The content of the bundle entry may be downloaded or extracted
|
||||
* to the local file system in order to create a file: URL.
|
||||
*
|
||||
* @return a URL to the content of the bundle entry that uses the file:
|
||||
* protocol
|
||||
* </p>
|
||||
*/
|
||||
public static URL getFileURL(URL url)
|
||||
{
|
||||
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
|
||||
{
|
||||
try
|
||||
{
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL == null && conn.getClass().getName()
|
||||
.equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
|
||||
{
|
||||
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null);
|
||||
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);
|
||||
}
|
||||
if (BUNDLE_URL_CONNECTION_getFileURL != null) { return (URL) BUNDLE_URL_CONNECTION_getFileURL.invoke(conn, null); }
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,20 +3,20 @@ Bundle-ManifestVersion: 2
|
|||
Bundle-Name: Console
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.equinoxtools
|
||||
Bundle-Description: Example application: equinox console accesssible on the web
|
||||
Bundle-Version: 7.6.2.qualifier
|
||||
Bundle-Version: 7.6.3.qualifier
|
||||
Bundle-Activator: org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator
|
||||
Import-Package: javax.servlet;version="2.5.0",
|
||||
javax.servlet.http;version="2.5.0",
|
||||
org.eclipse.jetty.continuation;version="7.6.2",
|
||||
org.eclipse.jetty.io;version="7.6.2",
|
||||
org.eclipse.jetty.util;version="7.6.2",
|
||||
org.eclipse.jetty.util.log;version="7.6.2",
|
||||
org.eclipse.jetty.websocket;version="7.6.2",
|
||||
org.eclipse.jetty.continuation;version="7.6.3",
|
||||
org.eclipse.jetty.io;version="7.6.3",
|
||||
org.eclipse.jetty.util;version="7.6.3",
|
||||
org.eclipse.jetty.util.log;version="7.6.3",
|
||||
org.eclipse.jetty.websocket;version="7.6.3",
|
||||
org.eclipse.osgi.framework.console;version="1.1.0",
|
||||
org.osgi.framework;version="1.3.0",
|
||||
org.osgi.service.http;version="1.2.0",
|
||||
org.osgi.util.tracker;version="1.3.0"
|
||||
Export-Package: org.eclipse.jetty.osgi.equinoxtools;x-internal:=true;version="7.6.2",
|
||||
org.eclipse.jetty.osgi.equinoxtools.console;x-internal:=true;version="7.6.2"
|
||||
Export-Package: org.eclipse.jetty.osgi.equinoxtools;x-internal:=true;version="7.6.3",
|
||||
org.eclipse.jetty.osgi.equinoxtools.console;x-internal:=true;version="7.6.3"
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-RequiredExecutionEnvironment: J2SE-1.5
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.httpservice
|
||||
Bundle-Version: 7.6.2.qualifier
|
||||
Bundle-Version: 7.6.3.qualifier
|
||||
Bundle-Vendor: Mort Bay Consulting
|
||||
Bundle-Name: OSGi HttpService provided by equinox HttpServiceServlet deployed on jetty
|
||||
Jetty-ContextFilePath: contexts/httpservice.xml
|
||||
Import-Package: javax.servlet;version="2.5.0",
|
||||
javax.servlet.http;version="2.5.0",
|
||||
org.eclipse.equinox.http.servlet,
|
||||
org.eclipse.jetty.server;version="7.6.2",
|
||||
org.eclipse.jetty.server.handler;version="7.6.2",
|
||||
org.eclipse.jetty.servlet;version="7.6.2",
|
||||
org.eclipse.jetty.util.component;version="7.6.2"
|
||||
Export-Package: org.eclipse.jetty.osgi.httpservice;version="7.6.2"
|
||||
org.eclipse.jetty.server;version="7.6.3",
|
||||
org.eclipse.jetty.server.handler;version="7.6.3",
|
||||
org.eclipse.jetty.servlet;version="7.6.3",
|
||||
org.eclipse.jetty.util.component;version="7.6.3"
|
||||
Export-Package: org.eclipse.jetty.osgi.httpservice;version="7.6.3"
|
||||
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
package org.eclipse.jetty.rewrite.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.server.handler.ScopedHandler;
|
||||
import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A handle that uses regular expressions to select the target.
|
||||
* <p>
|
||||
* This handler applies a list of regex to target name mappings to the URIs of requests.
|
||||
* If the regex matches the URI, then the mapped target name is used in the nested
|
||||
* call to {@link #doScope(String, Request, HttpServletRequest, HttpServletResponse)}.
|
||||
* <p>
|
||||
* This handler should be installed as the first handler in a Context. It can be configured
|
||||
* either with direct calls to {@link #addPatternTarget(String, String)} or by setting
|
||||
* the context init parameters "org.eclipse.jetty.rewrite.handler.REGEX_MAPPINGS" to a comma
|
||||
* separated list of strings in the format regex==target.
|
||||
*/
|
||||
public class RegexTargetHandler extends ScopedHandler
|
||||
{
|
||||
private final static Logger LOG = Log.getLogger(RegexTargetHandler.class);
|
||||
public final static String REGEX_MAPPINGS="org.eclipse.jetty.rewrite.handler.REGEX_MAPPINGS";
|
||||
static class RegexMapping
|
||||
{
|
||||
RegexMapping(String regex,String target)
|
||||
{
|
||||
_pattern=Pattern.compile(regex);
|
||||
_target=target;
|
||||
}
|
||||
final Pattern _pattern;
|
||||
final String _target;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return _pattern+"=="+_target;
|
||||
}
|
||||
}
|
||||
|
||||
final private List<RegexTargetHandler.RegexMapping> _patterns = new CopyOnWriteArrayList<RegexTargetHandler.RegexMapping>();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Add a pattern to target mapping.
|
||||
* @param pattern The regular expression pattern to match.
|
||||
* @param target The target (normally servlet name) to handle the request
|
||||
*/
|
||||
public void addPatternTarget(String pattern,String target)
|
||||
{
|
||||
_patterns.add(new RegexMapping(pattern,target));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
super.doStart();
|
||||
|
||||
Context context = ContextHandler.getCurrentContext();
|
||||
if (context!=null)
|
||||
{
|
||||
String config=context.getInitParameter(REGEX_MAPPINGS);
|
||||
LOG.debug("{}={}",REGEX_MAPPINGS,config);
|
||||
String[] mappings=config.split("\\s*,\\s*");
|
||||
for (String mapping : mappings)
|
||||
{
|
||||
mapping=mapping.trim();
|
||||
String[] parts=mapping.split("\\s*==\\s*");
|
||||
if (parts.length==2)
|
||||
{
|
||||
String pattern=parts[0];
|
||||
String target=parts[1];
|
||||
addPatternTarget(pattern,target);
|
||||
}
|
||||
else
|
||||
LOG.warn("Bad regex mapping: "+mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
for (RegexTargetHandler.RegexMapping rm : _patterns)
|
||||
{
|
||||
Matcher m=rm._pattern.matcher(target);
|
||||
if (m.matches())
|
||||
{
|
||||
String new_target = rm._target;
|
||||
final String sp;
|
||||
final String pi;
|
||||
|
||||
if (m.groupCount()==1&&target.endsWith(m.group(1)))
|
||||
{
|
||||
pi=m.group(1);
|
||||
sp=target.substring(0,target.length()-pi.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
sp=target;
|
||||
pi=null;
|
||||
}
|
||||
baseRequest.setServletPath(sp);
|
||||
baseRequest.setPathInfo(pi);
|
||||
baseRequest.setAttribute("org.eclipse.jetty.servlet.REGEX_PATH",target);
|
||||
super.nextScope(new_target,baseRequest,request,response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.nextScope(target,baseRequest,request,response);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
String path=(String)baseRequest.getAttribute("org.eclipse.jetty.servlet.REGEX_PATH");
|
||||
if (path==null)
|
||||
path=target;
|
||||
else
|
||||
baseRequest.setAttribute("org.eclipse.jetty.servlet.REGEX_PATH",null);
|
||||
|
||||
super.nextHandle(path,baseRequest,request,response);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
AggregateLifeCycle.dumpObject(out,this);
|
||||
AggregateLifeCycle.dump(out,indent,_patterns,Collections.singletonList(getHandler()));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ import java.util.regex.Matcher;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
|
||||
/**
|
||||
|
@ -89,14 +90,20 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI
|
|||
/* ------------------------------------------------------------ */
|
||||
public void applyURI(Request request, String oldTarget, String newTarget) throws IOException
|
||||
{
|
||||
request.setRequestURI(newTarget);
|
||||
if (_query!=null)
|
||||
if (_query==null)
|
||||
{
|
||||
request.setRequestURI(newTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
String query=(String)request.getAttribute("org.eclipse.jetty.rewrite.handler.RewriteRegexRule.Q");
|
||||
if (_queryGroup||request.getQueryString()==null)
|
||||
request.setQueryString(query);
|
||||
else
|
||||
request.setQueryString(request.getQueryString()+"&"+query);
|
||||
|
||||
if (!_queryGroup && request.getQueryString()!=null)
|
||||
query=request.getQueryString()+"&"+query;
|
||||
HttpURI uri=new HttpURI(newTarget+"?"+query);
|
||||
request.setUri(uri);
|
||||
request.setRequestURI(newTarget);
|
||||
request.setQueryString(query);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2009 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.rewrite.handler;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequestWrapper;
|
||||
import javax.servlet.ServletResponseWrapper;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.rewrite.handler.RegexTargetHandler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class RegexTargetHandlerTest
|
||||
{
|
||||
private static Server __server = new Server(0);
|
||||
private static int __port;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws Exception
|
||||
{
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/");
|
||||
__server.setHandler(context);
|
||||
|
||||
// Serve some hello world servlets
|
||||
context.addServlet(DispatchServletServlet.class,"/dispatch/*");
|
||||
context.addServlet(new ServletHolder("HelloAll",new HelloServlet("Hello World")),"/*");
|
||||
context.addServlet(new ServletHolder("Italian",new HelloServlet("Buongiorno Mondo")),"/it/*");
|
||||
context.addServlet(new ServletHolder("French", new HelloServlet("Bonjour le Monde")),"/fr/*");
|
||||
|
||||
RegexTargetHandler regexHandler=new RegexTargetHandler();
|
||||
regexHandler.setHandler(context.getHandler());
|
||||
context.setHandler(regexHandler);
|
||||
|
||||
context.getInitParams().put(RegexTargetHandler.REGEX_MAPPINGS,
|
||||
" .*\\.fr==French, \n"+
|
||||
"/ciao(/.*)$==Italian");
|
||||
|
||||
__server.start();
|
||||
|
||||
__port=__server.getConnectors()[0].getLocalPort();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() throws Exception
|
||||
{
|
||||
__server.stop();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNormal() throws Exception
|
||||
{
|
||||
String[] response=getResponse("/normal");
|
||||
assertEquals("HTTP/1.1 200 OK",response[0]);
|
||||
assertEquals("Hello World",response[1]);
|
||||
assertEquals("",response[2]);
|
||||
assertEquals("/normal",response[3]);
|
||||
|
||||
response=getResponse("/it/info");
|
||||
assertEquals("HTTP/1.1 200 OK",response[0]);
|
||||
assertEquals("Buongiorno Mondo",response[1]);
|
||||
assertEquals("/it",response[2]);
|
||||
assertEquals("/info",response[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFullMatch() throws Exception
|
||||
{
|
||||
String[] response=getResponse("/some/thing.fr");
|
||||
assertEquals("HTTP/1.1 200 OK",response[0]);
|
||||
assertEquals("Bonjour le Monde",response[1]);
|
||||
assertEquals("/some/thing.fr",response[2]);
|
||||
assertEquals("null",response[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaptureMatch() throws Exception
|
||||
{
|
||||
String[] response=getResponse("/ciao/info");
|
||||
assertEquals("HTTP/1.1 200 OK",response[0]);
|
||||
assertEquals("Buongiorno Mondo",response[1]);
|
||||
assertEquals("/ciao",response[2]);
|
||||
assertEquals("/info",response[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchFullMatch() throws Exception
|
||||
{
|
||||
String[] response=getResponse("/dispatch/xxx?forward=/some/thing.fr");
|
||||
assertEquals("HTTP/1.1 200 OK",response[0]);
|
||||
assertEquals("Bonjour le Monde",response[1]);
|
||||
assertEquals("/some/thing.fr",response[2]);
|
||||
assertEquals("null",response[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchCaptureMatch() throws Exception
|
||||
{
|
||||
String[] response=getResponse("/dispatch/xxx?forward=/ciao/info");
|
||||
assertEquals("HTTP/1.1 200 OK",response[0]);
|
||||
assertEquals("Buongiorno Mondo",response[1]);
|
||||
assertEquals("/ciao",response[2]);
|
||||
assertEquals("/info",response[3]);
|
||||
}
|
||||
|
||||
|
||||
private String[] getResponse(String uri) throws Exception
|
||||
{
|
||||
Socket socket = new Socket("127.0.0.1",__port);
|
||||
|
||||
PrintWriter out = new PrintWriter(socket.getOutputStream());
|
||||
out.print("GET "+uri+" HTTP/1.0\r\n\r\n");
|
||||
out.flush();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
|
||||
String[] response=new String[4];
|
||||
response[0]=in.readLine();
|
||||
//System.err.println(response[0]);
|
||||
|
||||
String line=in.readLine();
|
||||
while(line.length()>0)
|
||||
line=in.readLine();
|
||||
|
||||
response[1]=in.readLine();
|
||||
//System.err.println(response[1]);
|
||||
response[2]=in.readLine();
|
||||
//System.err.println(response[2]);
|
||||
response[3]=in.readLine();
|
||||
//System.err.println(response[3]);
|
||||
|
||||
socket.close();
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
public static class HelloServlet extends HttpServlet implements Servlet
|
||||
{
|
||||
final String _hello;
|
||||
|
||||
public HelloServlet(String hello)
|
||||
{
|
||||
_hello=hello;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
response.setStatus(200);
|
||||
response.getWriter().println(_hello);
|
||||
response.getWriter().println(request.getServletPath());
|
||||
response.getWriter().println(request.getPathInfo());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class DispatchServletServlet extends HttpServlet implements Servlet
|
||||
{
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
RequestDispatcher dispatcher = null;
|
||||
|
||||
if(request.getParameter("include")!=null)
|
||||
{
|
||||
dispatcher = getServletContext().getRequestDispatcher(request.getParameter("include"));
|
||||
dispatcher.include(new HttpServletRequestWrapper(request), new HttpServletResponseWrapper(response));
|
||||
}
|
||||
else if(request.getParameter("forward")!=null)
|
||||
{
|
||||
dispatcher = getServletContext().getRequestDispatcher(request.getParameter("forward"));
|
||||
dispatcher.forward(new HttpServletRequestWrapper(request), new HttpServletResponseWrapper(response));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,10 @@ package org.eclipse.jetty.rewrite.handler;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -23,21 +27,21 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
|
|||
{
|
||||
private String[][] _tests=
|
||||
{
|
||||
{"/foo/bar",null,".*","/replace","/replace",null},
|
||||
{"/foo/bar","n=v",".*","/replace","/replace","n=v"},
|
||||
{"/foo/bar",null,"/xxx.*","/replace",null,null},
|
||||
{"/foo/bar",null,"/(.*)/(.*)","/$2/$1/xxx","/bar/foo/xxx",null},
|
||||
{"/foo/bar",null,"/(.*)/(.*)","/test?p2=$2&p1=$1","/test","p2=bar&p1=foo"},
|
||||
{"/foo/bar","n=v","/(.*)/(.*)","/test?p2=$2&p1=$1","/test","n=v&p2=bar&p1=foo"},
|
||||
{"/foo/bar",null,"/(.*)/(.*)","/foo/bar?p2=$2&p1=$1","/foo/bar","p2=bar&p1=foo"},
|
||||
{"/foo/bar","n=v","/(.*)/(.*)","/foo/bar?p2=$2&p1=$1","/foo/bar","n=v&p2=bar&p1=foo"},
|
||||
{"/foo/bar",null,"/(foo)/(.*)(bar)","/$3/$1/xxx$2","/bar/foo/xxx",null},
|
||||
{"/foo/$bar",null,".*","/$replace","/$replace",null},
|
||||
{"/foo/$bar",null,"/foo/(.*)","/$1/replace","/$bar/replace",null},
|
||||
{"/foo/bar/info",null,"/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","p1=bar"},
|
||||
{"/foo/bar/info",null,"/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&"},
|
||||
{"/foo/bar/info","n=v","/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&n=v"},
|
||||
{"/foo/bar/info","n=v","/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","n=v&p1=bar"},
|
||||
{"/foo0/bar",null,".*","/replace","/replace",null},
|
||||
{"/foo1/bar","n=v",".*","/replace","/replace","n=v"},
|
||||
{"/foo2/bar",null,"/xxx.*","/replace",null,null},
|
||||
{"/foo3/bar",null,"/(.*)/(.*)","/$2/$1/xxx","/bar/foo3/xxx",null},
|
||||
{"/foo4/bar",null,"/(.*)/(.*)","/test?p2=$2&p1=$1","/test","p2=bar&p1=foo4"},
|
||||
{"/foo5/bar","n=v","/(.*)/(.*)","/test?p2=$2&p1=$1","/test","n=v&p2=bar&p1=foo5"},
|
||||
{"/foo6/bar",null,"/(.*)/(.*)","/foo6/bar?p2=$2&p1=$1","/foo6/bar","p2=bar&p1=foo6"},
|
||||
{"/foo7/bar","n=v","/(.*)/(.*)","/foo7/bar?p2=$2&p1=$1","/foo7/bar","n=v&p2=bar&p1=foo7"},
|
||||
{"/foo8/bar",null,"/(foo8)/(.*)(bar)","/$3/$1/xxx$2","/bar/foo8/xxx",null},
|
||||
{"/foo9/$bar",null,".*","/$replace","/$replace",null},
|
||||
{"/fooA/$bar",null,"/fooA/(.*)","/$1/replace","/$bar/replace",null},
|
||||
{"/fooB/bar/info",null,"/fooB/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","p1=bar"},
|
||||
{"/fooC/bar/info",null,"/fooC/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&"},
|
||||
{"/fooD/bar/info","n=v","/fooD/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&n=v"},
|
||||
{"/fooE/bar/info","n=v","/fooE/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","n=v&p1=bar"},
|
||||
};
|
||||
private RewriteRegexRule _rule;
|
||||
|
||||
|
@ -53,20 +57,35 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
|
|||
{
|
||||
for (String[] test : _tests)
|
||||
{
|
||||
reset();
|
||||
_request.setRequestURI(null);
|
||||
|
||||
String t=test[0]+"?"+test[1]+">"+test[2]+"|"+test[3];
|
||||
_rule.setRegex(test[2]);
|
||||
_rule.setReplacement(test[3]);
|
||||
|
||||
_request.setRequestURI(test[0]);
|
||||
_request.setQueryString(test[1]);
|
||||
_request.getAttributes().clearAttributes();
|
||||
_request.setUri(new HttpURI(test[0]+(test[1]==null?"":("?"+test[1]))));
|
||||
_request.getRequestURI();
|
||||
|
||||
|
||||
String result = _rule.matchAndApply(test[0], _request, _response);
|
||||
assertEquals(t, test[4], result);
|
||||
_rule.applyURI(_request,test[0],result);
|
||||
|
||||
assertEquals(t,test[4], _request.getRequestURI());
|
||||
assertEquals(t,test[5], _request.getQueryString());
|
||||
if (result!=null)
|
||||
{
|
||||
assertEquals(t,test[4], _request.getRequestURI());
|
||||
assertEquals(t,test[5], _request.getQueryString());
|
||||
}
|
||||
|
||||
if (test[5]!=null)
|
||||
{
|
||||
MultiMap<String> params=new MultiMap<String>();
|
||||
UrlEncoded.decodeTo(test[5],params,StringUtil.__UTF8);
|
||||
|
||||
for (String n:params.keySet())
|
||||
assertEquals(params.getString(n),_request.getParameter(n));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,6 +97,7 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
|
|||
container.addRule(_rule);
|
||||
for (String[] test : _tests)
|
||||
{
|
||||
reset();
|
||||
String t=test[0]+"?"+test[1]+">"+test[2]+"|"+test[3];
|
||||
_rule.setRegex(test[2]);
|
||||
_rule.setReplacement(test[3]);
|
||||
|
|
|
@ -819,6 +819,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_responseWrapped=!(response instanceof Response);
|
||||
doSuspend(context,request,response);
|
||||
if (request instanceof HttpServletRequest)
|
||||
{
|
||||
|
|
|
@ -193,7 +193,7 @@ public class CookieCutter
|
|||
continue;
|
||||
|
||||
case ';':
|
||||
case ',':
|
||||
// case ',':
|
||||
if (tokenstart>=0)
|
||||
value = hdr.substring(tokenstart, tokenend+1);
|
||||
else
|
||||
|
@ -239,7 +239,7 @@ public class CookieCutter
|
|||
continue;
|
||||
|
||||
case ';':
|
||||
case ',':
|
||||
// case ',':
|
||||
if (tokenstart>=0)
|
||||
{
|
||||
name = hdr.substring(tokenstart, tokenend+1);
|
||||
|
|
|
@ -21,6 +21,8 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -30,7 +32,8 @@ import org.eclipse.jetty.continuation.Continuation;
|
|||
import org.eclipse.jetty.continuation.ContinuationListener;
|
||||
import org.eclipse.jetty.continuation.ContinuationSupport;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.gzip.GzipResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.CompressedResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.AbstractCompressedStream;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -222,7 +225,7 @@ public class GzipHandler extends HandlerWrapper
|
|||
}
|
||||
}
|
||||
|
||||
final GzipResponseWrapper wrappedResponse = newGzipResponseWrapper(request,response);
|
||||
final CompressedResponseWrapper wrappedResponse = newGzipResponseWrapper(request,response);
|
||||
|
||||
boolean exceptional=true;
|
||||
try
|
||||
|
@ -256,7 +259,7 @@ public class GzipHandler extends HandlerWrapper
|
|||
else if (exceptional && !response.isCommitted())
|
||||
{
|
||||
wrappedResponse.resetBuffer();
|
||||
wrappedResponse.noGzip();
|
||||
wrappedResponse.noCompression();
|
||||
}
|
||||
else
|
||||
wrappedResponse.finish();
|
||||
|
@ -276,14 +279,27 @@ public class GzipHandler extends HandlerWrapper
|
|||
* @param response the response
|
||||
* @return the gzip response wrapper
|
||||
*/
|
||||
protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
protected CompressedResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
return new GzipResponseWrapper(request, response)
|
||||
return new CompressedResponseWrapper(request,response)
|
||||
{
|
||||
{
|
||||
super.setMimeTypes(GzipHandler.this._mimeTypes);
|
||||
super.setBufferSize(GzipHandler.this._bufferSize);
|
||||
super.setMinGzipSize(GzipHandler.this._minGzipSize);
|
||||
super.setMinCompressSize(GzipHandler.this._minGzipSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream("gzip",request,response,contentLength,bufferSize,minCompressSize)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
{
|
||||
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -669,7 +669,7 @@ public class RequestTest
|
|||
"POST / HTTP/1.1\r\n"+
|
||||
"Host: whatever\r\n"+
|
||||
"Cookie: name0=value0; name1 = value1 ; \"\\\"name2\\\"\" = \"\\\"value2\\\"\" \n" +
|
||||
"Cookie: $Version=2; name3=value3=value3;$path=/path;$domain=acme.com;$port=8080, name4=; name5 = ; name6\n" +
|
||||
"Cookie: $Version=2; name3=value3=value3;$path=/path;$domain=acme.com;$port=8080; name4=; name5 = ; name6\n" +
|
||||
"Cookie: name7=value7;\n" +
|
||||
"Connection: close\r\n"+
|
||||
"\r\n");
|
||||
|
@ -694,6 +694,20 @@ public class RequestTest
|
|||
assertEquals("", cookies.get(6).getValue());
|
||||
assertEquals("name7", cookies.get(7).getName());
|
||||
assertEquals("value7", cookies.get(7).getValue());
|
||||
|
||||
cookies.clear();
|
||||
response=_connector.getResponses(
|
||||
"GET /other HTTP/1.1\n"+
|
||||
"Host: whatever\n"+
|
||||
"Other: header\n"+
|
||||
"Cookie: __utmz=14316.133020.1.1.utr=gna.de|ucn=(real)|utd=reral|utct=/games/hen-one,gnt-50-ba-keys:key,2072262.html\n"+
|
||||
"\n"
|
||||
);
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
assertEquals(1,cookies.size());
|
||||
assertEquals("__utmz", cookies.get(0).getName());
|
||||
assertEquals("14316.133020.1.1.utr=gna.de|ucn=(real)|utd=reral|utct=/games/hen-one,gnt-50-ba-keys:key,2072262.html", cookies.get(0).getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -383,7 +383,7 @@ public class ResponseTest
|
|||
{
|
||||
String[][] tests={
|
||||
{"/other/location?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
|
||||
{"/other/location","http://myhost:8888/other/location"},
|
||||
/* {"/other/location","http://myhost:8888/other/location"},
|
||||
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
|
||||
{"location","http://myhost:8888/path/location"},
|
||||
{"./location","http://myhost:8888/path/location"},
|
||||
|
@ -391,7 +391,8 @@ public class ResponseTest
|
|||
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
|
||||
{"l%20cation","http://myhost:8888/path/l%20cation"},
|
||||
{"./l%20cation","http://myhost:8888/path/l%20cation"},
|
||||
{"../l%20cation","http://myhost:8888/l%20cation"},
|
||||
{"../l%20cation","http://myhost:8888/l%20cation"},*/
|
||||
{"../locati%C3%abn","http://myhost:8888/locati%C3%ABn"},
|
||||
};
|
||||
|
||||
for (int i=1;i<tests.length;i++)
|
||||
|
|
|
@ -99,8 +99,6 @@ public class SSLEngineTest
|
|||
connector.setRequestHeaderSize(512);
|
||||
|
||||
server.setConnectors(new Connector[]{connector });
|
||||
server.setHandler(new HelloWorldHandler());
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -109,10 +107,15 @@ public class SSLEngineTest
|
|||
server.stop();
|
||||
server.join();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBigResponse() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
server.setHandler(new HelloWorldHandler());
|
||||
server.start();
|
||||
|
||||
SSLContext ctx=SSLContext.getInstance("TLS");
|
||||
ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
|
||||
|
||||
|
@ -123,7 +126,7 @@ public class SSLEngineTest
|
|||
|
||||
String request =
|
||||
"GET /?dump=102400 HTTP/1.1\r\n"+
|
||||
"Host: localhost:8080\r\n"+
|
||||
"Host: localhost:"+port+"\r\n"+
|
||||
"Connection: close\r\n"+
|
||||
"\r\n";
|
||||
|
||||
|
@ -138,6 +141,10 @@ public class SSLEngineTest
|
|||
@Test
|
||||
public void testRequestJettyHttps() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
server.setHandler(new HelloWorldHandler());
|
||||
server.start();
|
||||
|
||||
final int loops=10;
|
||||
final int numConns=10;
|
||||
|
||||
|
@ -204,8 +211,7 @@ public class SSLEngineTest
|
|||
@Test
|
||||
public void testServletPost() throws Exception
|
||||
{
|
||||
stopServer();
|
||||
|
||||
server.stop();
|
||||
StreamHandler handler = new StreamHandler();
|
||||
server.setHandler(handler);
|
||||
server.start();
|
||||
|
@ -308,6 +314,7 @@ public class SSLEngineTest
|
|||
{
|
||||
ServletOutputStream out=response.getOutputStream();
|
||||
byte[] buf = new byte[Integer.valueOf(request.getParameter("dump"))];
|
||||
// System.err.println("DUMP "+buf.length);
|
||||
for (int i=0;i<buf.length;i++)
|
||||
buf[i]=(byte)('0'+(i%10));
|
||||
out.write(buf);
|
||||
|
|
|
@ -1233,7 +1233,7 @@ public class ServletHandler extends ScopedHandler
|
|||
{
|
||||
if(LOG.isDebugEnabled())
|
||||
LOG.debug("Not Found "+request.getRequestURI());
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
//Override to send an error back, eg with: response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.eclipse.jetty.servlet;
|
|||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
@ -12,6 +13,7 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
|
@ -223,17 +225,20 @@ public class AsyncContextTest
|
|||
}
|
||||
else
|
||||
{
|
||||
boolean wrapped = false;
|
||||
final AsyncContext asyncContext;
|
||||
if (request.getParameter("dispatchRequestResponse") != null)
|
||||
{
|
||||
asyncContext = request.startAsync(request,response);
|
||||
wrapped = true;
|
||||
asyncContext = request.startAsync(request, new Wrapper(response));
|
||||
}
|
||||
else
|
||||
{
|
||||
asyncContext = request.startAsync();
|
||||
}
|
||||
|
||||
new Thread(new DispatchingRunnable(asyncContext)).start();
|
||||
|
||||
new Thread(new DispatchingRunnable(asyncContext, wrapped)).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,14 +246,18 @@ public class AsyncContextTest
|
|||
private class DispatchingRunnable implements Runnable
|
||||
{
|
||||
private AsyncContext asyncContext;
|
||||
private boolean wrapped;
|
||||
|
||||
public DispatchingRunnable(AsyncContext asyncContext)
|
||||
public DispatchingRunnable(AsyncContext asyncContext, boolean wrapped)
|
||||
{
|
||||
this.asyncContext = asyncContext;
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
if (wrapped)
|
||||
assertTrue(asyncContext.getResponse() instanceof Wrapper);
|
||||
asyncContext.dispatch();
|
||||
}
|
||||
}
|
||||
|
@ -347,4 +356,13 @@ public class AsyncContextTest
|
|||
}
|
||||
}
|
||||
|
||||
private class Wrapper extends HttpServletResponseWrapper
|
||||
{
|
||||
public Wrapper (HttpServletResponse response)
|
||||
{
|
||||
super(response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -13,14 +13,12 @@
|
|||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
|
@ -34,14 +32,16 @@ import org.eclipse.jetty.continuation.Continuation;
|
|||
import org.eclipse.jetty.continuation.ContinuationListener;
|
||||
import org.eclipse.jetty.continuation.ContinuationSupport;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.gzip.GzipResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.CompressedResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.AbstractCompressedStream;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** GZIP Filter
|
||||
* This filter will gzip the content of a response iff: <ul>
|
||||
* This filter will gzip or deflate the content of a response if: <ul>
|
||||
* <li>The filter is mapped to a matching path</li>
|
||||
* <li>accept-encoding header is set to either gzip, deflate or a combination of those</li>
|
||||
* <li>The response status code is >=200 and <300
|
||||
* <li>The content length is unknown or more than the <code>minGzipSize</code> initParameter or the minGzipSize is 0(default)</li>
|
||||
* <li>The content-type is in the comma separated list of mimeTypes set in the <code>mimeTypes</code> initParameter or
|
||||
|
@ -50,8 +50,11 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* If both gzip and deflate are specified in the accept-encoding header, then gzip will be used.
|
||||
* </p>
|
||||
* <p>
|
||||
* Compressing the content can greatly improve the network bandwidth usage, but at a cost of memory and
|
||||
* CPU cycles. If this filter is mapped for static content, then use of efficient direct NIO may be
|
||||
* CPU cycles. If this filter is mapped for static content, then use of efficient direct NIO may be
|
||||
* prevented, thus use of the gzip mechanism of the {@link org.eclipse.jetty.servlet.DefaultServlet} is
|
||||
* advised instead.
|
||||
* </p>
|
||||
|
@ -64,6 +67,8 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class GzipFilter extends UserAgentFilter
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(GzipFilter.class);
|
||||
public final static String GZIP="gzip";
|
||||
public final static String DEFLATE="deflate";
|
||||
|
||||
protected Set<String> _mimeTypes;
|
||||
protected int _bufferSize=8192;
|
||||
|
@ -144,7 +149,7 @@ public class GzipFilter extends UserAgentFilter
|
|||
public void destroy()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
|
||||
|
@ -156,9 +161,8 @@ public class GzipFilter extends UserAgentFilter
|
|||
HttpServletRequest request=(HttpServletRequest)req;
|
||||
HttpServletResponse response=(HttpServletResponse)res;
|
||||
|
||||
String ae = request.getHeader("accept-encoding");
|
||||
if (ae != null && ae.indexOf("gzip")>=0 && !response.containsHeader("Content-Encoding")
|
||||
&& !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod()))
|
||||
String compressionType = selectCompression(request.getHeader("accept-encoding"));
|
||||
if (compressionType!=null && !response.containsHeader("Content-Encoding") && !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod()))
|
||||
{
|
||||
String ua = getUserAgent(request);
|
||||
if (isExcludedAgent(ua))
|
||||
|
@ -172,8 +176,8 @@ public class GzipFilter extends UserAgentFilter
|
|||
super.doFilter(request,response,chain);
|
||||
return;
|
||||
}
|
||||
|
||||
final GzipResponseWrapper wrappedResponse=newGzipResponseWrapper(request,response);
|
||||
|
||||
CompressedResponseWrapper wrappedResponse = createWrappedResponse(request,response,compressionType);
|
||||
|
||||
boolean exceptional=true;
|
||||
try
|
||||
|
@ -186,28 +190,12 @@ public class GzipFilter extends UserAgentFilter
|
|||
Continuation continuation = ContinuationSupport.getContinuation(request);
|
||||
if (continuation.isSuspended() && continuation.isResponseWrapped())
|
||||
{
|
||||
continuation.addContinuationListener(new ContinuationListener()
|
||||
{
|
||||
public void onComplete(Continuation continuation)
|
||||
{
|
||||
try
|
||||
{
|
||||
wrappedResponse.finish();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTimeout(Continuation continuation)
|
||||
{}
|
||||
});
|
||||
continuation.addContinuationListener(new ContinuationListenerWaitingForWrappedResponseToFinish(wrappedResponse));
|
||||
}
|
||||
else if (exceptional && !response.isCommitted())
|
||||
{
|
||||
wrappedResponse.resetBuffer();
|
||||
wrappedResponse.noGzip();
|
||||
wrappedResponse.noCompression();
|
||||
}
|
||||
else
|
||||
wrappedResponse.finish();
|
||||
|
@ -218,7 +206,102 @@ public class GzipFilter extends UserAgentFilter
|
|||
super.doFilter(request,response,chain);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String selectCompression(String encodingHeader)
|
||||
{
|
||||
// TODO, this could be a little more robust.
|
||||
// prefer gzip over deflate
|
||||
if (encodingHeader!=null)
|
||||
{
|
||||
if (encodingHeader.toLowerCase().contains(GZIP))
|
||||
return GZIP;
|
||||
else if (encodingHeader.toLowerCase().contains(DEFLATE))
|
||||
return DEFLATE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
|
||||
{
|
||||
CompressedResponseWrapper wrappedResponse = null;
|
||||
if (compressionType.equals(GZIP))
|
||||
{
|
||||
wrappedResponse = new CompressedResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
{
|
||||
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (compressionType.equals(DEFLATE))
|
||||
{
|
||||
wrappedResponse = new CompressedResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
{
|
||||
return new DeflaterOutputStream(_response.getOutputStream());
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException(compressionType + " not supported");
|
||||
}
|
||||
configureWrappedResponse(wrappedResponse);
|
||||
return wrappedResponse;
|
||||
}
|
||||
|
||||
protected void configureWrappedResponse(CompressedResponseWrapper wrappedResponse)
|
||||
{
|
||||
wrappedResponse.setMimeTypes(_mimeTypes);
|
||||
wrappedResponse.setBufferSize(_bufferSize);
|
||||
wrappedResponse.setMinCompressSize(_minGzipSize);
|
||||
}
|
||||
|
||||
private class ContinuationListenerWaitingForWrappedResponseToFinish implements ContinuationListener{
|
||||
|
||||
private CompressedResponseWrapper wrappedResponse;
|
||||
|
||||
public ContinuationListenerWaitingForWrappedResponseToFinish(CompressedResponseWrapper wrappedResponse)
|
||||
{
|
||||
this.wrappedResponse = wrappedResponse;
|
||||
}
|
||||
|
||||
public void onComplete(Continuation continuation)
|
||||
{
|
||||
try
|
||||
{
|
||||
wrappedResponse.finish();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTimeout(Continuation continuation)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the UserAgent is excluded
|
||||
*
|
||||
|
@ -285,42 +368,4 @@ public class GzipFilter extends UserAgentFilter
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows derived implementations to replace ResponseWrapper implementation.
|
||||
*
|
||||
* @param request the request
|
||||
* @param response the response
|
||||
* @return the gzip response wrapper
|
||||
*/
|
||||
protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
return new GzipResponseWrapper(request, response)
|
||||
{
|
||||
{
|
||||
setMimeTypes(GzipFilter.this._mimeTypes);
|
||||
setBufferSize(GzipFilter.this._bufferSize);
|
||||
setMinGzipSize(GzipFilter.this._minGzipSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
return GzipFilter.this.newWriter(out,encoding);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows derived implementations to replace PrintWriter implementation.
|
||||
*
|
||||
* @param out the out
|
||||
* @param encoding the encoding
|
||||
* @return the prints the writer
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,18 +18,18 @@ import java.io.OutputStream;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.gzip.GzipResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.GzipStream;
|
||||
import org.eclipse.jetty.http.gzip.CompressedResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.AbstractCompressedStream;
|
||||
import org.eclipse.jetty.io.UncheckedPrintWriter;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Includable GZip Filter.
|
||||
* This extension to the {@link GzipFilter} that uses Jetty features to allow
|
||||
|
@ -56,61 +56,82 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
_uncheckedPrintWriter=Boolean.valueOf(tmp).booleanValue();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlets.GzipFilter#createWrappedResponse(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
|
||||
{
|
||||
return new IncludableResponseWrapper(request,response);
|
||||
CompressedResponseWrapper wrappedResponse = null;
|
||||
if (compressionType.equals(GZIP))
|
||||
{
|
||||
wrappedResponse = new IncludableResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
{
|
||||
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (compressionType.equals(DEFLATE))
|
||||
{
|
||||
wrappedResponse = new IncludableResponseWrapper(request,response)
|
||||
{
|
||||
@Override
|
||||
protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException
|
||||
{
|
||||
return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize)
|
||||
{
|
||||
@Override
|
||||
protected DeflaterOutputStream createStream() throws IOException
|
||||
{
|
||||
return new DeflaterOutputStream(_response.getOutputStream());
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException(compressionType + " not supported");
|
||||
}
|
||||
configureWrappedResponse(wrappedResponse);
|
||||
return wrappedResponse;
|
||||
}
|
||||
|
||||
public class IncludableResponseWrapper extends GzipResponseWrapper
|
||||
|
||||
|
||||
// Extend CompressedResponseWrapper to be able to set headers during include and to create unchecked printwriters
|
||||
private abstract class IncludableResponseWrapper extends CompressedResponseWrapper
|
||||
{
|
||||
public IncludableResponseWrapper(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
super(request,response);
|
||||
|
||||
super.setMimeTypes(IncludableGzipFilter.this._mimeTypes);
|
||||
super.setBufferSize(IncludableGzipFilter.this._bufferSize);
|
||||
super.setMinGzipSize(IncludableGzipFilter.this._minGzipSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
|
||||
public void setHeader(String name,String value)
|
||||
{
|
||||
return new IncludableGzipStream(request,response,contentLength,bufferSize,minGzipSize);
|
||||
super.setHeader(name,value);
|
||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||
if (!response.containsHeader(name))
|
||||
response.setHeader("org.eclipse.jetty.server.include."+name,value);;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
|
||||
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
return IncludableGzipFilter.this.newWriter(out,encoding);
|
||||
}
|
||||
}
|
||||
|
||||
public class IncludableGzipStream extends GzipStream
|
||||
{
|
||||
public IncludableGzipStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize)
|
||||
throws IOException
|
||||
{
|
||||
super(request,response,contentLength,bufferSize,minGzipSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean setContentEncodingGzip()
|
||||
{
|
||||
if (_request.getAttribute("javax.servlet.include.request_uri")!=null)
|
||||
_response.setHeader("org.eclipse.jetty.server.include.Content-Encoding", "gzip");
|
||||
else
|
||||
_response.setHeader("Content-Encoding", "gzip");
|
||||
|
||||
return _response.containsHeader("Content-Encoding");
|
||||
if (_uncheckedPrintWriter)
|
||||
return encoding == null?new UncheckedPrintWriter(out):new UncheckedPrintWriter(new OutputStreamWriter(out,encoding));
|
||||
return super.newWriter(out,encoding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
if (_uncheckedPrintWriter)
|
||||
return encoding==null?new UncheckedPrintWriter(out):new UncheckedPrintWriter(new OutputStreamWriter(out,encoding));
|
||||
return super.newWriter(out,encoding);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.List;
|
|||
import javax.servlet.Servlet;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.gzip.GzipResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.CompressedResponseWrapper;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlets.gzip.GzipTester;
|
||||
import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite;
|
||||
|
@ -48,32 +48,42 @@ public class GzipFilterContentLengthTest
|
|||
{
|
||||
return Arrays.asList(new Object[][]
|
||||
{
|
||||
{ TestServletLengthStreamTypeWrite.class },
|
||||
{ TestServletLengthTypeStreamWrite.class },
|
||||
{ TestServletStreamLengthTypeWrite.class },
|
||||
{ TestServletStreamTypeLengthWrite.class },
|
||||
{ TestServletTypeLengthStreamWrite.class },
|
||||
{ TestServletTypeStreamLengthWrite.class } });
|
||||
{ TestServletLengthStreamTypeWrite.class, GzipFilter.GZIP },
|
||||
{ TestServletLengthTypeStreamWrite.class, GzipFilter.GZIP },
|
||||
{ TestServletStreamLengthTypeWrite.class, GzipFilter.GZIP },
|
||||
{ TestServletStreamTypeLengthWrite.class, GzipFilter.GZIP },
|
||||
{ TestServletTypeLengthStreamWrite.class, GzipFilter.GZIP },
|
||||
{ TestServletTypeStreamLengthWrite.class, GzipFilter.GZIP },
|
||||
{ TestServletLengthStreamTypeWrite.class, GzipFilter.DEFLATE },
|
||||
{ TestServletLengthTypeStreamWrite.class, GzipFilter.DEFLATE },
|
||||
{ TestServletStreamLengthTypeWrite.class, GzipFilter.DEFLATE },
|
||||
{ TestServletStreamTypeLengthWrite.class, GzipFilter.DEFLATE },
|
||||
{ TestServletTypeLengthStreamWrite.class, GzipFilter.DEFLATE },
|
||||
{ TestServletTypeStreamLengthWrite.class, GzipFilter.DEFLATE }
|
||||
});
|
||||
}
|
||||
|
||||
private static final int LARGE = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 8;
|
||||
private static final int MEDIUM = GzipResponseWrapper.DEFAULT_BUFFER_SIZE;
|
||||
private static final int SMALL = GzipResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
|
||||
private static final int TINY = GzipResponseWrapper.DEFAULT_MIN_GZIP_SIZE / 2;
|
||||
private static final int LARGE = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 8;
|
||||
private static final int MEDIUM = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE;
|
||||
private static final int SMALL = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
|
||||
private static final int TINY = CompressedResponseWrapper.DEFAULT_MIN_COMPRESS_SIZE/ 2;
|
||||
|
||||
private String compressionType;
|
||||
|
||||
public GzipFilterContentLengthTest(Class<? extends Servlet> testServlet, String compressionType)
|
||||
{
|
||||
this.testServlet = testServlet;
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestingDir testingdir = new TestingDir();
|
||||
|
||||
private Class<? extends Servlet> testServlet;
|
||||
|
||||
public GzipFilterContentLengthTest(Class<? extends Servlet> testServlet)
|
||||
{
|
||||
this.testServlet = testServlet;
|
||||
}
|
||||
|
||||
private void assertIsGzipCompressed(String filename, int filesize) throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
File testfile = tester.prepareServerFile(testServlet.getSimpleName() + "-" + filename,filesize);
|
||||
|
||||
|
@ -93,7 +103,7 @@ public class GzipFilterContentLengthTest
|
|||
|
||||
private void assertIsNotGzipCompressed(String filename, int filesize) throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
File testfile = tester.prepareServerFile(testServlet.getSimpleName() + "-" + filename,filesize);
|
||||
|
||||
|
|
|
@ -31,22 +31,41 @@ public class GzipFilterDefaultNoRecompressTest
|
|||
return Arrays.asList(new Object[][]
|
||||
{
|
||||
// Some already compressed files
|
||||
{ "test_quotes.gz", "application/gzip" },
|
||||
{ "test_quotes.bz2", "application/bzip2" },
|
||||
{ "test_quotes.zip", "application/zip" },
|
||||
{ "test_quotes.rar", "application/octet-stream" },
|
||||
{ "test_quotes.gz", "application/gzip", GzipFilter.GZIP },
|
||||
{ "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP },
|
||||
{ "test_quotes.zip", "application/zip", GzipFilter.GZIP },
|
||||
{ "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP },
|
||||
// Some images (common first)
|
||||
{ "jetty_logo.png", "image/png" },
|
||||
{ "jetty_logo.gif", "image/gif" },
|
||||
{ "jetty_logo.jpeg", "image/jpeg" },
|
||||
{ "jetty_logo.jpg", "image/jpeg" },
|
||||
{ "jetty_logo.png", "image/png", GzipFilter.GZIP },
|
||||
{ "jetty_logo.gif", "image/gif", GzipFilter.GZIP },
|
||||
{ "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP },
|
||||
{ "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP },
|
||||
// Lesser encountered images (usually found being requested from non-browser clients)
|
||||
{ "jetty_logo.bmp", "image/bmp" },
|
||||
{ "jetty_logo.tga", "application/tga" },
|
||||
{ "jetty_logo.tif", "image/tiff" },
|
||||
{ "jetty_logo.tiff", "image/tiff" },
|
||||
{ "jetty_logo.xcf", "image/xcf" },
|
||||
{ "jetty_logo.jp2", "image/jpeg2000" } });
|
||||
{ "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP },
|
||||
{ "jetty_logo.tga", "application/tga", GzipFilter.GZIP },
|
||||
{ "jetty_logo.tif", "image/tiff", GzipFilter.GZIP },
|
||||
{ "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP },
|
||||
{ "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP },
|
||||
{ "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP },
|
||||
|
||||
// Same tests again for deflate
|
||||
// Some already compressed files
|
||||
{ "test_quotes.gz", "application/gzip", GzipFilter.DEFLATE },
|
||||
{ "test_quotes.bz2", "application/bzip2", GzipFilter.DEFLATE },
|
||||
{ "test_quotes.zip", "application/zip", GzipFilter.DEFLATE },
|
||||
{ "test_quotes.rar", "application/octet-stream", GzipFilter.DEFLATE },
|
||||
// Some images (common first)
|
||||
{ "jetty_logo.png", "image/png", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.gif", "image/gif", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.jpeg", "image/jpeg", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.jpg", "image/jpeg", GzipFilter.DEFLATE },
|
||||
// Lesser encountered images (usually found being requested from non-browser clients)
|
||||
{ "jetty_logo.bmp", "image/bmp", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.tga", "application/tga", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.tif", "image/tiff", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.tiff", "image/tiff", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.xcf", "image/xcf", GzipFilter.DEFLATE },
|
||||
{ "jetty_logo.jp2", "image/jpeg2000", GzipFilter.DEFLATE } });
|
||||
}
|
||||
|
||||
@Rule
|
||||
|
@ -54,17 +73,19 @@ public class GzipFilterDefaultNoRecompressTest
|
|||
|
||||
private String alreadyCompressedFilename;
|
||||
private String expectedContentType;
|
||||
private String compressionType;
|
||||
|
||||
public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType)
|
||||
public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType, String compressionType)
|
||||
{
|
||||
this.alreadyCompressedFilename = testFilename;
|
||||
this.expectedContentType = expectedContentType;
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotGzipFiltered_Default_AlreadyCompressed() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
copyTestFileToServer(alreadyCompressedFilename);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
@ -8,19 +10,41 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.gzip.GzipResponseWrapper;
|
||||
import org.eclipse.jetty.http.gzip.CompressedResponseWrapper;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlets.gzip.GzipTester;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Test the GzipFilter support built into the {@link DefaultServlet}
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class GzipFilterDefaultTest
|
||||
{
|
||||
@Parameters
|
||||
public static Collection<String[]> data()
|
||||
{
|
||||
String[][] data = new String[][]
|
||||
{
|
||||
{ GzipFilter.GZIP },
|
||||
{ GzipFilter.DEFLATE }
|
||||
};
|
||||
|
||||
return Arrays.asList(data);
|
||||
}
|
||||
|
||||
private String compressionType;
|
||||
|
||||
public GzipFilterDefaultTest(String compressionType)
|
||||
{
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
|
||||
public static class HttpStatusServlet extends HttpServlet
|
||||
|
@ -52,10 +76,10 @@ public class GzipFilterDefaultTest
|
|||
@Test
|
||||
public void testIsGzipCompressedTiny() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
// Test content that is smaller than the buffer.
|
||||
int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
|
||||
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4;
|
||||
tester.prepareServerFile("file.txt",filesize);
|
||||
|
||||
FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
|
||||
|
@ -75,10 +99,10 @@ public class GzipFilterDefaultTest
|
|||
@Test
|
||||
public void testIsGzipCompressedLarge() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
// Test content that is smaller than the buffer.
|
||||
int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
|
||||
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
|
||||
tester.prepareServerFile("file.txt",filesize);
|
||||
|
||||
FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
|
||||
|
@ -98,10 +122,10 @@ public class GzipFilterDefaultTest
|
|||
@Test
|
||||
public void testIsNotGzipCompressed() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
// Test content that is smaller than the buffer.
|
||||
int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
|
||||
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
|
||||
tester.prepareServerFile("file.mp3",filesize);
|
||||
|
||||
FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
|
||||
|
@ -121,7 +145,7 @@ public class GzipFilterDefaultTest
|
|||
@Test
|
||||
public void testIsNotGzipCompressedHttpStatus() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
// Test error code 204
|
||||
FilterHolder holder = tester.setContentServlet(HttpStatusServlet.class);
|
||||
|
@ -142,13 +166,13 @@ public class GzipFilterDefaultTest
|
|||
@Test
|
||||
public void testUserAgentExclusion() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testingdir);
|
||||
GzipTester tester = new GzipTester(testingdir, compressionType);
|
||||
|
||||
FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
|
||||
holder.setInitParameter("excludedAgents", "foo");
|
||||
tester.setUserAgent("foo");
|
||||
|
||||
int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
|
||||
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
|
||||
tester.prepareServerFile("file.txt",filesize);
|
||||
|
||||
try
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -25,21 +30,46 @@ import org.eclipse.jetty.toolchain.test.IO;
|
|||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Test the effects of Gzip filtering when in the context of HTTP/1.1 Pipelining.
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class GzipWithPipeliningTest
|
||||
{
|
||||
@Parameters
|
||||
public static Collection<String[]> data()
|
||||
{
|
||||
// Test different Content-Encoding header combinations. So implicitly testing that gzip is preferred oder deflate
|
||||
String[][] data = new String[][]
|
||||
{
|
||||
{ GzipFilter.GZIP },
|
||||
{ GzipFilter.DEFLATE + ", " + GzipFilter.GZIP },
|
||||
{ GzipFilter.GZIP + ", " + GzipFilter.DEFLATE },
|
||||
{ GzipFilter.DEFLATE }
|
||||
};
|
||||
|
||||
return Arrays.asList(data);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestingDir testingdir = new TestingDir();
|
||||
|
||||
private Server server;
|
||||
private URI serverUri;
|
||||
private String encodingHeader;
|
||||
|
||||
|
||||
public GzipWithPipeliningTest(String encodingHeader)
|
||||
{
|
||||
this.encodingHeader = encodingHeader;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
|
@ -86,7 +116,7 @@ public class GzipWithPipeliningTest
|
|||
testingdir.ensureEmpty();
|
||||
File outputDir = testingdir.getDir();
|
||||
|
||||
PipelineHelper client = new PipelineHelper(serverUri);
|
||||
PipelineHelper client = new PipelineHelper(serverUri, encodingHeader);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -95,7 +125,7 @@ public class GzipWithPipeliningTest
|
|||
|
||||
// Size of content, as it exists on disk, without gzip compression.
|
||||
long rawsize = txtFile.length() + pngFile.length();
|
||||
Assert.assertThat("Ensure that we have sufficient file size to trigger chunking",rawsize,greaterThan(300000L));
|
||||
assertThat("Ensure that we have sufficient file size to trigger chunking",rawsize,greaterThan(300000L));
|
||||
|
||||
String respHeader;
|
||||
|
||||
|
@ -106,8 +136,9 @@ public class GzipWithPipeliningTest
|
|||
|
||||
respHeader = client.readResponseHeader();
|
||||
System.out.println("Response Header #1 --\n" + respHeader);
|
||||
Assert.assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: gzip\r\n"));
|
||||
Assert.assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n"));
|
||||
String expectedEncodingHeader = encodingHeader.equals(GzipFilter.DEFLATE) ? GzipFilter.DEFLATE : GzipFilter.GZIP;
|
||||
assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: " + expectedEncodingHeader + "\r\n"));
|
||||
assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n"));
|
||||
|
||||
// Raw output / gzipped, writted to disk (checked for sha1sum later)
|
||||
File rawOutputFile = new File(outputDir, "response-1.gz");
|
||||
|
@ -118,7 +149,7 @@ public class GzipWithPipeliningTest
|
|||
|
||||
// Read only 20% - intentionally a partial read.
|
||||
System.out.println("Attempting to read partial content ...");
|
||||
int readBytes = client.readBody(rawOutputStream,(int)((float)chunkSize * 0.20f));
|
||||
int readBytes = client.readBody(rawOutputStream,(int)(chunkSize * 0.20f));
|
||||
System.out.printf("Read %,d bytes%n",readBytes);
|
||||
|
||||
// Issue another request
|
||||
|
@ -133,14 +164,14 @@ public class GzipWithPipeliningTest
|
|||
readBytes = client.readBody(rawOutputStream,(int)chunkSize);
|
||||
System.out.printf("Read %,d bytes%n",readBytes);
|
||||
line = client.readLine();
|
||||
Assert.assertThat("Chunk delim should be an empty line with CR+LF",line,is(""));
|
||||
assertThat("Chunk delim should be an empty line with CR+LF",line,is(""));
|
||||
chunkSize = client.readChunkSize();
|
||||
System.out.printf("Next Chunk: (0x%X) %,d bytes%n",chunkSize,chunkSize);
|
||||
}
|
||||
|
||||
// Inter-pipeline delim
|
||||
line = client.readLine();
|
||||
Assert.assertThat("Inter-pipeline delim should be an empty line with CR+LF",line,is(""));
|
||||
assertThat("Inter-pipeline delim should be an empty line with CR+LF",line,is(""));
|
||||
|
||||
// Sha1tracking for 1st Request
|
||||
MessageDigest digestTxt = MessageDigest.getInstance("SHA1");
|
||||
|
@ -149,14 +180,23 @@ public class GzipWithPipeliningTest
|
|||
// Decompress 1st request and calculate sha1sum
|
||||
IO.close(rawOutputStream);
|
||||
FileInputStream rawInputStream = new FileInputStream(rawOutputFile);
|
||||
GZIPInputStream ungzipStream = new GZIPInputStream(rawInputStream);
|
||||
IO.copy(ungzipStream, digesterTxt);
|
||||
InputStream uncompressedStream = null;
|
||||
if (GzipFilter.DEFLATE.equals(encodingHeader))
|
||||
{
|
||||
uncompressedStream = new InflaterInputStream(rawInputStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
uncompressedStream = new GZIPInputStream(rawInputStream);
|
||||
}
|
||||
|
||||
IO.copy(uncompressedStream, digesterTxt);
|
||||
|
||||
// Read 2nd request http response header
|
||||
respHeader = client.readResponseHeader();
|
||||
System.out.println("Response Header #2 --\n" + respHeader);
|
||||
Assert.assertThat("Content-Encoding should NOT be gzipped",respHeader,not(containsString("Content-Encoding: gzip\r\n")));
|
||||
Assert.assertThat("Transfer-Encoding should NOT be chunked",respHeader,not(containsString("Transfer-Encoding: chunked\r\n")));
|
||||
assertThat("Content-Encoding should NOT be gzipped",respHeader,not(containsString("Content-Encoding: gzip\r\n")));
|
||||
assertThat("Transfer-Encoding should NOT be chunked",respHeader,not(containsString("Transfer-Encoding: chunked\r\n")));
|
||||
|
||||
// Sha1tracking for 2nd Request
|
||||
MessageDigest digestImg = MessageDigest.getInstance("SHA1");
|
||||
|
@ -164,7 +204,7 @@ public class GzipWithPipeliningTest
|
|||
|
||||
// Read 2nd request body
|
||||
int contentLength = client.getContentLength(respHeader);
|
||||
Assert.assertThat("Image Content Length",(long)contentLength,is(pngFile.length()));
|
||||
assertThat("Image Content Length",(long)contentLength,is(pngFile.length()));
|
||||
client.readBody(digesterImg,contentLength);
|
||||
|
||||
// Validate checksums
|
||||
|
@ -183,7 +223,7 @@ public class GzipWithPipeliningTest
|
|||
{
|
||||
String expectedSha1 = loadSha1sum(testResourceFile + ".sha1");
|
||||
String actualSha1 = Hex.asHex(digest.digest());
|
||||
Assert.assertEquals(testResourceFile + " / SHA1Sum of content",expectedSha1,actualSha1);
|
||||
assertEquals(testResourceFile + " / SHA1Sum of content",expectedSha1,actualSha1);
|
||||
}
|
||||
|
||||
private String loadSha1sum(String testResourceSha1Sum) throws IOException
|
||||
|
@ -192,7 +232,7 @@ public class GzipWithPipeliningTest
|
|||
String contents = IO.readToString(sha1File);
|
||||
Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
|
||||
Matcher mat = pat.matcher(contents);
|
||||
Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
|
||||
assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
|
||||
return mat.group();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.servlets;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
|
@ -21,6 +24,9 @@ import org.eclipse.jetty.servlets.gzip.TestMinGzipSizeServlet;
|
|||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Perform specific tests on the IncludableGzipFilter's ability to manage
|
||||
|
@ -28,17 +34,36 @@ import org.junit.Test;
|
|||
*
|
||||
* @see <a href="Eclipse Bug 366106">http://bugs.eclipse.org/366106</a>
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class IncludableGzipFilterMinSizeTest
|
||||
{
|
||||
@Parameters
|
||||
public static Collection<String[]> data()
|
||||
{
|
||||
String[][] data = new String[][]
|
||||
{
|
||||
{ GzipFilter.GZIP },
|
||||
{ GzipFilter.DEFLATE }
|
||||
};
|
||||
|
||||
return Arrays.asList(data);
|
||||
}
|
||||
|
||||
public IncludableGzipFilterMinSizeTest(String compressionType)
|
||||
{
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestingDir testdir = new TestingDir();
|
||||
|
||||
private String compressionType;
|
||||
private Class<? extends Servlet> testServlet = TestMinGzipSizeServlet.class;
|
||||
|
||||
@Test
|
||||
public void testUnderMinSize() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testdir);
|
||||
GzipTester tester = new GzipTester(testdir, compressionType);
|
||||
// Use IncludableGzipFilter
|
||||
tester.setGzipFilterClass(IncludableGzipFilter.class);
|
||||
|
||||
|
@ -64,7 +89,7 @@ public class IncludableGzipFilterMinSizeTest
|
|||
@Test
|
||||
public void testOverMinSize() throws Exception
|
||||
{
|
||||
GzipTester tester = new GzipTester(testdir);
|
||||
GzipTester tester = new GzipTester(testdir, compressionType);
|
||||
// Use IncludableGzipFilter
|
||||
tester.setGzipFilterClass(IncludableGzipFilter.class);
|
||||
|
||||
|
|
|
@ -22,7 +22,10 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -36,9 +39,28 @@ import org.junit.After;
|
|||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class IncludableGzipFilterTest
|
||||
{
|
||||
@Parameters
|
||||
public static Collection<String[]> data()
|
||||
{
|
||||
String[][] data = new String[][]
|
||||
{
|
||||
{ GzipFilter.GZIP },
|
||||
{ GzipFilter.DEFLATE }
|
||||
};
|
||||
|
||||
return Arrays.asList(data);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestingDir testdir = new TestingDir();
|
||||
|
||||
private static String __content =
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+
|
||||
"Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+
|
||||
|
@ -53,11 +75,14 @@ public class IncludableGzipFilterTest
|
|||
"Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+
|
||||
"et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
@Rule
|
||||
public TestingDir testdir = new TestingDir();
|
||||
|
||||
private ServletTester tester;
|
||||
|
||||
private String compressionType;
|
||||
|
||||
public IncludableGzipFilterTest(String compressionType)
|
||||
{
|
||||
this.compressionType = compressionType;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
|
@ -95,7 +120,7 @@ public class IncludableGzipFilterTest
|
|||
request.setMethod("GET");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setHeader("accept-encoding","gzip");
|
||||
request.setHeader("accept-encoding", compressionType);
|
||||
request.setURI("/context/file.txt");
|
||||
|
||||
ByteArrayBuffer reqsBuff = new ByteArrayBuffer(request.generate().getBytes());
|
||||
|
@ -103,10 +128,19 @@ public class IncludableGzipFilterTest
|
|||
response.parse(respBuff.asArray());
|
||||
|
||||
assertTrue(response.getMethod()==null);
|
||||
assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase("gzip"));
|
||||
assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase(compressionType));
|
||||
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
|
||||
|
||||
InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes()));
|
||||
InputStream testIn = null;
|
||||
ByteArrayInputStream compressedResponseStream = new ByteArrayInputStream(response.getContentBytes());
|
||||
if (compressionType.equals(GzipFilter.GZIP))
|
||||
{
|
||||
testIn = new GZIPInputStream(compressedResponseStream);
|
||||
}
|
||||
else if (compressionType.equals(GzipFilter.DEFLATE))
|
||||
{
|
||||
testIn = new InflaterInputStream(compressedResponseStream);
|
||||
}
|
||||
ByteArrayOutputStream testOut = new ByteArrayOutputStream();
|
||||
IO.copy(testIn,testOut);
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ public class PipelineHelper
|
|||
private Socket socket;
|
||||
private OutputStream outputStream;
|
||||
private InputStream inputStream;
|
||||
private String encodingHeader;
|
||||
|
||||
public PipelineHelper(URI uri)
|
||||
public PipelineHelper(URI uri, String encodingHeader)
|
||||
{
|
||||
if (LOG instanceof StdErrLog)
|
||||
{
|
||||
|
@ -34,6 +35,7 @@ public class PipelineHelper
|
|||
}
|
||||
this.uri = uri;
|
||||
this.endpoint = new InetSocketAddress(uri.getHost(),uri.getPort());
|
||||
this.encodingHeader = encodingHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,7 +78,7 @@ public class PipelineHelper
|
|||
req.append("Accept-Language: en-us\r\n");
|
||||
if (acceptGzipped)
|
||||
{
|
||||
req.append("Accept-Encoding: gzip, deflate\r\n");
|
||||
req.append("Accept-Encoding: " + encodingHeader + "\r\n");
|
||||
}
|
||||
req.append("Cookie: JSESSIONID=spqx8v8szylt1336t96vc6mw0\r\n");
|
||||
if ( close )
|
||||
|
@ -134,7 +136,7 @@ public class PipelineHelper
|
|||
while (!(foundCR && foundLF))
|
||||
{
|
||||
b = inputStream.read();
|
||||
Assert.assertThat("Should not have hit EOL (yet) during chunk size read",(int)b,not(-1));
|
||||
Assert.assertThat("Should not have hit EOL (yet) during chunk size read",b,not(-1));
|
||||
if (b == 0x0D)
|
||||
{
|
||||
foundCR = true;
|
||||
|
@ -163,7 +165,7 @@ public class PipelineHelper
|
|||
while (!(foundCR && foundLF))
|
||||
{
|
||||
b = inputStream.read();
|
||||
Assert.assertThat("Should not have hit EOL (yet) during chunk size read",(int)b,not(-1));
|
||||
Assert.assertThat("Should not have hit EOL (yet) during chunk size read",b,not(-1));
|
||||
if (b == 0x0D)
|
||||
{
|
||||
foundCR = true;
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
package org.eclipse.jetty.servlets.gzip;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
|
@ -12,6 +20,8 @@ import java.util.Enumeration;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -26,12 +36,6 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.junit.Assert;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class GzipTester
|
||||
{
|
||||
private Class<? extends GzipFilter> gzipFilterClass = GzipFilter.class;
|
||||
|
@ -39,10 +43,12 @@ public class GzipTester
|
|||
private String userAgent = null;
|
||||
private ServletTester servletTester;
|
||||
private TestingDir testdir;
|
||||
private String compressionType;
|
||||
|
||||
public GzipTester(TestingDir testingdir)
|
||||
public GzipTester(TestingDir testingdir, String compressionType)
|
||||
{
|
||||
this.testdir = testingdir;
|
||||
this.compressionType = compressionType;
|
||||
// Make sure we start with a clean testing directory.
|
||||
// DOES NOT WORK IN WINDOWS - this.testdir.ensureEmpty();
|
||||
}
|
||||
|
@ -61,7 +67,7 @@ public class GzipTester
|
|||
request.setMethod("GET");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setHeader("Accept-Encoding","gzip");
|
||||
request.setHeader("Accept-Encoding",compressionType);
|
||||
if (this.userAgent != null)
|
||||
request.setHeader("User-Agent", this.userAgent);
|
||||
request.setURI("/context/" + requestedFilename);
|
||||
|
@ -76,7 +82,7 @@ public class GzipTester
|
|||
Assert.assertThat("Response.method",response.getMethod(),nullValue());
|
||||
Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK));
|
||||
Assert.assertThat("Response.header[Content-Length]",response.getHeader("Content-Length"),notNullValue());
|
||||
Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString("gzip"));
|
||||
Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType));
|
||||
|
||||
// Assert that the decompressed contents are what we expect.
|
||||
File serverFile = testdir.getFile(serverFilename);
|
||||
|
@ -89,12 +95,19 @@ public class GzipTester
|
|||
try
|
||||
{
|
||||
bais = new ByteArrayInputStream(response.getContentBytes());
|
||||
in = new GZIPInputStream(bais);
|
||||
if (compressionType.equals(GzipFilter.GZIP))
|
||||
{
|
||||
in = new GZIPInputStream(bais);
|
||||
}
|
||||
else if (compressionType.equals(GzipFilter.DEFLATE))
|
||||
{
|
||||
in = new InflaterInputStream(bais);
|
||||
}
|
||||
out = new ByteArrayOutputStream();
|
||||
IO.copy(in,out);
|
||||
|
||||
actual = out.toString(encoding);
|
||||
Assert.assertEquals("Uncompressed contents",expected,actual);
|
||||
assertThat("Uncompressed contents",actual,equalTo(expected));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -128,7 +141,7 @@ public class GzipTester
|
|||
request.setMethod("GET");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setHeader("Accept-Encoding","gzip");
|
||||
request.setHeader("Accept-Encoding",compressionType);
|
||||
if (this.userAgent != null)
|
||||
request.setHeader("User-Agent", this.userAgent);
|
||||
request.setURI("/context/" + requestedFilename);
|
||||
|
@ -215,7 +228,7 @@ public class GzipTester
|
|||
request.setMethod("GET");
|
||||
request.setVersion("HTTP/1.0");
|
||||
request.setHeader("Host","tester");
|
||||
request.setHeader("Accept-Encoding","gzip");
|
||||
request.setHeader("Accept-Encoding",compressionType);
|
||||
if (this.userAgent != null)
|
||||
request.setHeader("User-Agent", this.userAgent);
|
||||
if (filename == null)
|
||||
|
@ -238,7 +251,7 @@ public class GzipTester
|
|||
int serverLength = Integer.parseInt(response.getHeader("Content-Length"));
|
||||
Assert.assertThat("Response.header[Content-Length]",serverLength,is(expectedFilesize));
|
||||
}
|
||||
Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),not(containsString("gzip")));
|
||||
Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),not(containsString(compressionType)));
|
||||
|
||||
// Assert that the contents are what we expect.
|
||||
if (filename != null)
|
||||
|
|
|
@ -12,13 +12,9 @@
|
|||
<packaging>pom</packaging>
|
||||
<name>Jetty :: SPDY :: Parent</name>
|
||||
|
||||
<properties>
|
||||
<!--
|
||||
npn version only needs to change when there are changes in that binary, not
|
||||
with each and every release.
|
||||
-->
|
||||
<npn.version>7.6.2.v20120308</npn.version>
|
||||
</properties>
|
||||
<properties>
|
||||
<npn.version>1.0.0.v20120402</npn.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>spdy-core</module>
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
|
|
@ -68,8 +68,9 @@ public interface IStream extends Stream
|
|||
* of true puts the stream into closed state.</p>
|
||||
*
|
||||
* @param close whether the close state should be updated
|
||||
* @param local whether the close is local or remote
|
||||
*/
|
||||
public void updateCloseState(boolean close);
|
||||
public void updateCloseState(boolean close, boolean local);
|
||||
|
||||
/**
|
||||
* <p>Processes the given control frame,
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.eclipse.jetty.spdy;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.InterruptedByTimeoutException;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -62,12 +61,12 @@ import org.eclipse.jetty.spdy.frames.SynStreamFrame;
|
|||
import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
|
||||
import org.eclipse.jetty.spdy.generator.Generator;
|
||||
import org.eclipse.jetty.spdy.parser.Parser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class StandardSession implements ISession, Parser.Listener, Handler<StandardSession.FrameBytes>
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Session.class);
|
||||
private static final Logger logger = Log.getLogger(Session.class);
|
||||
private static final ThreadLocal<Integer> handlerInvocations = new ThreadLocal<Integer>()
|
||||
{
|
||||
@Override
|
||||
|
@ -79,7 +78,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
|
||||
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>();
|
||||
private final Deque<FrameBytes> queue = new LinkedList<>();
|
||||
private final LinkedList<FrameBytes> queue = new LinkedList<>();
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final Executor threadPool;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
@ -399,6 +398,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
private void onSyn(SynStreamFrame frame)
|
||||
{
|
||||
IStream stream = newStream(frame);
|
||||
stream.updateCloseState(frame.isClose(), false);
|
||||
logger.debug("Opening {}", stream);
|
||||
int streamId = frame.getStreamId();
|
||||
IStream existing = streams.putIfAbsent(streamId, stream);
|
||||
|
@ -430,6 +430,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
private IStream createStream(SynStreamFrame synStream, StreamFrameListener listener)
|
||||
{
|
||||
IStream stream = newStream(synStream);
|
||||
stream.updateCloseState(synStream.isClose(), true);
|
||||
stream.setStreamFrameListener(listener);
|
||||
if (streams.putIfAbsent(synStream.getStreamId(), stream) != null)
|
||||
{
|
||||
|
@ -732,10 +733,15 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
{
|
||||
ByteBuffer buffer = generator.control(frame);
|
||||
logger.debug("Queuing {} on {}", frame, stream);
|
||||
ControlFrameBytes<C> frameBytes = new ControlFrameBytes<>(handler, context, frame, buffer);
|
||||
ControlFrameBytes<C> frameBytes = new ControlFrameBytes<>(stream, handler, context, frame, buffer);
|
||||
if (timeout > 0)
|
||||
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
|
||||
enqueueLast(frameBytes);
|
||||
|
||||
// Special handling for PING frames, they must be sent as soon as possible
|
||||
if (ControlFrameType.PING == frame.getType())
|
||||
prepend(frameBytes);
|
||||
else
|
||||
append(frameBytes);
|
||||
}
|
||||
|
||||
flush();
|
||||
|
@ -766,10 +772,10 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
public <C> void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Handler<C> handler, C context)
|
||||
{
|
||||
logger.debug("Queuing {} on {}", dataInfo, stream);
|
||||
DataFrameBytes<C> frameBytes = new DataFrameBytes<>(handler, context, stream, dataInfo);
|
||||
DataFrameBytes<C> frameBytes = new DataFrameBytes<>(stream, handler, context, dataInfo);
|
||||
if (timeout > 0)
|
||||
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
|
||||
enqueueLast(frameBytes);
|
||||
append(frameBytes);
|
||||
flush();
|
||||
}
|
||||
|
||||
|
@ -781,47 +787,73 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
@Override
|
||||
public void flush()
|
||||
{
|
||||
FrameBytes frameBytes;
|
||||
ByteBuffer buffer;
|
||||
FrameBytes frameBytes = null;
|
||||
ByteBuffer buffer = null;
|
||||
synchronized (queue)
|
||||
{
|
||||
if (flushing)
|
||||
if (flushing || queue.isEmpty())
|
||||
return;
|
||||
|
||||
frameBytes = queue.poll();
|
||||
if (frameBytes == null)
|
||||
return;
|
||||
|
||||
buffer = frameBytes.getByteBuffer();
|
||||
if (buffer == null)
|
||||
Set<IStream> stalledStreams = null;
|
||||
for (int i = 0; i < queue.size(); ++i)
|
||||
{
|
||||
enqueueFirst(frameBytes);
|
||||
logger.debug("Flush skipped, {} frame(s) in queue", queue.size());
|
||||
return;
|
||||
frameBytes = queue.get(i);
|
||||
|
||||
if (stalledStreams != null && stalledStreams.contains(frameBytes.getStream()))
|
||||
continue;
|
||||
|
||||
buffer = frameBytes.getByteBuffer();
|
||||
if (buffer != null)
|
||||
{
|
||||
queue.remove(i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (stalledStreams == null)
|
||||
stalledStreams = new HashSet<>();
|
||||
stalledStreams.add(frameBytes.getStream());
|
||||
|
||||
logger.debug("Flush stalled for {}, {} frame(s) in queue", frameBytes, queue.size());
|
||||
}
|
||||
|
||||
if (buffer == null)
|
||||
return;
|
||||
|
||||
flushing = true;
|
||||
logger.debug("Flushing {}, {} frame(s) in queue", frameBytes, queue.size());
|
||||
}
|
||||
|
||||
logger.debug("Writing {} frame bytes of {}", buffer.remaining(), frameBytes);
|
||||
write(buffer, this, frameBytes);
|
||||
}
|
||||
|
||||
private void enqueueLast(FrameBytes frameBytes)
|
||||
private void append(FrameBytes frameBytes)
|
||||
{
|
||||
// TODO: handle priority; e.g. use queues to prioritize the buffers ?
|
||||
synchronized (queue)
|
||||
{
|
||||
queue.offerLast(frameBytes);
|
||||
int index = queue.size();
|
||||
while (index > 0)
|
||||
{
|
||||
FrameBytes element = queue.get(index - 1);
|
||||
if (element.compareTo(frameBytes) >= 0)
|
||||
break;
|
||||
--index;
|
||||
}
|
||||
queue.add(index, frameBytes);
|
||||
}
|
||||
}
|
||||
|
||||
private void enqueueFirst(FrameBytes frameBytes)
|
||||
private void prepend(FrameBytes frameBytes)
|
||||
{
|
||||
synchronized (queue)
|
||||
{
|
||||
queue.offerFirst(frameBytes);
|
||||
int index = 0;
|
||||
while (index < queue.size())
|
||||
{
|
||||
FrameBytes element = queue.get(index);
|
||||
if (element.compareTo(frameBytes) <= 0)
|
||||
break;
|
||||
++index;
|
||||
}
|
||||
queue.add(index, frameBytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,42 +877,44 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
protected void write(ByteBuffer buffer, Handler<FrameBytes> handler, FrameBytes frameBytes)
|
||||
{
|
||||
if (controller != null)
|
||||
{
|
||||
logger.debug("Writing {} frame bytes of {}", buffer.remaining(), frameBytes);
|
||||
controller.write(buffer, handler, frameBytes);
|
||||
}
|
||||
}
|
||||
|
||||
private <C> void complete(final Handler<C> handler, final C context)
|
||||
{
|
||||
if (handler != null)
|
||||
// Applications may send and queue up a lot of frames and
|
||||
// if we call Handler.completed() only synchronously we risk
|
||||
// starvation (for the last frames sent) and stack overflow.
|
||||
// Therefore every some invocation, we dispatch to a new thread
|
||||
Integer invocations = handlerInvocations.get();
|
||||
if (invocations >= 4)
|
||||
{
|
||||
// Applications may send and queue up a lot of frames and
|
||||
// if we call Handler.completed() only synchronously we risk
|
||||
// starvation (for the last frames sent) and stack overflow.
|
||||
// Therefore every some invocation, we dispatch to a new thread
|
||||
Integer invocations = handlerInvocations.get();
|
||||
if (invocations >= 4)
|
||||
execute(new Runnable()
|
||||
{
|
||||
execute(new Runnable()
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (handler != null)
|
||||
notifyHandlerCompleted(handler, context);
|
||||
flush();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
handlerInvocations.set(invocations + 1);
|
||||
try
|
||||
{
|
||||
notifyHandlerCompleted(handler, context);
|
||||
flush();
|
||||
}
|
||||
finally
|
||||
{
|
||||
handlerInvocations.set(invocations);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
handlerInvocations.set(invocations + 1);
|
||||
try
|
||||
{
|
||||
if (handler != null)
|
||||
notifyHandlerCompleted(handler, context);
|
||||
flush();
|
||||
}
|
||||
finally
|
||||
{
|
||||
handlerInvocations.set(invocations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -911,8 +945,10 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
}
|
||||
}
|
||||
|
||||
public interface FrameBytes
|
||||
public interface FrameBytes extends Comparable<FrameBytes>
|
||||
{
|
||||
public IStream getStream();
|
||||
|
||||
public abstract ByteBuffer getByteBuffer();
|
||||
|
||||
public abstract void complete();
|
||||
|
@ -920,16 +956,31 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
|
||||
private abstract class AbstractFrameBytes<C> implements FrameBytes, Runnable
|
||||
{
|
||||
private final IStream stream;
|
||||
private final Handler<C> handler;
|
||||
private final C context;
|
||||
protected volatile ScheduledFuture<?> task;
|
||||
|
||||
protected AbstractFrameBytes(Handler<C> handler, C context)
|
||||
protected AbstractFrameBytes(IStream stream, Handler<C> handler, C context)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.handler = handler;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStream getStream()
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FrameBytes that)
|
||||
{
|
||||
// If this.stream.priority > that.stream.priority => -1 (this.stream has less priority than that.stream)
|
||||
return that.getStream().getPriority() - getStream().getPriority();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete()
|
||||
{
|
||||
|
@ -957,9 +1008,9 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
private final ControlFrame frame;
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
private ControlFrameBytes(Handler<C> handler, C context, ControlFrame frame, ByteBuffer buffer)
|
||||
private ControlFrameBytes(IStream stream, Handler<C> handler, C context, ControlFrame frame, ByteBuffer buffer)
|
||||
{
|
||||
super(handler, context);
|
||||
super(stream, handler, context);
|
||||
this.frame = frame;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
@ -994,15 +1045,13 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
|
||||
private class DataFrameBytes<C> extends AbstractFrameBytes<C>
|
||||
{
|
||||
private final IStream stream;
|
||||
private final DataInfo dataInfo;
|
||||
private int length;
|
||||
private ByteBuffer buffer;
|
||||
private int size;
|
||||
private volatile ByteBuffer buffer;
|
||||
|
||||
private DataFrameBytes(Handler<C> handler, C context, IStream stream, DataInfo dataInfo)
|
||||
private DataFrameBytes(IStream stream, Handler<C> handler, C context, DataInfo dataInfo)
|
||||
{
|
||||
super(handler, context);
|
||||
this.stream = stream;
|
||||
super(stream, handler, context);
|
||||
this.dataInfo = dataInfo;
|
||||
}
|
||||
|
||||
|
@ -1011,15 +1060,16 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
{
|
||||
try
|
||||
{
|
||||
IStream stream = getStream();
|
||||
int windowSize = stream.getWindowSize();
|
||||
if (windowSize <= 0)
|
||||
return null;
|
||||
|
||||
length = dataInfo.length();
|
||||
if (length > windowSize)
|
||||
length = windowSize;
|
||||
size = dataInfo.available();
|
||||
if (size > windowSize)
|
||||
size = windowSize;
|
||||
|
||||
buffer = generator.data(stream.getId(), length, dataInfo);
|
||||
buffer = generator.data(stream.getId(), size, dataInfo);
|
||||
return buffer;
|
||||
}
|
||||
catch (Throwable x)
|
||||
|
@ -1032,19 +1082,21 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
@Override
|
||||
public void complete()
|
||||
{
|
||||
stream.updateWindowSize(-length);
|
||||
bufferPool.release(buffer);
|
||||
IStream stream = getStream();
|
||||
stream.updateWindowSize(-size);
|
||||
|
||||
if (dataInfo.available() > 0)
|
||||
{
|
||||
// If we could not write a full data frame, then we need first
|
||||
// to finish it, and then process the others (to avoid data garbling)
|
||||
enqueueFirst(this);
|
||||
// We have written a frame out of this DataInfo, but there is more to write.
|
||||
// We need to keep the correct ordering of frames, to avoid that another
|
||||
// DataInfo for the same stream is written before this one is finished.
|
||||
prepend(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.complete();
|
||||
stream.updateCloseState(dataInfo.isClose());
|
||||
stream.updateCloseState(dataInfo.isClose(), true);
|
||||
if (stream.isClosed())
|
||||
removeStream(stream);
|
||||
}
|
||||
|
@ -1053,7 +1105,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), stream);
|
||||
return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), getStream());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,27 +39,25 @@ import org.eclipse.jetty.spdy.frames.HeadersFrame;
|
|||
import org.eclipse.jetty.spdy.frames.SynReplyFrame;
|
||||
import org.eclipse.jetty.spdy.frames.SynStreamFrame;
|
||||
import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class StandardStream implements IStream
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Stream.class);
|
||||
private static final Logger logger = Log.getLogger(Stream.class);
|
||||
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
|
||||
private final SynStreamFrame frame;
|
||||
private final ISession session;
|
||||
private final AtomicInteger windowSize;
|
||||
private volatile StreamFrameListener listener;
|
||||
private volatile boolean opened;
|
||||
private volatile boolean halfClosed;
|
||||
private volatile boolean closed;
|
||||
private volatile OpenState openState = OpenState.SYN_SENT;
|
||||
private volatile CloseState closeState = CloseState.OPENED;
|
||||
|
||||
public StandardStream(SynStreamFrame frame, ISession session, int windowSize)
|
||||
{
|
||||
this.frame = frame;
|
||||
this.session = session;
|
||||
this.windowSize = new AtomicInteger(windowSize);
|
||||
this.halfClosed = frame.isClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,7 +93,8 @@ public class StandardStream implements IStream
|
|||
|
||||
public boolean isHalfClosed()
|
||||
{
|
||||
return halfClosed;
|
||||
CloseState closeState = this.closeState;
|
||||
return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.REMOTELY_CLOSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,14 +122,38 @@ public class StandardStream implements IStream
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateCloseState(boolean close)
|
||||
public void updateCloseState(boolean close, boolean local)
|
||||
{
|
||||
if (close)
|
||||
{
|
||||
if (isHalfClosed())
|
||||
closed = true;
|
||||
else
|
||||
halfClosed = true;
|
||||
switch (closeState)
|
||||
{
|
||||
case OPENED:
|
||||
{
|
||||
closeState = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED;
|
||||
break;
|
||||
}
|
||||
case LOCALLY_CLOSED:
|
||||
{
|
||||
if (local)
|
||||
throw new IllegalStateException();
|
||||
else
|
||||
closeState = CloseState.CLOSED;
|
||||
break;
|
||||
}
|
||||
case REMOTELY_CLOSED:
|
||||
{
|
||||
if (local)
|
||||
closeState = CloseState.CLOSED;
|
||||
else
|
||||
throw new IllegalStateException();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,14 +164,14 @@ public class StandardStream implements IStream
|
|||
{
|
||||
case SYN_STREAM:
|
||||
{
|
||||
opened = true;
|
||||
openState = OpenState.SYN_RECV;
|
||||
break;
|
||||
}
|
||||
case SYN_REPLY:
|
||||
{
|
||||
opened = true;
|
||||
openState = OpenState.REPLY_RECV;
|
||||
SynReplyFrame synReply = (SynReplyFrame)frame;
|
||||
updateCloseState(synReply.isClose());
|
||||
updateCloseState(synReply.isClose(), false);
|
||||
ReplyInfo replyInfo = new ReplyInfo(synReply.getHeaders(), synReply.isClose());
|
||||
notifyOnReply(replyInfo);
|
||||
break;
|
||||
|
@ -156,7 +179,7 @@ public class StandardStream implements IStream
|
|||
case HEADERS:
|
||||
{
|
||||
HeadersFrame headers = (HeadersFrame)frame;
|
||||
updateCloseState(headers.isClose());
|
||||
updateCloseState(headers.isClose(), false);
|
||||
HeadersInfo headersInfo = new HeadersInfo(headers.getHeaders(), headers.isClose(), headers.isResetCompression());
|
||||
notifyOnHeaders(headersInfo);
|
||||
break;
|
||||
|
@ -183,13 +206,13 @@ public class StandardStream implements IStream
|
|||
@Override
|
||||
public void process(DataFrame frame, ByteBuffer data)
|
||||
{
|
||||
if (!opened)
|
||||
if (!canReceive())
|
||||
{
|
||||
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
updateCloseState(frame.isClose());
|
||||
updateCloseState(frame.isClose(), false);
|
||||
|
||||
ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose(), frame.isCompress())
|
||||
{
|
||||
|
@ -286,7 +309,8 @@ public class StandardStream implements IStream
|
|||
@Override
|
||||
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Handler<Void> handler)
|
||||
{
|
||||
updateCloseState(replyInfo.isClose());
|
||||
openState = OpenState.REPLY_SENT;
|
||||
updateCloseState(replyInfo.isClose(), true);
|
||||
SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders());
|
||||
session.control(this, frame, timeout, unit, handler, null);
|
||||
}
|
||||
|
@ -302,6 +326,17 @@ public class StandardStream implements IStream
|
|||
@Override
|
||||
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Handler<Void> handler)
|
||||
{
|
||||
if (!canSend())
|
||||
{
|
||||
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
|
||||
throw new IllegalStateException("Protocol violation: cannot send a DATA frame before a SYN_REPLY frame");
|
||||
}
|
||||
if (isLocallyClosed())
|
||||
{
|
||||
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
|
||||
throw new IllegalStateException("Protocol violation: cannot send a DATA frame on a closed stream");
|
||||
}
|
||||
|
||||
// Cannot update the close state here, because the data that we send may
|
||||
// be flow controlled, so we need the stream to update the window size.
|
||||
session.data(this, dataInfo, timeout, unit, handler, null);
|
||||
|
@ -318,7 +353,18 @@ public class StandardStream implements IStream
|
|||
@Override
|
||||
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Handler<Void> handler)
|
||||
{
|
||||
updateCloseState(headersInfo.isClose());
|
||||
if (!canSend())
|
||||
{
|
||||
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
|
||||
throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame before a SYN_REPLY frame");
|
||||
}
|
||||
if (isLocallyClosed())
|
||||
{
|
||||
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
|
||||
throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame on a closed stream");
|
||||
}
|
||||
|
||||
updateCloseState(headersInfo.isClose(), true);
|
||||
HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders());
|
||||
session.control(this, frame, timeout, unit, handler, null);
|
||||
}
|
||||
|
@ -326,12 +372,40 @@ public class StandardStream implements IStream
|
|||
@Override
|
||||
public boolean isClosed()
|
||||
{
|
||||
return closed;
|
||||
return closeState == CloseState.CLOSED;
|
||||
}
|
||||
|
||||
private boolean isLocallyClosed()
|
||||
{
|
||||
CloseState closeState = this.closeState;
|
||||
return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.CLOSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("stream=%d v%d closed=%s", getId(), session.getVersion(), isClosed() ? "true" : isHalfClosed() ? "half" : "false");
|
||||
return String.format("stream=%d v%d %s", getId(), session.getVersion(), closeState);
|
||||
}
|
||||
|
||||
private boolean canSend()
|
||||
{
|
||||
OpenState openState = this.openState;
|
||||
return openState == OpenState.SYN_SENT || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT;
|
||||
}
|
||||
|
||||
private boolean canReceive()
|
||||
{
|
||||
OpenState openState = this.openState;
|
||||
return openState == OpenState.SYN_RECV || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT;
|
||||
}
|
||||
|
||||
private enum OpenState
|
||||
{
|
||||
SYN_SENT, SYN_RECV, REPLY_SENT, REPLY_RECV
|
||||
}
|
||||
|
||||
private enum CloseState
|
||||
{
|
||||
OPENED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.eclipse.jetty.spdy.api;
|
|||
|
||||
import java.util.EventListener;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* <p>A {@link SessionFrameListener} is the passive counterpart of a {@link Session} and receives events happening
|
||||
|
@ -122,7 +122,7 @@ public interface SessionFrameListener extends EventListener
|
|||
*/
|
||||
public static class Adapter implements SessionFrameListener
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Adapter.class);
|
||||
private static final Logger logger = Log.getLogger(Adapter.class);
|
||||
|
||||
@Override
|
||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||
|
|
|
@ -65,7 +65,7 @@ public class SettingsGenerator extends ControlFrameGenerator
|
|||
case SPDY.V2:
|
||||
{
|
||||
// In v2 the format is 24 bits of ID + 8 bits of flag
|
||||
int idAndFlags = (id << 8) + flags;
|
||||
int idAndFlags = (id << 8) + (flags & 0xFF);
|
||||
// A bug in the Chromium implementation forces v2 to have
|
||||
// the 3 ID bytes little endian, so we swap first and third
|
||||
int result = idAndFlags & 0x00_FF_00_FF;
|
||||
|
|
|
@ -58,6 +58,10 @@ public class GoAwayBodyParser extends ControlFrameBodyParser
|
|||
state = State.STATUS_CODE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -87,6 +91,10 @@ public class GoAwayBodyParser extends ControlFrameBodyParser
|
|||
state = State.STATUS_CODE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -27,12 +27,12 @@ import org.eclipse.jetty.spdy.StreamException;
|
|||
import org.eclipse.jetty.spdy.api.SessionStatus;
|
||||
import org.eclipse.jetty.spdy.frames.ControlFrame;
|
||||
import org.eclipse.jetty.spdy.frames.DataFrame;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class Parser
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(Parser.class);
|
||||
private static final Logger logger = Log.getLogger(Parser.class);
|
||||
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
private final ControlFrameParser controlFrameParser;
|
||||
private final DataFrameParser dataFrameParser;
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.util.concurrent.Executor;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.spdy.api.Handler;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
|
@ -94,17 +93,15 @@ public class AsyncTimeoutTest
|
|||
Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
|
||||
Session session = new StandardSession(SPDY.V2, bufferPool, threadPool, scheduler, new TestController(), null, 1, null, generator)
|
||||
{
|
||||
private final AtomicInteger flushes = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void flush()
|
||||
protected void write(ByteBuffer buffer, Handler<FrameBytes> handler, FrameBytes frameBytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
int flushes = this.flushes.incrementAndGet();
|
||||
if (flushes == 3)
|
||||
// Wait if we're writing the data frame (control frame's first byte is 0x80)
|
||||
if (buffer.get(0) == 0)
|
||||
unit.sleep(2 * timeout);
|
||||
super.flush();
|
||||
super.write(buffer, handler, frameBytes);
|
||||
}
|
||||
catch (InterruptedException x)
|
||||
{
|
||||
|
|
|
@ -1,63 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty-http-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Jetty :: SPDY :: Jetty HTTP Web Application</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>config</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--
|
||||
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<configuration>
|
||||
<stopPort>8888</stopPort>
|
||||
<stopKey>quit</stopKey>
|
||||
<jvmArgs>
|
||||
-Dlog4j.configuration=file://${basedir}/src/main/resources/log4j.properties
|
||||
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
|
||||
</jvmArgs>
|
||||
<jettyXml>${basedir}/src/main/config/jetty-spdy.xml</jettyXml>
|
||||
<contextPath>/</contextPath>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-jetty-http</artifactId>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty-http-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Jetty :: SPDY :: Jetty HTTP Web Application</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>config</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
<configuration>
|
||||
<stopPort>8888</stopPort>
|
||||
<stopKey>quit</stopKey>
|
||||
<jvmArgs>
|
||||
-Dlog4j.configuration=file://${basedir}/src/main/resources/log4j.properties
|
||||
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
|
||||
</jvmArgs>
|
||||
<jettyXml>${basedir}/src/main/config/etc/jetty-spdy.xml</jettyXml>
|
||||
<contextPath>/</contextPath>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -9,13 +9,6 @@
|
|||
<Set name="trustStore">src/main/resources/truststore.jks</Set>
|
||||
<Set name="trustStorePassword">storepwd</Set>
|
||||
<Set name="protocol">TLSv1</Set>
|
||||
<Set name="includeProtocols">
|
||||
<Array type="java.lang.String">
|
||||
<Item>TLSv1</Item>
|
||||
<Item>TLSv1.1</Item>
|
||||
<Item>TLSv1.2</Item>
|
||||
</Array>
|
||||
</Set>
|
||||
</New>
|
||||
|
||||
<Call name="addConnector">
|
||||
|
|
|
@ -1,84 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty-http</artifactId>
|
||||
<name>Jetty :: SPDY :: Jetty HTTP Layer</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.mortbay.jetty.npn</groupId>
|
||||
<artifactId>npn-boot</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>false</overWrite>
|
||||
<outputDirectory>${build.directory}/npn</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Xbootclasspath/p:${build.directory}/npn/npn-boot-${npn.version}.jar </argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>eclipse-release</id>
|
||||
<build>
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty-http</artifactId>
|
||||
<name>Jetty :: SPDY :: Jetty HTTP Layer</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.mortbay.jetty.npn</groupId>
|
||||
<artifactId>npn-boot</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>false</overWrite>
|
||||
<outputDirectory>${project.build.directory}/npn</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-jetty</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-jetty</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -50,13 +50,14 @@ import org.eclipse.jetty.spdy.api.DataInfo;
|
|||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.ReplyInfo;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implements AsyncConnection
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServerHTTPSPDYAsyncConnection.class);
|
||||
private static final Logger logger = Log.getLogger(ServerHTTPSPDYAsyncConnection.class);
|
||||
private static final ByteBuffer ZERO_BYTES = ByteBuffer.allocate(0);
|
||||
private static final DataInfo END_OF_CONTENT = new ByteBufferDataInfo(ZERO_BYTES, true);
|
||||
|
||||
private final Queue<Runnable> tasks = new LinkedList<>();
|
||||
private final BlockingQueue<DataInfo> dataInfos = new LinkedBlockingQueue<>();
|
||||
|
@ -65,7 +66,6 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
private Headers headers; // No need for volatile, guarded by state
|
||||
private DataInfo dataInfo; // No need for volatile, guarded by state
|
||||
private NIOBuffer buffer; // No need for volatile, guarded by state
|
||||
private boolean complete; // No need for volatile, guarded by state
|
||||
private volatile State state = State.INITIAL;
|
||||
private boolean dispatched; // Guarded by synchronization on tasks
|
||||
|
||||
|
@ -160,7 +160,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
logger.debug("HTTP > {} {} {}", new Object[]{m, u, v});
|
||||
startRequest(new ByteArrayBuffer(m), new ByteArrayBuffer(u), new ByteArrayBuffer(v));
|
||||
|
||||
state = State.HEADERS;
|
||||
updateState(State.HEADERS);
|
||||
handle();
|
||||
break;
|
||||
}
|
||||
|
@ -261,6 +261,12 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
{
|
||||
}
|
||||
|
||||
private void updateState(State newState)
|
||||
{
|
||||
logger.debug("State update {} -> {}", state, newState);
|
||||
state = newState;
|
||||
}
|
||||
|
||||
public void beginRequest(final Headers headers)
|
||||
{
|
||||
this.headers = headers.isEmpty() ? null : headers;
|
||||
|
@ -270,7 +276,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
public void run()
|
||||
{
|
||||
if (!headers.isEmpty())
|
||||
state = State.REQUEST;
|
||||
updateState(State.REQUEST);
|
||||
handle();
|
||||
}
|
||||
});
|
||||
|
@ -284,7 +290,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
state = state == State.INITIAL ? State.REQUEST : State.HEADERS;
|
||||
updateState(state == State.INITIAL ? State.REQUEST : State.HEADERS);
|
||||
handle();
|
||||
}
|
||||
});
|
||||
|
@ -292,7 +298,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
|
||||
public void content(final DataInfo dataInfo, boolean endRequest)
|
||||
{
|
||||
dataInfos.offer(new ByteBufferDataInfo(dataInfo.asByteBuffer(false), dataInfo.isClose(), dataInfo.isCompress())
|
||||
// We need to copy the dataInfo since we do not know when its bytes
|
||||
// will be consumed. When the copy is consumed, we consume also the
|
||||
// original, so the implementation can send a window update.
|
||||
ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(dataInfo.asByteBuffer(false), dataInfo.isClose(), dataInfo.isCompress())
|
||||
{
|
||||
@Override
|
||||
public void consume(int delta)
|
||||
|
@ -300,8 +309,11 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
super.consume(delta);
|
||||
dataInfo.consume(delta);
|
||||
}
|
||||
});
|
||||
complete = endRequest;
|
||||
};
|
||||
logger.debug("Queuing last={} content {}", endRequest, copyDataInfo);
|
||||
dataInfos.offer(copyDataInfo);
|
||||
if (endRequest)
|
||||
dataInfos.offer(END_OF_CONTENT);
|
||||
post(new Runnable()
|
||||
{
|
||||
@Override
|
||||
|
@ -310,10 +322,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
logger.debug("HTTP > {} bytes of content", dataInfo.length());
|
||||
if (state == State.HEADERS)
|
||||
{
|
||||
state = State.HEADERS_COMPLETE;
|
||||
updateState(State.HEADERS_COMPLETE);
|
||||
handle();
|
||||
}
|
||||
state = State.CONTENT;
|
||||
updateState(State.CONTENT);
|
||||
handle();
|
||||
}
|
||||
});
|
||||
|
@ -327,10 +339,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
{
|
||||
if (state == State.HEADERS)
|
||||
{
|
||||
state = State.HEADERS_COMPLETE;
|
||||
updateState(State.HEADERS_COMPLETE);
|
||||
handle();
|
||||
}
|
||||
state = State.FINAL;
|
||||
updateState(State.FINAL);
|
||||
handle();
|
||||
}
|
||||
});
|
||||
|
@ -343,10 +355,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
@Override
|
||||
public void run()
|
||||
{
|
||||
State currentState = state;
|
||||
state = State.ASYNC;
|
||||
State oldState = state;
|
||||
updateState(State.ASYNC);
|
||||
handle();
|
||||
state = currentState;
|
||||
updateState(oldState);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -370,12 +382,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
else
|
||||
{
|
||||
// The application has consumed the buffer, so consume also the DataInfo
|
||||
if (dataInfo.consumed() == 0)
|
||||
dataInfo.consume(dataInfo.length());
|
||||
dataInfo.consume(dataInfo.length());
|
||||
logger.debug("Consumed {} content bytes, queue size {}", dataInfo.consumed(), dataInfos.size());
|
||||
dataInfo = null;
|
||||
buffer = null;
|
||||
if (complete && dataInfos.isEmpty())
|
||||
return null;
|
||||
// Loop to get content bytes from DataInfos
|
||||
}
|
||||
}
|
||||
|
@ -388,9 +398,13 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
|
|||
logger.debug("Waited {} ms for content bytes", elapsed);
|
||||
if (dataInfo != null)
|
||||
{
|
||||
// Only consume if it's the last DataInfo
|
||||
boolean consume = complete && dataInfos.isEmpty();
|
||||
ByteBuffer byteBuffer = dataInfo.asByteBuffer(consume);
|
||||
if (dataInfo == END_OF_CONTENT)
|
||||
{
|
||||
logger.debug("End of content bytes, queue size {}", dataInfos.size());
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteBuffer byteBuffer = dataInfo.asByteBuffer(false);
|
||||
buffer = byteBuffer.isDirect() ? new DirectNIOBuffer(byteBuffer, false) : new IndirectNIOBuffer(byteBuffer, false);
|
||||
// Loop to return the buffer
|
||||
}
|
||||
|
|
|
@ -33,13 +33,13 @@ import org.eclipse.jetty.spdy.api.Stream;
|
|||
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.SynInfo;
|
||||
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnectionFactory
|
||||
{
|
||||
private static final String CONNECTION_ATTRIBUTE = "org.eclipse.jetty.spdy.http.connection";
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServerHTTPSPDYAsyncConnectionFactory.class);
|
||||
private static final Logger logger = Log.getLogger(ServerHTTPSPDYAsyncConnectionFactory.class);
|
||||
|
||||
private final Connector connector;
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect
|
|||
|
||||
logger.debug("Received {} on {}", synInfo, stream);
|
||||
|
||||
HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(stream);
|
||||
HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(endPoint, stream);
|
||||
ServerHTTPSPDYAsyncConnection connection = new ServerHTTPSPDYAsyncConnection(connector,
|
||||
asyncEndPoint, connector.getServer(),
|
||||
(SPDYAsyncConnection)endPoint.getConnection(), stream);
|
||||
|
@ -133,10 +133,12 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect
|
|||
|
||||
private class HTTPSPDYAsyncEndPoint extends EmptyAsyncEndPoint
|
||||
{
|
||||
private final AsyncEndPoint endPoint;
|
||||
private final Stream stream;
|
||||
|
||||
public HTTPSPDYAsyncEndPoint(Stream stream)
|
||||
private HTTPSPDYAsyncEndPoint(AsyncEndPoint endPoint, Stream stream)
|
||||
{
|
||||
this.endPoint = endPoint;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
|
@ -146,5 +148,41 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect
|
|||
ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE);
|
||||
connection.async();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalAddr()
|
||||
{
|
||||
return endPoint.getLocalAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalHost()
|
||||
{
|
||||
return endPoint.getLocalHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort()
|
||||
{
|
||||
return endPoint.getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
return endPoint.getRemoteAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteHost()
|
||||
{
|
||||
return endPoint.getRemoteHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemotePort()
|
||||
{
|
||||
return endPoint.getRemotePort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,6 +190,14 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
|
|||
Assert.assertEquals("POST", httpRequest.getMethod());
|
||||
Assert.assertEquals("1", httpRequest.getParameter("a"));
|
||||
Assert.assertEquals("2", httpRequest.getParameter("b"));
|
||||
Assert.assertNotNull(httpRequest.getRemoteHost());
|
||||
Assert.assertNotNull(httpRequest.getRemotePort());
|
||||
Assert.assertNotNull(httpRequest.getRemoteAddr());
|
||||
Assert.assertNotNull(httpRequest.getLocalPort());
|
||||
Assert.assertNotNull(httpRequest.getLocalName());
|
||||
Assert.assertNotNull(httpRequest.getLocalAddr());
|
||||
Assert.assertNotNull(httpRequest.getServerPort());
|
||||
Assert.assertNotNull(httpRequest.getServerName());
|
||||
handlerLatch.countDown();
|
||||
}
|
||||
}), null);
|
||||
|
@ -519,7 +527,6 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
|
|||
@Override
|
||||
public void onData(Stream stream, DataInfo dataInfo)
|
||||
{
|
||||
|
||||
contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining());
|
||||
if (dataInfo.isClose())
|
||||
{
|
||||
|
|
|
@ -1,88 +1,77 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty</artifactId>
|
||||
<name>Jetty :: SPDY :: Jetty Binding</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.mortbay.jetty.npn</groupId>
|
||||
<artifactId>npn-boot</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>false</overWrite>
|
||||
<outputDirectory>${build.directory}/npn</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Xbootclasspath/p:${build.directory}/npn/npn-boot-${npn.version}.jar </argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>eclipse-release</id>
|
||||
<build>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-parent</artifactId>
|
||||
<version>7.6.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spdy-jetty</artifactId>
|
||||
<name>Jetty :: SPDY :: Jetty Binding</name>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.mortbay.jetty.npn</groupId>
|
||||
<artifactId>npn-boot</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>false</overWrite>
|
||||
<outputDirectory>${project.build.directory}/npn</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>-Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.spdy</groupId>
|
||||
<artifactId>spdy-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>${slf4j-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -30,12 +30,12 @@ import org.eclipse.jetty.io.nio.NIOBuffer;
|
|||
import org.eclipse.jetty.spdy.api.Handler;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.parser.Parser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class SPDYAsyncConnection extends AbstractConnection implements AsyncConnection, Controller<StandardSession.FrameBytes>, IdleListener
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(SPDYAsyncConnection.class);
|
||||
private static final Logger logger = Log.getLogger(SPDYAsyncConnection.class);
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final Parser parser;
|
||||
private volatile Session session;
|
||||
|
@ -181,7 +181,7 @@ public class SPDYAsyncConnection extends AbstractConnection implements AsyncConn
|
|||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
logger.trace("", x);
|
||||
logger.ignore(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,14 +41,14 @@ import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
|||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class SPDYServerConnector extends SelectChannelConnector
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(SPDYServerConnector.class);
|
||||
private static final Logger logger = Log.getLogger(SPDYServerConnector.class);
|
||||
|
||||
// Order is important on server side, so we use a LinkedHashMap
|
||||
private final Map<String, AsyncConnectionFactory> factories = new LinkedHashMap<>();
|
||||
|
|
|
@ -307,7 +307,7 @@ public class FlowControlTest extends AbstractTest
|
|||
|
||||
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
|
||||
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS);
|
||||
final int length = 5 * windowSize;
|
||||
stream.data(new BytesDataInfo(new byte[length], true));
|
||||
|
||||
|
@ -359,6 +359,98 @@ public class FlowControlTest extends AbstractTest
|
|||
Assert.assertEquals(dataInfo.length(), dataInfo.consumed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStreamsStalledDoesNotStallOtherStreams() throws Exception
|
||||
{
|
||||
final int windowSize = 1024;
|
||||
final CountDownLatch settingsLatch = new CountDownLatch(1);
|
||||
Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onSettings(Session session, SettingsInfo settingsInfo)
|
||||
{
|
||||
settingsLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||
{
|
||||
stream.reply(new ReplyInfo(false));
|
||||
stream.data(new BytesDataInfo(new byte[windowSize * 2], true));
|
||||
return null;
|
||||
}
|
||||
}), null);
|
||||
Settings settings = new Settings();
|
||||
settings.put(new Settings.Setting(Settings.ID.INITIAL_WINDOW_SIZE, windowSize));
|
||||
session.settings(new SettingsInfo(settings));
|
||||
|
||||
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(3);
|
||||
final AtomicReference<DataInfo> dataInfoRef1 = new AtomicReference<>();
|
||||
final AtomicReference<DataInfo> dataInfoRef2 = new AtomicReference<>();
|
||||
session.syn(new SynInfo(true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
private final AtomicInteger dataFrames = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void onData(Stream stream, DataInfo dataInfo)
|
||||
{
|
||||
int frames = dataFrames.incrementAndGet();
|
||||
if (frames == 1)
|
||||
{
|
||||
// Do not consume it to stall flow control
|
||||
dataInfoRef1.set(dataInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataInfo.consume(dataInfo.length());
|
||||
if (dataInfo.isClose())
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}).get(5, TimeUnit.SECONDS);
|
||||
session.syn(new SynInfo(true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
private final AtomicInteger dataFrames = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void onData(Stream stream, DataInfo dataInfo)
|
||||
{
|
||||
int frames = dataFrames.incrementAndGet();
|
||||
if (frames == 1)
|
||||
{
|
||||
// Do not consume it to stall flow control
|
||||
dataInfoRef2.set(dataInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataInfo.consume(dataInfo.length());
|
||||
if (dataInfo.isClose())
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
}).get(5, TimeUnit.SECONDS);
|
||||
session.syn(new SynInfo(true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataInfo dataInfo)
|
||||
{
|
||||
DataInfo dataInfo1 = dataInfoRef1.getAndSet(null);
|
||||
if (dataInfo1 != null)
|
||||
dataInfo1.consume(dataInfo1.length());
|
||||
DataInfo dataInfo2 = dataInfoRef2.getAndSet(null);
|
||||
if (dataInfo2 != null)
|
||||
dataInfo2.consume(dataInfo2.length());
|
||||
dataInfo.consume(dataInfo.length());
|
||||
if (dataInfo.isClose())
|
||||
latch.countDown();
|
||||
}
|
||||
}).get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private void expectException(Class<? extends Exception> exception, Callable command)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
package org.eclipse.jetty.spdy;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.spdy.api.BytesDataInfo;
|
||||
import org.eclipse.jetty.spdy.api.DataInfo;
|
||||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.HeadersInfo;
|
||||
import org.eclipse.jetty.spdy.api.RstInfo;
|
||||
import org.eclipse.jetty.spdy.api.SPDY;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.SessionStatus;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.StreamStatus;
|
||||
import org.eclipse.jetty.spdy.api.StringDataInfo;
|
||||
import org.eclipse.jetty.spdy.api.SynInfo;
|
||||
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
|
||||
import org.eclipse.jetty.spdy.frames.ControlFrameType;
|
||||
import org.eclipse.jetty.spdy.frames.GoAwayFrame;
|
||||
import org.eclipse.jetty.spdy.frames.SynReplyFrame;
|
||||
import org.eclipse.jetty.spdy.generator.Generator;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ProtocolViolationsTest extends AbstractTest
|
||||
{
|
||||
@Test
|
||||
public void testSendDataBeforeReplyIsIllegal() throws Exception
|
||||
{
|
||||
final CountDownLatch resetLatch = new CountDownLatch(1);
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.data(new StringDataInfo("failure", true));
|
||||
return null;
|
||||
}
|
||||
catch (IllegalStateException x)
|
||||
{
|
||||
latch.countDown();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}), new SessionFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onRst(Session session, RstInfo rstInfo)
|
||||
{
|
||||
Assert.assertSame(StreamStatus.PROTOCOL_ERROR, rstInfo.getStreamStatus());
|
||||
resetLatch.countDown();
|
||||
}
|
||||
});
|
||||
session.syn(new SynInfo(true), null);
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveDataBeforeReplyIsIllegal() throws Exception
|
||||
{
|
||||
ServerSocketChannel server = ServerSocketChannel.open();
|
||||
server.bind(new InetSocketAddress("localhost", 0));
|
||||
|
||||
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
|
||||
session.syn(new SynInfo(true), null);
|
||||
|
||||
SocketChannel channel = server.accept();
|
||||
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
|
||||
channel.read(readBuffer);
|
||||
readBuffer.flip();
|
||||
int streamId = readBuffer.getInt(8);
|
||||
|
||||
Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
|
||||
byte[] bytes = new byte[1];
|
||||
ByteBuffer writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
|
||||
channel.write(writeBuffer);
|
||||
|
||||
readBuffer.clear();
|
||||
channel.read(readBuffer);
|
||||
readBuffer.flip();
|
||||
Assert.assertEquals(ControlFrameType.RST_STREAM.getCode(), readBuffer.getShort(2));
|
||||
Assert.assertEquals(streamId, readBuffer.getInt(8));
|
||||
|
||||
writeBuffer = generator.control(new GoAwayFrame(SPDY.V2, 0, SessionStatus.OK.getCode()));
|
||||
channel.write(writeBuffer);
|
||||
channel.shutdownOutput();
|
||||
channel.close();
|
||||
|
||||
server.close();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testSendDataAfterCloseIsIllegal() throws Exception
|
||||
{
|
||||
Session session = startClient(startServer(null), null);
|
||||
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
|
||||
stream.data(new StringDataInfo("test", true));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testSendHeadersAfterCloseIsIllegal() throws Exception
|
||||
{
|
||||
Session session = startClient(startServer(null), null);
|
||||
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
|
||||
stream.headers(new HeadersInfo(new Headers(), true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataSentAfterCloseIsDiscardedByRecipient() throws Exception
|
||||
{
|
||||
ServerSocketChannel server = ServerSocketChannel.open();
|
||||
server.bind(new InetSocketAddress("localhost", 0));
|
||||
|
||||
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
|
||||
final CountDownLatch dataLatch = new CountDownLatch(2);
|
||||
session.syn(new SynInfo(true), new StreamFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataInfo dataInfo)
|
||||
{
|
||||
dataLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
SocketChannel channel = server.accept();
|
||||
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
|
||||
channel.read(readBuffer);
|
||||
readBuffer.flip();
|
||||
int streamId = readBuffer.getInt(8);
|
||||
|
||||
Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
|
||||
|
||||
ByteBuffer writeBuffer = generator.control(new SynReplyFrame(SPDY.V2, (byte)0, streamId, new Headers()));
|
||||
channel.write(writeBuffer);
|
||||
|
||||
byte[] bytes = new byte[1];
|
||||
writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
|
||||
channel.write(writeBuffer);
|
||||
|
||||
// Write again to simulate the faulty condition
|
||||
writeBuffer.flip();
|
||||
channel.write(writeBuffer);
|
||||
|
||||
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
writeBuffer = generator.control(new GoAwayFrame(SPDY.V2, 0, SessionStatus.OK.getCode()));
|
||||
channel.write(writeBuffer);
|
||||
channel.shutdownOutput();
|
||||
channel.close();
|
||||
|
||||
server.close();
|
||||
}
|
||||
}
|
|
@ -64,6 +64,8 @@ public class ResetStreamTest extends AbstractTest
|
|||
Assert.assertEquals(0, serverSession.getStreams().size());
|
||||
|
||||
Assert.assertTrue(rstLatch.await(5, TimeUnit.SECONDS));
|
||||
// Need to sleep a while to give the chance to the implementation to remove the stream
|
||||
TimeUnit.SECONDS.sleep(1);
|
||||
Assert.assertEquals(0, clientSession.getStreams().size());
|
||||
}
|
||||
|
||||
|
|
|
@ -87,25 +87,8 @@ public class SynDataReplyDataLoadTest extends AbstractTest
|
|||
}
|
||||
});
|
||||
|
||||
List<Callable<Object>> tasks = new ArrayList<>();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
tasks.add(new Callable<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object call() throws Exception
|
||||
{
|
||||
synCompletedData(session, headers, iterations);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ExecutorService threadPool = Executors.newFixedThreadPool(count);
|
||||
List<Future<Object>> futures = threadPool.invokeAll(tasks);
|
||||
for (Future<Object> future : futures)
|
||||
future.get(iterations, TimeUnit.SECONDS);
|
||||
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
|
||||
List<Callable<Object>> tasks = new ArrayList<>();
|
||||
|
||||
tasks.clear();
|
||||
for (int i = 0; i < count; ++i)
|
||||
|
@ -120,11 +103,38 @@ public class SynDataReplyDataLoadTest extends AbstractTest
|
|||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
long begin = System.nanoTime();
|
||||
List<Future<Object>> futures = threadPool.invokeAll(tasks);
|
||||
for (Future<Object> future : futures)
|
||||
future.get(iterations, TimeUnit.SECONDS);
|
||||
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
|
||||
long end = System.nanoTime();
|
||||
System.err.printf("SYN+GET+DATA+GET completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
|
||||
}
|
||||
|
||||
futures = threadPool.invokeAll(tasks);
|
||||
for (Future<Object> future : futures)
|
||||
future.get(iterations, TimeUnit.SECONDS);
|
||||
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
|
||||
tasks.clear();
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
tasks.add(new Callable<Object>()
|
||||
{
|
||||
@Override
|
||||
public Object call() throws Exception
|
||||
{
|
||||
synCompletedData(session, headers, iterations);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
long begin = System.nanoTime();
|
||||
List<Future<Object>> futures = threadPool.invokeAll(tasks);
|
||||
for (Future<Object> future : futures)
|
||||
future.get(iterations, TimeUnit.SECONDS);
|
||||
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
|
||||
long end = System.nanoTime();
|
||||
System.err.printf("SYN+COMPLETED+DATA completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
|
||||
}
|
||||
|
||||
threadPool.shutdown();
|
||||
}
|
||||
|
|
|
@ -30,12 +30,10 @@ import org.eclipse.jetty.spdy.api.DataInfo;
|
|||
import org.eclipse.jetty.spdy.api.Handler;
|
||||
import org.eclipse.jetty.spdy.api.Headers;
|
||||
import org.eclipse.jetty.spdy.api.ReplyInfo;
|
||||
import org.eclipse.jetty.spdy.api.RstInfo;
|
||||
import org.eclipse.jetty.spdy.api.Session;
|
||||
import org.eclipse.jetty.spdy.api.SessionFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.Stream;
|
||||
import org.eclipse.jetty.spdy.api.StreamFrameListener;
|
||||
import org.eclipse.jetty.spdy.api.StreamStatus;
|
||||
import org.eclipse.jetty.spdy.api.StringDataInfo;
|
||||
import org.eclipse.jetty.spdy.api.SynInfo;
|
||||
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
|
||||
|
@ -324,39 +322,6 @@ public class SynReplyTest extends AbstractTest
|
|||
Assert.assertTrue(clientDataLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynDataRst() throws Exception
|
||||
{
|
||||
final AtomicReference<RstInfo> ref = new AtomicReference<>();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
|
||||
{
|
||||
// Do not send the reply, we expect a RST_STREAM
|
||||
stream.data(new StringDataInfo("foo", true));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRst(Session session, RstInfo rstInfo)
|
||||
{
|
||||
ref.set(rstInfo);
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
Session session = startClient(startServer(serverSessionFrameListener), null);
|
||||
|
||||
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
RstInfo rstInfo = ref.get();
|
||||
Assert.assertNotNull(rstInfo);
|
||||
Assert.assertEquals(stream.getId(), rstInfo.getStreamId());
|
||||
Assert.assertSame(StreamStatus.PROTOCOL_ERROR, rstInfo.getStreamStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynReplyDataSynReplyData() throws Exception
|
||||
{
|
||||
|
|
|
@ -381,7 +381,7 @@ public class Main
|
|||
}
|
||||
else if (info.equals("@STARTINI"))
|
||||
{
|
||||
List<String> ini = loadStartIni(null);
|
||||
List<String> ini = loadStartIni(new File(_jettyHome,"start.ini"));
|
||||
if (ini != null && ini.size() > 0)
|
||||
{
|
||||
for (String a : ini)
|
||||
|
|
|
@ -287,7 +287,25 @@ public class MultiMap<K> implements ConcurrentMap<K,Object>, Serializable
|
|||
*/
|
||||
public Map<K,String[]> toStringArrayMap()
|
||||
{
|
||||
HashMap<K,String[]> map = new HashMap<K,String[]>(_map.size()*3/2);
|
||||
HashMap<K,String[]> map = new HashMap<K,String[]>(_map.size()*3/2)
|
||||
{
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder b=new StringBuilder();
|
||||
b.append('{');
|
||||
for (K k:keySet())
|
||||
{
|
||||
if(b.length()>1)
|
||||
b.append(',');
|
||||
b.append(k);
|
||||
b.append('=');
|
||||
b.append(Arrays.asList(get(k)));
|
||||
}
|
||||
|
||||
b.append('}');
|
||||
return b.toString();
|
||||
}
|
||||
};
|
||||
|
||||
for(Map.Entry<K,Object> entry: _map.entrySet())
|
||||
{
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
|
||||
|
||||
|
@ -67,6 +71,7 @@ public class URIUtil
|
|||
*/
|
||||
public static StringBuilder encodePath(StringBuilder buf, String path)
|
||||
{
|
||||
byte[] bytes=null;
|
||||
if (buf==null)
|
||||
{
|
||||
loop:
|
||||
|
@ -84,8 +89,23 @@ public class URIUtil
|
|||
case '<':
|
||||
case '>':
|
||||
case ' ':
|
||||
buf=new StringBuilder(path.length()<<1);
|
||||
buf=new StringBuilder(path.length()*2);
|
||||
break loop;
|
||||
default:
|
||||
if (c>127)
|
||||
{
|
||||
try
|
||||
{
|
||||
bytes=path.getBytes(URIUtil.__CHARSET);
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
buf=new StringBuilder(path.length()*2);
|
||||
break loop;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (buf==null)
|
||||
|
@ -94,41 +114,91 @@ public class URIUtil
|
|||
|
||||
synchronized(buf)
|
||||
{
|
||||
for (int i=0;i<path.length();i++)
|
||||
if (bytes!=null)
|
||||
{
|
||||
char c=path.charAt(i);
|
||||
switch(c)
|
||||
for (int i=0;i<bytes.length;i++)
|
||||
{
|
||||
case '%':
|
||||
buf.append("%25");
|
||||
continue;
|
||||
case '?':
|
||||
buf.append("%3F");
|
||||
continue;
|
||||
case ';':
|
||||
buf.append("%3B");
|
||||
continue;
|
||||
case '#':
|
||||
buf.append("%23");
|
||||
continue;
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
case ' ':
|
||||
buf.append("%20");
|
||||
continue;
|
||||
default:
|
||||
buf.append(c);
|
||||
continue;
|
||||
byte c=bytes[i];
|
||||
switch(c)
|
||||
{
|
||||
case '%':
|
||||
buf.append("%25");
|
||||
continue;
|
||||
case '?':
|
||||
buf.append("%3F");
|
||||
continue;
|
||||
case ';':
|
||||
buf.append("%3B");
|
||||
continue;
|
||||
case '#':
|
||||
buf.append("%23");
|
||||
continue;
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
case ' ':
|
||||
buf.append("%20");
|
||||
continue;
|
||||
default:
|
||||
if (c<0)
|
||||
{
|
||||
buf.append('%');
|
||||
TypeUtil.toHex(c,buf);
|
||||
}
|
||||
else
|
||||
buf.append((char)c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0;i<path.length();i++)
|
||||
{
|
||||
char c=path.charAt(i);
|
||||
switch(c)
|
||||
{
|
||||
case '%':
|
||||
buf.append("%25");
|
||||
continue;
|
||||
case '?':
|
||||
buf.append("%3F");
|
||||
continue;
|
||||
case ';':
|
||||
buf.append("%3B");
|
||||
continue;
|
||||
case '#':
|
||||
buf.append("%23");
|
||||
continue;
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
case ' ':
|
||||
buf.append("%20");
|
||||
continue;
|
||||
default:
|
||||
buf.append(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,7 +305,8 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
LOG.warn("tmpdir",e); System.exit(1);
|
||||
tmpDir = null;
|
||||
throw new IllegalStateException("Cannot create tmp dir in "+System.getProperty("java.io.tmpdir")+ " for context "+context,e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,8 +403,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
|
||||
|
||||
LOG.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory()+" file="+(web_app.getFile()));
|
||||
// Is the WAR usable directly?
|
||||
if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
|
||||
{
|
||||
|
@ -485,57 +485,50 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
LOG.debug("webapp=" + web_app);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Do we need to extract WEB-INF/lib?
|
||||
if (context.isCopyWebInf())
|
||||
if (context.isCopyWebInf() && !context.isCopyWebDir())
|
||||
{
|
||||
Resource web_inf= web_app.addPath("WEB-INF/");
|
||||
|
||||
if (web_inf instanceof ResourceCollection ||
|
||||
web_inf.exists() &&
|
||||
web_inf.isDirectory() &&
|
||||
(web_inf.getFile()==null || !web_inf.getFile().isDirectory()))
|
||||
{
|
||||
File extractedWebInfDir= new File(context.getTempDirectory(), "webinf");
|
||||
if (extractedWebInfDir.exists())
|
||||
IO.delete(extractedWebInfDir);
|
||||
extractedWebInfDir.mkdir();
|
||||
Resource web_inf_lib = web_inf.addPath("lib/");
|
||||
File webInfDir=new File(extractedWebInfDir,"WEB-INF");
|
||||
webInfDir.mkdir();
|
||||
File extractedWebInfDir= new File(context.getTempDirectory(), "webinf");
|
||||
if (extractedWebInfDir.exists())
|
||||
IO.delete(extractedWebInfDir);
|
||||
extractedWebInfDir.mkdir();
|
||||
Resource web_inf_lib = web_inf.addPath("lib/");
|
||||
File webInfDir=new File(extractedWebInfDir,"WEB-INF");
|
||||
webInfDir.mkdir();
|
||||
|
||||
if (web_inf_lib.exists())
|
||||
{
|
||||
File webInfLibDir = new File(webInfDir, "lib");
|
||||
if (webInfLibDir.exists())
|
||||
IO.delete(webInfLibDir);
|
||||
webInfLibDir.mkdir();
|
||||
if (web_inf_lib.exists())
|
||||
{
|
||||
File webInfLibDir = new File(webInfDir, "lib");
|
||||
if (webInfLibDir.exists())
|
||||
IO.delete(webInfLibDir);
|
||||
webInfLibDir.mkdir();
|
||||
|
||||
LOG.info("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
|
||||
web_inf_lib.copyTo(webInfLibDir);
|
||||
}
|
||||
LOG.info("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
|
||||
web_inf_lib.copyTo(webInfLibDir);
|
||||
}
|
||||
|
||||
Resource web_inf_classes = web_inf.addPath("classes/");
|
||||
if (web_inf_classes.exists())
|
||||
{
|
||||
File webInfClassesDir = new File(webInfDir, "classes");
|
||||
if (webInfClassesDir.exists())
|
||||
IO.delete(webInfClassesDir);
|
||||
webInfClassesDir.mkdir();
|
||||
LOG.info("Copying WEB-INF/classes from "+web_inf_classes+" to "+webInfClassesDir.getAbsolutePath());
|
||||
web_inf_classes.copyTo(webInfClassesDir);
|
||||
}
|
||||
Resource web_inf_classes = web_inf.addPath("classes/");
|
||||
if (web_inf_classes.exists())
|
||||
{
|
||||
File webInfClassesDir = new File(webInfDir, "classes");
|
||||
if (webInfClassesDir.exists())
|
||||
IO.delete(webInfClassesDir);
|
||||
webInfClassesDir.mkdir();
|
||||
LOG.info("Copying WEB-INF/classes from "+web_inf_classes+" to "+webInfClassesDir.getAbsolutePath());
|
||||
web_inf_classes.copyTo(webInfClassesDir);
|
||||
}
|
||||
|
||||
web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath());
|
||||
web_inf=Resource.newResource(extractedWebInfDir.getCanonicalPath());
|
||||
|
||||
ResourceCollection rc = new ResourceCollection(web_inf,web_app);
|
||||
ResourceCollection rc = new ResourceCollection(web_inf,web_app);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("context.resourcebase = "+rc);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("context.resourcebase = "+rc);
|
||||
|
||||
context.setBaseResource(rc);
|
||||
}
|
||||
context.setBaseResource(rc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue