mcardle 2005/11/08 11:57:03 CET
Modified files:
src/org/jahia/esi GetThread.java
Log:
* creates dummy cache entries which contain the appropriate error message why
a given object/fragment wasn't retrieved correctly.
* supports a configurable number of connection retries
* removes If-conditional HTTP headers from requests
Revision Changes Path
1.6 +152 -48 esi_server/src/org/jahia/esi/GetThread.java
http://jahia.mine.nu:8080/cgi-bin/cvsweb.cgi/esi_server/src/org/jahia/esi/GetThread.java.diff?r1=1.5&r2=1.6&f=h
Index: GetThread.java
===================================================================
RCS file: /home/cvs/repository/esi_server/src/org/jahia/esi/GetThread.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- GetThread.java 2 Nov 2005 15:46:02 -0000 1.5
+++ GetThread.java 8 Nov 2005 10:57:03 -0000 1.6
@@ -1,9 +1,5 @@
package org.jahia.esi;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.URI;
-import org.apache.commons.httpclient.URIException;
-import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -24,6 +20,8 @@
import org.jahia.esi.cache.UrlCacheObject;
import org.jahia.esi.tags.EsiIncludeTag;
import org.jahia.esi.tags.EsiRemoveTag;
+import org.jahia.esi.settings.GeneralSettings;
+import org.jahia.esi.exceptions.TransferFailedException;
import net.sf.j2ep.ProxyFilter;
import net.sf.j2ep.responsehandlers.ResponseHandlerBase;
@@ -34,6 +32,9 @@
import java.util.Date;
import java.io.InputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.commons.httpclient.*;
/**
* Created by IntelliJ IDEA.
@@ -44,19 +45,21 @@
*/
public class GetThread extends Thread {
+ private static final int SC_NULL = -1;
+
private static final transient Log log =
LogFactory.getLog(GetThread.class);
private HttpClient httpClient;
private GetMethod methodToServer;
private int id = (int)(Math.random()*100.0);
private ResponseHandlerBase responseHandlerBase;
-
private HttpServletResponse clientResponse;
private HttpServletRequest clientRequest;
private String urlKey;
private UrlCacheObject urlObj;
private String urlToServer;
private String clientRequestUrl;
+ private boolean success = true;
long expirationDateInSecs = (new Date()).getTime();
long expirationInSecs = EsiConst.DEFAULT_EXPIRATION;
@@ -106,7 +109,13 @@
return urlToServer;
}
+ public boolean isSuccess() {
+ return success;
+ }
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
/**
* Executes the GetMethod and prints some satus information.
@@ -120,7 +129,19 @@
//******************** FETCH ************************
byte[] bytes = null;
- bytes = retrieveBytesFromServer(bytes);
+ try {
+ bytes = retrieveBytesFromServer();
+ }
+ catch (TransferFailedException e) {
+ log.error(id + " - error: " + e);
+ setSuccess(false);
+ String urlKey =
CacheAdminstrator.getInstance().generateEntryKey("GET" , clientRequestUrl );
+ StringBuffer errorMsg = new StringBuffer("<b>ESI ERROR: Could
not fetch the object (urlKey:[").append(urlKey).append("]) due to error: ");
+ errorMsg.append(e.toString()).append(" - Http Status Code
").append(this.methodToServer.getStatusLine().toString())
+ .append(" - for client request:
").append(clientRequestUrl).append("</b>");
+ fragmentCache.addUnfectched ( urlKey , this.methodToServer ,
errorMsg.toString() , this.clientRequestUrl);
+ return;
+ }
//******************** CHECK CONTENT TYPE ************************
//***********************************************
@@ -243,7 +264,6 @@
GetThread thread = (GetThread) threadEnum.nextElement();
try {
thread.join();
-
} catch (InterruptedException ex) {
log.error(id + "THREAD WAS INTERRUPTED
!!!!!!!!!!!!!!!!!!!!");
//TODO: deal with error
@@ -326,60 +346,115 @@
} catch (Exception e) {
log.error(id + " - Main Thread ERROR : " + e);
+ e.printStackTrace();
}
yield();
}
- private byte[] retrieveBytesFromServer(byte[] bytes) {
+
+
+ private byte[] retrieveBytesFromServer()
+ throws TransferFailedException {
+
+ byte[] bytes = null;
+
+ int statusCode = SC_NULL;
+
+ int attempt = 0;
+
try {
- //TODO: replace by STREAM version
+ // We will retry up to NumberOfAttempts times.
+ while ( statusCode == SC_NULL && attempt <
GeneralSettings.getInstance().getNumberOfAttempts() )
+ {
+ try
+ {
-
//ResponseHandlerBase.getRidOfDodgyRequestHeaders(methodToServer);
+ getRidOfConditionalHttpHeaders();
- log.debug(id + " - about to get something from " + urlToServer );
- // execute the methodToServer
- httpClient.executeMethod(methodToServer);
-
- // TODO: CHECK CONTENT TYPE should go here so that if the
content is binary and too big,
- // then we just do a passthrough. If it's just binary and small
enough to cache
- // we do a passthroughAndCache.
-
- log.debug(id + " - get executed");
- // get the response body as an array of bytes
-
- InputStream streamFromServer =
methodToServer.getResponseBodyAsStream();
- ByteArrayOutputStream byteStream = new
ByteArrayOutputStream(1000);
-
- if (streamFromServer != null) {
- byte[] buffer = new
byte[1024];//CHANGEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
- int read = streamFromServer.read(buffer);
- while (read > 0) {
- byteStream.write(buffer, 0, read);
- read = streamFromServer.read(buffer);
- }
- streamFromServer.close();
- }
+ log.debug(id + " - about to get something from " +
urlToServer );
+ // execute the methodToServer
+ statusCode = httpClient.executeMethod(methodToServer);
+
+ // TODO: CHECK CONTENT TYPE should go here so that if
the content is binary and too big,
+ // then we just do a passthrough. If it's just binary
and small enough to cache
+ // we do a passthroughAndCache.
+
+ // get the response body as an array of bytes
+ InputStream streamFromServer =
methodToServer.getResponseBodyAsStream();
+ ByteArrayOutputStream byteStream = new
ByteArrayOutputStream(1000);
+
+ if (streamFromServer != null) {
+ byte[] buffer = new byte[1024]; //TODO: check best
optimal value
+ int read = streamFromServer.read(buffer);
+ while (read > 0) {
+ byteStream.write(buffer, 0, read);
+ read = streamFromServer.read(buffer);
+ }
+ streamFromServer.close();
+ }
+
+ byteStream.flush();
+ byteStream.close();
+
+ bytes = byteStream.toByteArray();
+
+ if (bytes==null) {
+ log.error(id + " - bytes is NULL. No content
returned. bytes["+bytes+"]");
+ log.error(id + " - therefore setting it to some
random one byte value. ++++++++++++++++++++++++++++++");
+ bytes[0] = 0;
+ }
- byteStream.flush();
- byteStream.close();
+ log.debug(id + " - " + bytes.length + " bytes read");
- bytes = byteStream.toByteArray();
+ //TODO: NEED TO CHECK RESPONSE ESI HEADERS
+ }
+ catch (HttpException e )
+ //catch ( HttpRecoverableException e )
+ {
+ attempt++;
+ }
+ catch ( IOException e )
+ {
+ log.error(id + " - error: " + e);
+ throw new TransferFailedException( e.getMessage(), e );
+ }
- if (bytes==null) {
- log.error(id + " - bytes is NULL. No content returned.
bytes["+bytes+"]");
- log.error(id + " - therefore setting it to some random one
byte value. ++++++++++++++++++++++++++++++");
- bytes[0] = 0;
}
- log.debug(id + " - " + bytes.length + " bytes read");
+ // Check that we didn't run out of retries.
+ switch ( statusCode )
+ {
+ case HttpStatus.SC_OK:
+ break;
- //TODO: NEED TO CHECK RESPONSE ESI HEADERS
+ case HttpStatus.SC_CREATED:
+ break;
- } catch (Exception e) {
- log.error(id + " - error: " + e);
- } finally {
+ case SC_NULL:
+ throw new TransferFailedException(
+ "Failed to transfer file: " + urlToServer + "
after " + attempt + " attempts" );
+ case HttpStatus.SC_FORBIDDEN:
+ throw new TransferFailedException( "Access denided to: "
+ urlToServer );
+
+ case HttpStatus.SC_UNAUTHORIZED:
+ throw new TransferFailedException( "Not authorized." );
+
+ case HttpStatus.SC_NOT_FOUND:
+ throw new TransferFailedException( "File: " +
urlToServer + " does not exist" );
+
+ case HttpStatus.SC_NOT_MODIFIED:
+ log.error( "304 on File: " + urlToServer + " which is
IMPOSSIBLE ");
+ throw new TransferFailedException( "304 on File: " +
urlToServer + " which is IMPOSSIBLE " );
+ //add more entries here
+ default :
+ throw new TransferFailedException(
+ "Failed to transfer file: " + urlToServer + ".
Return code is: " + statusCode );
+ }
+
+ }
+ finally {
// always release the connection after we're done
methodToServer.releaseConnection();
log.debug(id + " - connection released");
@@ -389,9 +464,38 @@
parseEsiResponseHeaders();
}
+
return bytes;
}
+ /**
+ * We have to remove the client's If-conditional HTTP request headers
when fetching content which is not
+ * in the cache, otherwise we'll just get a 304 back and we won't have
any entries in the cache.
+ */
+ private void getRidOfConditionalHttpHeaders() {
+ String ifnonematch = "";
+ try {
+ if (methodToServer.getRequestHeader("if-none-match").getValue()
!=null) {
+ log.debug("removed if-none-match
["+methodToServer.getRequestHeader("if-none-match")+"] ");
+ methodToServer.removeRequestHeader("if-none-match");
+ }
+
+ } catch (Exception ex) {
+ //log.debug(" no if-none-match
["+methodToServer.getResponseHeader("if-none-match")+"] ex: "+ex);
+ }
+ String ifmodifiedsince = "";
+ try {
+ if
(methodToServer.getRequestHeader("if-modified-since").getValue() !=null) {
+ log.debug("removed if-modified-since
["+methodToServer.getRequestHeader("if-modified-since")+"] ");
+ methodToServer.removeRequestHeader("if-modified-since");
+ }
+
+ } catch (Exception ex) {
+ //log.debug(" no if-modified-since
["+methodToServer.getResponseHeader("if-modified-since")+"] ex: "+ex);
+ }
+
+ }
+
private static OrFilter EsiTagFilter = new OrFilter(
new NodeClassFilter (EsiIncludeTag.class),//new TagNameFilter
("esi:include")),
new NodeClassFilter (EsiRemoveTag.class)
@@ -405,12 +509,12 @@
}
private void removeAllAttributes(TagNode tag) {
- Vector v = tag.getAttributesEx();
+ Vector v = tag.getAttributesEx();
Enumeration enumAtt = v.elements();
while (enumAtt.hasMoreElements()) {
- Attribute att = (Attribute) enumAtt.nextElement();
- tag.removeAttribute(att.getName());
+ Attribute att = (Attribute) enumAtt.nextElement();
+ tag.removeAttribute(att.getName());
}
}