1 package org.apache.slide.projector.repository.webdav; 2 3 import java.io.IOException ; 4 import java.io.InputStream ; 5 import java.util.ArrayList ; 6 import java.util.Enumeration ; 7 import java.util.HashMap ; 8 import java.util.Iterator ; 9 import java.util.List ; 10 import java.util.Map ; 11 import java.util.Vector ; 12 import java.util.logging.Logger ; 13 14 import org.apache.commons.httpclient.Credentials; 15 import org.apache.commons.httpclient.Header; 16 import org.apache.commons.httpclient.HttpConnection; 17 import org.apache.commons.httpclient.HttpState; 18 import org.apache.commons.httpclient.HttpStatus; 19 import org.apache.commons.httpclient.UsernamePasswordCredentials; 20 import org.apache.commons.httpclient.methods.DeleteMethod; 21 import org.apache.commons.httpclient.methods.GetMethod; 22 import org.apache.commons.httpclient.methods.PutMethod; 23 import org.apache.commons.httpclient.protocol.Protocol; 24 import org.apache.slide.projector.Projector; 25 import org.apache.slide.projector.URI; 26 import org.apache.slide.projector.i18n.ErrorMessage; 27 import org.apache.slide.projector.repository.Configurable; 28 import org.apache.slide.projector.repository.Repository; 29 import org.apache.slide.projector.repository.RoleExistsException; 30 import org.apache.slide.projector.repository.UserExistsException; 31 import org.apache.slide.projector.value.ArrayValue; 32 import org.apache.slide.projector.value.ElementValue; 33 import org.apache.slide.projector.value.InputStreamValue; 34 import org.apache.slide.projector.value.MapValue; 35 import org.apache.slide.projector.value.NullValue; 36 import org.apache.slide.projector.value.StreamableValue; 37 import org.apache.slide.projector.value.StringValue; 38 import org.apache.slide.projector.value.URIValue; 39 import org.apache.slide.projector.value.Value; 40 import org.apache.slide.projector.value.XMLValue; 41 import org.apache.webdav.lib.NotificationListener; 42 import org.apache.webdav.lib.Property; 43 import org.apache.webdav.lib.PropertyName; 44 import org.apache.webdav.lib.Subscriber; 45 import org.apache.webdav.lib.methods.MkcolMethod; 46 import org.apache.webdav.lib.methods.PropFindMethod; 47 import org.apache.webdav.lib.methods.PropPatchMethod; 48 import org.apache.webdav.lib.methods.SearchMethod; 49 import org.jdom.Element; 50 import org.jdom.input.DOMBuilder; 51 import org.jdom.output.Format; 52 import org.jdom.output.XMLOutputter; 53 54 public class WebdavRepository implements Repository, Configurable { 55 private static Logger logger = Logger.getLogger(WebdavRepository.class.getName()); 56 57 private static final String SLIDE_NAMESPACE = "http://jakarta.apache.org/slide/"; 58 private static final String DAV_NAMESPACE = "DAV:"; 59 60 private Protocol protocol; 61 private String host, domain, notificationHost, users, roles; 62 private int port, notificationPort, notificationDelay, pollInterval, subscriptionLifetime; 63 64 private static WebdavRepository repository = new WebdavRepository(); 65 private NotificationListener dispatcher; 66 67 private WebdavRepository() {} 68 69 public static Repository getInstance() { 70 return repository; 71 } 72 73 public void configure(Element configuration) { 74 protocol = Protocol.getProtocol(configuration.getChildText("protocol")); 75 host = configuration.getChildText("host"); 76 port = Integer.valueOf(configuration.getChildText("port")).intValue(); 77 domain = configuration.getChildText("domain"); 78 users = configuration.getChildText("users"); 79 roles = configuration.getChildText("roles"); 80 Element notifications = configuration.getChild("notifications"); 81 notificationHost = notifications.getChildText("host"); 82 notificationPort = Integer.valueOf(notifications.getChildText("port")).intValue(); 83 pollInterval = Integer.valueOf(notifications.getChildText("poll-interval")).intValue(); 84 subscriptionLifetime = Integer.valueOf(notifications.getChildText("subscription-lifetime")).intValue(); 85 notificationDelay = Integer.valueOf(notifications.getChildText("notification-delay")).intValue(); 86 dispatcher = new NotificationListener(notificationHost, notificationPort, 87 host, port, protocol, Projector.getCredentials(), domain, pollInterval, true); 88 } 89 90 public Credentials login(String username, String password) throws IOException { 91 String url = domain+Projector.getProjectorDir(); 92 GetMethod getMethod = new GetMethod(url); 93 getMethod.setDoAuthentication(true); 94 Credentials credentials = new UsernamePasswordCredentials(username, password); 95 HttpState httpState = new HttpState(); 96 httpState.setCredentials(null, host, credentials); 97 int state = getMethod.execute(httpState, new HttpConnection(host, port, protocol)); 98 if ( state == HttpStatus.SC_OK ) { 99 return credentials; 100 } 101 return null; 102 } 103 104 public URI createUser(String username, String password, Credentials credentials) throws UserExistsException, IOException { 105 Value userExists = getResource(new URIValue(users+username), credentials); 106 if ( userExists == NullValue.NULL || userExists != null ) { 107 throw new UserExistsException(new ErrorMessage("userExists", new String [] { username })); 108 } else { 109 URI userUri = new URIValue(users+username); 110 MkcolMethod mkcolMethod = new MkcolMethod(domain+userUri.toString()); 111 mkcolMethod.setDoAuthentication(true); 112 HttpState httpState = new HttpState(); 113 httpState.setCredentials(null, host, credentials); 114 int state = mkcolMethod.execute(httpState, new HttpConnection(host, port, protocol)); 115 if ( state == HttpStatus.SC_CREATED ) { 116 changePassword(userUri, null, password, credentials); 117 return userUri; 118 } 119 return null; 120 } 121 } 122 123 public URI createRole(String rolename, Credentials credentials) throws RoleExistsException, IOException { 124 Value userExists = getResource(new URIValue(domain+roles+rolename), credentials); 125 if ( userExists == NullValue.NULL || userExists != null ) { 126 throw new RoleExistsException(new ErrorMessage("roleExists", new String [] { rolename })); 127 } else { 128 URI roleUri = new URIValue(roles+rolename); 129 MkcolMethod mkcolMethod = new MkcolMethod(domain+roleUri.toString()); 130 mkcolMethod.setDoAuthentication(true); 131 HttpState httpState = new HttpState(); 132 httpState.setCredentials(null, host, credentials); 133 int state = mkcolMethod.execute(httpState, new HttpConnection(host, port, protocol)); 134 if ( state == HttpStatus.SC_CREATED ) { 135 return roleUri; 136 } 137 return null; 138 } 139 } 140 141 public void deleteRole(URI role, Credentials credentials) throws IOException { 142 removeResource(role, credentials); 143 } 144 145 public void deleteUser(URI user, Credentials credentials) throws IOException { 146 removeResource(user, credentials); 147 } 148 149 public void addRole(URI user, URI role, Credentials credentials) throws IOException { 150 XMLValue roleElement = getPropertyAsXMLValue(role, DAV_NAMESPACE, "group-member-set", credentials); 151 Element newUserElement = new Element("href", "DAV:"); 152 newUserElement.addContent(user.toString()); 153 roleElement.getRootElement().addContent(newUserElement); 154 XMLOutputter xout = new XMLOutputter(Format.getCompactFormat()); 155 String groupMemberSet = xout.outputString(roleElement.getRootElement().getContent()); 156 setProperty(role, DAV_NAMESPACE, "group-member-set", groupMemberSet, credentials); 157 } 158 159 public void removeRole(URI user, URI role, Credentials credentials) throws IOException { 160 XMLValue membersElement = getPropertyAsXMLValue(role, DAV_NAMESPACE, "group-member-set", credentials); 161 List members = membersElement.getRootElement().getChildren(); 162 for ( Iterator i = members.iterator(); i.hasNext(); ) { 163 Element memberElement = (Element)i.next(); 164 String uri = memberElement.getTextTrim(); 165 if ( uri.equals(user.toString()) ) { 166 i.remove(); 167 break; 168 } 169 } 170 XMLOutputter xout = new XMLOutputter(Format.getCompactFormat()); 171 String groupMemberSet = xout.outputString(membersElement.getRootElement().getContent()); 172 setProperty(role, DAV_NAMESPACE, "group-member-set", groupMemberSet, credentials); 173 } 174 175 public ArrayValue listRoles(URI user, Credentials credentials) throws IOException { 176 XMLValue membership = getPropertyAsXMLValue(user, DAV_NAMESPACE, "group-membership", credentials); 177 List roles = membership.getRootElement().getChildren(); 178 List roleList = new ArrayList (); 179 for ( Iterator i = roles.iterator(); i.hasNext(); ) { 180 Map map = new HashMap (); 181 Element roleElement = (Element)i.next(); 182 String uri = roleElement.getTextTrim(); 183 if ( uri.indexOf(domain) != -1 ) { 184 uri = uri.substring(uri.indexOf(domain)+domain.length()); 185 } 186 map.put("uri", uri); 187 roleList.add(new MapValue(map)); 188 } 189 return new ArrayValue((Value [])roleList.toArray(new Value[roleList.size()])); 190 } 191 192 public void changePassword(URI uri, String oldPassword, String newPassword, Credentials credentials) throws IOException { 193 setProperty(uri, SLIDE_NAMESPACE, "password", newPassword, credentials); 194 } 195 196 public Value getResource(URI uri, Credentials credentials) throws IOException { 197 String url = domain+uri.toString(); 198 GetMethod getMethod = new GetMethod(url); 199 getMethod.setDoAuthentication(true); 200 HttpState httpState = new HttpState(); 201 httpState.setCredentials(null, host, credentials); 202 int state = getMethod.execute(httpState, new HttpConnection(host, port, protocol)); 203 if ( state != HttpStatus.SC_OK ) { 204 return null; 205 } 206 InputStream stream = getMethod.getResponseBodyAsStream(); 207 String contentType = getMethod.getResponseHeader("Content-type").getValue(); 208 String characterEncoding = getMethod.getResponseCharSet(); 209 Header contentLengthHeader = getMethod.getResponseHeader("Content-length"); 210 if ( contentLengthHeader == null ) return NullValue.NULL; 211 int contentLength = Integer.parseInt(getMethod.getResponseHeader("Content-length").getValue()); 212 return new InputStreamValue(stream, contentType, characterEncoding, contentLength, true); 213 } 214 215 public void setProperty(URI uri, String namespace, String name, String value, Credentials credentials) throws IOException { 216 PropPatchMethod proppatchMethod = new PropPatchMethod(domain+uri.toString()); 217 proppatchMethod.setDoAuthentication(true); 218 HttpState httpState = new HttpState(); 219 httpState.setCredentials(null, host, credentials); 220 proppatchMethod.addPropertyToSet(name, value, "S", namespace); 221 int state = proppatchMethod.execute(httpState, new HttpConnection(host, port, protocol)); 222 if ( state != HttpStatus.SC_MULTI_STATUS ) { 223 throw new IOException ("Received status code "+state+" when doing PROPPATH on URI="+uri); 224 } 225 } 226 227 public Value getPropertyAsStringValue(URI uri, String namespace, String name, Credentials credentials) throws IOException { 228 Property property = getProperty(uri, namespace, name, credentials); 229 if ( property == null ) return null; 230 return new StringValue(property.getPropertyAsString()); 231 } 232 233 public XMLValue getPropertyAsXMLValue(URI uri, String namespace, String name, Credentials credentials) throws IOException { 234 Property property = getProperty(uri, namespace, name, credentials); 235 if ( property == null ) return null; 236 DOMBuilder builder = new DOMBuilder(); 237 Element element = builder.build(property.getElement()); 238 return new ElementValue(element); 239 } 240 241 private Property getProperty(URI uri, String namespace, String name, Credentials credentials) throws IOException { 242 String url = domain+uri.toString(); 243 Vector props = new Vector (); 244 props.add(new PropertyName(namespace, name)); 245 PropFindMethod propfindMethod = new PropFindMethod(url, 0, props.elements()); 246 propfindMethod.setDoAuthentication(true); 247 HttpState httpState = new HttpState(); 248 httpState.setCredentials(null, host, credentials); 249 int state = propfindMethod.execute(httpState, new HttpConnection(host, port, protocol)); 250 if ( state != HttpStatus.SC_MULTI_STATUS ) { 251 throw new IOException ("Received status code "+state+" when doing PROPFIND on URI="+url); 252 } 253 Enumeration propertyEnumeration = propfindMethod.getResponseProperties(url); 254 if ( propertyEnumeration.hasMoreElements() ) { 255 return (Property)propertyEnumeration.nextElement(); 256 } 257 return null; 258 } 259 260 public ArrayValue getProperties(URI uri, Credentials credentials) throws IOException { 261 String url = domain+uri.toString(); 262 PropFindMethod propfindMethod = new PropFindMethod(url, 0); 263 propfindMethod.setDoAuthentication(true); 264 HttpState httpState = new HttpState(); 265 httpState.setCredentials(null, host, credentials); 266 int state = propfindMethod.execute(httpState, new HttpConnection(host, port, protocol)); 267 if ( state != HttpStatus.SC_MULTI_STATUS ) { 268 throw new IOException ("Received status code "+state+" when doing PROPFIND on URI="+url); 269 } 270 List arrayList = new ArrayList (); 271 for ( Enumeration propertyEnumeration = propfindMethod.getResponseProperties(url); propertyEnumeration.hasMoreElements(); ) { 272 Map properties = new HashMap (); 273 Property property = (Property)propertyEnumeration.nextElement(); 274 properties.put("name", new StringValue(property.getLocalName())); 275 properties.put("value", new StringValue(property.getPropertyAsString())); 276 arrayList.add(new MapValue(properties)); 277 } 278 Value[] resource = new Value[arrayList.size()]; 279 return new ArrayValue((Value[])arrayList.toArray(resource)); 280 } 281 282 public void setResource(URI uri, StreamableValue resource, Credentials credentials) throws IOException { 283 String url = domain+uri.toString(); 284 PutMethod putMethod = new PutMethod(url); 285 putMethod.setDoAuthentication(true); 286 HttpState httpState = new HttpState(); 287 httpState.setCredentials(null, host, credentials); 288 putMethod.setRequestBody(resource.getInputStream()); 289 putMethod.setRequestHeader("Content-type", resource.getContentType()); 290 putMethod.setRequestHeader("Content-length", String.valueOf(resource.getContentLength())); 291 putMethod.execute(httpState, new HttpConnection(host, port, protocol)); 292 } 293 294 public void removeResource(URI uri, Credentials credentials) throws IOException { 295 String url = domain+uri.toString(); 296 DeleteMethod deleteMethod = new DeleteMethod(url); 297 deleteMethod.setDoAuthentication(true); 298 HttpState httpState = new HttpState(); 299 httpState.setCredentials(null, host, credentials); 300 deleteMethod.execute(httpState, new HttpConnection(host, port, protocol)); 301 } 302 303 public ArrayValue getChildren(URI uri, Credentials credentials) throws IOException { 304 String url = domain+uri.toString(); 305 if ( url.charAt(url.length()-1) == '/') { 306 url = url.substring(0, url.length()-1); 307 } 308 PropFindMethod propfindMethod = new PropFindMethod(url, 0); 309 propfindMethod.setDepth(1); 310 propfindMethod.setDoAuthentication(true); 311 HttpState httpState = new HttpState(); 312 httpState.setCredentials(null, host, credentials); 313 int state = propfindMethod.execute(httpState, new HttpConnection(host, port, protocol)); 314 if ( state != HttpStatus.SC_MULTI_STATUS ) { 315 throw new IOException ("Received status code "+state+" when doing PROPFIND on URI="+url); 316 } 317 List children = new ArrayList (); 318 for ( Enumeration propertyEnumeration = propfindMethod.getAllResponseURLs(); propertyEnumeration.hasMoreElements(); ) { 319 String childUrl = (String )propertyEnumeration.nextElement(); 320 if ( !childUrl.equals(url) ) { 321 if ( childUrl.indexOf(domain) != -1 ) { 322 childUrl = childUrl.substring(childUrl.indexOf(domain)+domain.length()); 323 } 324 children.add(new URIValue(childUrl)); 325 } 326 } 327 return new ArrayValue((Value[])children.toArray(new Value[children.size()])); 328 } 329 330 public void subscribe(String method, URI uri, int depth, Subscriber listener, Credentials credentials) { 331 dispatcher.subscribe(method, uri.toString(), depth, subscriptionLifetime, notificationDelay, listener, credentials); 332 } 333 334 public void subscribe(String method, URI uri, int depth, int lifetime, int notificationDelay, Subscriber listener, Credentials credentials) { 335 dispatcher.subscribe(method, uri.toString(), depth, lifetime, notificationDelay, listener, credentials); 336 } 337 338 public void unsubscribe(URI uri, Subscriber listener, Credentials credentials) { 339 dispatcher.unsubscribe(uri.toString(), listener, credentials); 340 } 341 342 public void fireEvent(Map information, Credentials credentials) throws IOException { 343 dispatcher.fireEvent(information, credentials); 344 } 345 346 public void fireVetoableEvent(Map information, Credentials credentials) throws IOException { 347 dispatcher.fireVetoableEvent(information, credentials); 348 } 349 350 public Value[] search(String query, Credentials credentials) throws IOException { 351 String url = domain+"/"; 352 SearchMethod searchMethod = new SearchMethod(url, query); 353 searchMethod.setDoAuthentication(true); 354 HttpState httpState = new HttpState(); 355 httpState.setCredentials(null, host, credentials); 356 int state = searchMethod.execute(httpState, new HttpConnection(host, port, protocol)); 357 if ( state != HttpStatus.SC_MULTI_STATUS ) { 358 throw new IOException ("Received status code "+state+" when doing SEARCH with query="+query); 359 } 360 List values = new ArrayList (); 361 for ( Enumeration e = searchMethod.getAllResponseURLs(); e.hasMoreElements(); ) { 362 Map searchResults = new HashMap (); 363 String uri = (String )e.nextElement(); 364 for ( Enumeration pe = searchMethod.getResponseProperties(uri); pe.hasMoreElements(); ) { 365 Property property = (Property)pe.nextElement(); 366 searchResults.put(property.getLocalName(), property.getPropertyAsString()); 367 } 368 if ( uri.indexOf(domain) != -1 ) { 369 uri = uri.substring(uri.indexOf(domain)+domain.length()); 370 } 371 searchResults.put("uri", uri); 372 values.add(new MapValue(searchResults)); 373 } 374 return (Value [])values.toArray(new Value[values.size()]); 375 } 376 } | Popular Tags |