1 16 package org.outerj.daisy.repository.clientimpl.infrastructure; 17 18 import org.apache.commons.httpclient.*; 19 import org.apache.xmlbeans.XmlObject; 20 import org.apache.xmlbeans.XmlOptions; 21 import org.outerj.daisy.repository.RepositoryException; 22 import org.outerj.daisy.repository.AuthenticationFailedException; 23 import org.outerj.daisy.xmlutil.LocalSAXParserFactory; 24 import org.outerx.daisy.x10.ErrorDocument; 25 import org.outerx.daisy.x10.CauseType; 26 27 import java.util.Map ; 28 import java.util.ArrayList ; 29 import java.util.HashMap ; 30 import java.lang.reflect.Method ; 31 import java.lang.reflect.Constructor ; 32 import java.lang.reflect.InvocationTargetException ; 33 34 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 35 36 public class DaisyHttpClient { 37 private static Map xmlObjectParseMethodCache = new ConcurrentReaderHashMap(); 38 private static final boolean validateResponses = false; 39 private HttpClient sharedHttpClient; 40 private HttpState httpState; 41 private HostConfiguration sharedHostConfiguration; 42 43 public DaisyHttpClient(HttpClient sharedHttpClient, HostConfiguration sharedHostConfiguration, HttpState httpState) { 44 this.sharedHttpClient = sharedHttpClient; 45 this.httpState = httpState; 46 this.sharedHostConfiguration = sharedHostConfiguration; 47 } 48 49 59 public XmlObject executeMethod(HttpMethod method, Class xmlObjectResponseClass, boolean releaseConnection) throws RepositoryException { 60 try { 61 int statusCode; 62 try { 63 statusCode = sharedHttpClient.executeMethod(sharedHostConfiguration, method, httpState); 64 } catch (Exception e) { 65 throw new RepositoryException("Problems connecting to repository server.", e); 66 } 67 68 if (statusCode == HttpStatus.SC_OK) { 69 if (xmlObjectResponseClass != null) { 70 Method parseMethod = getParseMethod(xmlObjectResponseClass); 71 XmlObject parseResult = null; 72 try { 73 parseResult = (XmlObject)parseMethod.invoke(null, new Object [] {method.getResponseBodyAsStream()}); 74 if (validateResponses) 75 parseResult.validate(); 76 } catch (Exception e) { 77 throw new RepositoryException("Error parsing reponse from repository server.", e); 78 } 79 80 return parseResult; 81 } else { 82 return null; 83 } 84 } else { 85 handleNotOkResponse(method); 86 throw new RuntimeException ("This statement should be unreacheable."); 88 } 89 } finally { 90 if (releaseConnection) 91 method.releaseConnection(); 92 } 93 } 94 95 private static Method getParseMethod(Class xmlObjectClass) { 96 Object parseMethod = xmlObjectParseMethodCache.get(xmlObjectClass); 97 if (parseMethod != null) { 98 return (Method )parseMethod; 99 } else { 100 Class [] classes = xmlObjectClass.getClasses(); 101 Class factoryClass = null; 102 for (int i = 0; i < classes.length; i++) { 103 if (classes[i].getName().equals(xmlObjectClass.getName() + "$Factory")) { 104 factoryClass = classes[i]; 105 break; 106 } 107 } 108 109 if (factoryClass == null) { 110 throw new RuntimeException ("Missing Factory class in class " + xmlObjectClass.getName()); 111 } 112 113 Method newParseMethod = null; 114 try { 115 newParseMethod = factoryClass.getMethod("parse", new Class [] {java.io.InputStream .class}); 116 } catch (NoSuchMethodException e) { 117 throw new RuntimeException ("Missing parse method on XmlObject Factory class for " + xmlObjectClass.getName(), e); 118 } 119 120 xmlObjectParseMethodCache.put(xmlObjectClass, newParseMethod); 121 return newParseMethod; 122 } 123 } 124 125 public static String getContentType(HttpMethod method) throws RepositoryException { 126 String contentType = null; 127 try { 128 if (method.getResponseHeader("Content-Type") != null) 129 contentType = method.getResponseHeader("Content-Type").getValues()[0].getName(); 130 } catch (HttpException e) { 131 throw new RepositoryException("Error getting Content-Type of the reponse.", e); 132 } 133 return contentType; 134 } 135 136 public void handleNotOkResponse(HttpMethod method) throws RepositoryException { 137 if ("text/xml".equals(getContentType(method))) { 138 ErrorDocument.Error errorXml = null; 140 try { 141 XmlOptions xmlOptions = new XmlOptions().setLoadUseXMLReader(LocalSAXParserFactory.newXmlReader()); 142 ErrorDocument errorDocument = ErrorDocument.Factory.parse(method.getResponseBodyAsStream(), xmlOptions); 143 errorXml = errorDocument.getError(); 144 } catch (Exception e) { 145 throw new RepositoryException("Error reading error response from repositoryserver", e); 146 } 147 if (errorXml.getDescription() != null) { 148 throw new RepositoryException("Repository server answered with an error: " + errorXml.getDescription()); 149 } else { 150 CauseType causeXml = errorXml.getCause(); 151 if (causeXml.getExceptionData() != null) 152 tryRestoreOriginalException(causeXml); 153 Exception cause = restoreException(causeXml); 154 throw new RepositoryException("Received exception from repository server.", cause); 155 } 156 } else { 157 if (method.getStatusCode() == 401) { 158 throw new AuthenticationFailedException(((UsernamePasswordCredentials)httpState.getCredentials(null, null)).getUserName()); 159 } else { 160 throw new RepositoryException("Unexpected response from repositoryserver: " + method.getStatusCode() + " : " + HttpStatus.getStatusText(method.getStatusCode())); 161 } 162 } 163 } 164 165 private static Exception restoreException(CauseType causeXml) { 166 String message = causeXml.getException().getMessage(); 167 String className = causeXml.getException().getType(); 168 169 ArrayList stackTrace = new ArrayList (); 170 CauseType.StackTrace.StackTraceElement[] stackTraceElements = causeXml.getStackTrace().getStackTraceElementArray(); 171 for (int i = 0; i < stackTraceElements.length; i++) { 172 CauseType.StackTrace.StackTraceElement stackTraceElement = stackTraceElements[i]; 173 stackTrace.add(new MyStackTraceElement(stackTraceElement.getClassName(), stackTraceElement.getFileName(), stackTraceElement.getLineNumber(), stackTraceElement.getMethodName(), stackTraceElement.getNativeMethod())); 174 } 175 MyStackTraceElement[] remoteStackTrace = (MyStackTraceElement[])stackTrace.toArray(new MyStackTraceElement[stackTrace.size()]); 176 177 DaisyPropagatedException exception = new DaisyPropagatedException(message, className, remoteStackTrace); 178 179 CauseType nestedCauseXml = causeXml.getCause(); 180 if (nestedCauseXml != null) { 181 Exception cause = restoreException(nestedCauseXml); 182 exception.initCause(cause); 183 } 184 185 return exception; 186 } 187 188 197 private static void tryRestoreOriginalException(CauseType causeXml) throws RepositoryException { 198 String className = causeXml.getException().getType(); 199 CauseType.ExceptionData exceptionData = causeXml.getExceptionData(); 200 201 Map state = new HashMap (); 202 CauseType.ExceptionData.Parameter[] parameters = exceptionData.getParameterArray(); 203 for (int i = 0; i < parameters.length; i++) { 204 state.put(parameters[i].getName(), parameters[i].getValue()); 205 } 206 207 Class clazz = null; 208 try { 209 clazz = DaisyHttpClient.class.getClassLoader().loadClass(className); 210 } catch (ClassNotFoundException e) { 211 return; 212 } 213 214 if (!RepositoryException.class.isAssignableFrom(clazz)) 215 return; 216 217 Constructor constructor = null; 218 try { 219 constructor = clazz.getConstructor(new Class [] {Map .class}); 220 } catch (NoSuchMethodException e) { 221 return; 222 } 223 224 RepositoryException restoredException = null; 225 try { 226 restoredException = (RepositoryException)constructor.newInstance(new Object [] {state}); 227 } catch (InstantiationException e) { 228 } catch (IllegalAccessException e) { 230 } catch (InvocationTargetException e) { 232 } 234 235 if (causeXml.getCause() != null) { 236 Exception cause = restoreException(causeXml.getCause()); 237 restoredException.initCause(cause); 238 } 239 240 if (restoredException != null) { 241 throw restoredException; 242 } 243 } 244 } 245 | Popular Tags |