1 23 24 package org.apache.slide.webdav.method; 25 26 import java.io.IOException ; 27 import java.io.StringWriter ; 28 import java.io.Writer ; 29 import java.util.Date ; 30 import java.util.Enumeration ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 34 import javax.transaction.Transaction ; 35 36 import org.apache.slide.common.NamespaceAccessToken; 37 import org.apache.slide.common.NamespaceConfig; 38 import org.apache.slide.common.ServiceAccessException; 39 import org.apache.slide.common.SlideException; 40 import org.apache.slide.content.NodeRevisionContent; 41 import org.apache.slide.content.NodeRevisionDescriptor; 42 import org.apache.slide.content.NodeRevisionDescriptors; 43 import org.apache.slide.content.RevisionAlreadyExistException; 44 import org.apache.slide.content.RevisionDescriptorNotFoundException; 45 import org.apache.slide.event.VetoException; 46 import org.apache.slide.lock.NodeLock; 47 import org.apache.slide.lock.ObjectIsAlreadyLockedException; 48 import org.apache.slide.lock.ObjectLockedException; 49 import org.apache.slide.security.AccessDeniedException; 50 import org.apache.slide.structure.LinkedObjectNotFoundException; 51 import org.apache.slide.structure.ObjectAlreadyExistsException; 52 import org.apache.slide.structure.ObjectNotFoundException; 53 import org.apache.slide.structure.SubjectNode; 54 import org.apache.slide.transaction.ExternalTransactionContext; 55 import org.apache.slide.util.XMLValue; 56 import org.apache.slide.webdav.WebdavException; 57 import org.apache.slide.webdav.WebdavServletConfig; 58 import org.apache.slide.webdav.util.PropertyHelper; 59 import org.apache.slide.webdav.util.WebdavConstants; 60 import org.apache.slide.webdav.util.WebdavStatus; 61 import org.jdom.Element; 62 import org.jdom.JDOMException; 63 import org.jdom.output.XMLOutputter; 64 65 69 public class LockMethod extends AbstractMultistatusResponseMethod implements 70 WebdavConstants, WriteMethod { 71 72 74 77 private static final int LOCK_CREATION = 0; 78 79 82 private static final int LOCK_REFRESH = 1; 83 84 87 private static final int MAX_TIMEOUT = Integer.MAX_VALUE; 88 89 private static final int DEFAULT_TIMEOUT = MAX_TIMEOUT; 90 91 94 public static final String DEFAULT_LOCK_OWNER = ""; 95 96 98 101 private int depth; 102 103 106 private int lockType; 107 108 111 private int lockDuration = DEFAULT_TIMEOUT; 112 113 116 private String lockInfo_lockScope; 117 118 121 private String lockInfo_lockType; 122 123 126 private String lockInfo_lockOwner; 127 128 131 private String lockInfo_lockSubject; 132 133 136 protected PropertyHelper propertyHelper = null; 137 138 140 148 public LockMethod(NamespaceAccessToken token, WebdavServletConfig config) { 149 super(token, config); 150 } 151 152 154 160 protected void parseRequest() throws WebdavException { 161 162 propertyHelper = PropertyHelper.getPropertyHelper(slideToken, token, 163 getConfig()); 164 166 lockInfo_lockSubject = requestUri; 168 if (lockInfo_lockSubject == null) { 169 lockInfo_lockSubject = "/"; 170 } 171 172 depth = requestHeaders.getDepth(INFINITY); 173 if (depth != 0 && depth != INFINITY) { 174 int sc = WebdavStatus.SC_PRECONDITION_FAILED; 175 sendError(sc, "Invalid header Depth: " + depth); 176 throw new WebdavException(sc); 177 } 178 179 lockDuration = requestHeaders.getTimeout(MAX_TIMEOUT); 180 181 if (req.getContentLength() > 0 || isRequestChunked()) { 182 parseLockInfo(); 183 } else { 184 lockType = LOCK_REFRESH; 185 } 186 187 } 188 189 195 private void parseLockInfo() throws WebdavException { 196 197 lockType = LOCK_CREATION; 198 199 try { 200 Iterator childrenIterator = parseRequestContent(E_LOCKINFO) 201 .getChildren().iterator(); 202 while (childrenIterator.hasNext()) { 203 Element currentElement = (Element) childrenIterator.next(); 204 if (E_LOCKSCOPE.equals(currentElement.getName())) { 205 parseLockScope(currentElement); 206 } else if (E_LOCKTYPE.equals(currentElement.getName())) { 207 parseLockType(currentElement); 208 } else if (E_OWNER.equals(currentElement.getName())) { 209 parseOwner(currentElement); 210 } 211 } 212 } catch (JDOMException e) { 213 int statusCode = WebdavStatus.SC_BAD_REQUEST; 214 sendError(statusCode, e); 215 throw new WebdavException(statusCode); 216 } catch (IOException e) { 217 int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR; 218 sendError(statusCode, e); 219 throw new WebdavException(statusCode); 220 } 221 } 222 223 233 private void parseLockScope(Element lockScopeElement) throws JDOMException { 234 if (lockScopeElement == null) { 235 throw new JDOMException("Expected <" + E_LOCKSCOPE + "> element"); 236 } 237 238 List children = lockScopeElement.getChildren(); 239 if (children.size() != 1) { 240 throw new JDOMException("<" + E_LOCKSCOPE 241 + "> must have exactly one child element"); 242 } 243 244 lockInfo_lockScope = ((Element) children.get(0)).getName(); 245 if (!(E_EXCLUSIVE.equals(lockInfo_lockScope) 246 || E_SHARED.equals(lockInfo_lockScope) || E_LOCAL 247 .equals(lockInfo_lockScope))) { 248 throw new JDOMException("<" + E_LOCKSCOPE 249 + "> can only contain one of <" + E_EXCLUSIVE + "> or <" 250 + E_SHARED + "> or <" + E_LOCAL + ">"); 251 } 252 } 253 254 264 private void parseLockType(Element lockTypeElement) throws JDOMException { 265 266 if (lockTypeElement == null) { 267 throw new JDOMException("Expected <" + E_LOCKTYPE + "> element"); 268 } 269 270 List children = lockTypeElement.getChildren(); 271 if (children.size() != 1) { 272 throw new JDOMException("<" + E_LOCKTYPE 273 + "> must have exactly one child element"); 274 } 275 String lockTypeName = ((Element) children.get(0)).getName(); 276 if (!E_WRITE.equals(lockTypeName) 277 && !E_TRANSACTION.equals(lockTypeName)) { 278 throw new JDOMException( 279 "Only write and transaction locks are supported"); 280 } 281 lockInfo_lockType = ((Element) children.get(0)).getName(); 282 } 283 284 294 private void parseOwner(Element ownerElement) throws JDOMException { 295 296 if (ownerElement == null) { 297 lockInfo_lockOwner = DEFAULT_LOCK_OWNER; 298 return; 299 } 301 302 StringWriter stringWriter = new StringWriter (); 303 XMLOutputter xmlOutputter = new XMLOutputter(); 304 try { 305 xmlOutputter.outputElementContent(ownerElement, stringWriter); 306 } catch (IOException e) { 307 e.printStackTrace(); 310 } 311 lockInfo_lockOwner = stringWriter.toString(); 312 313 if (lockInfo_lockOwner.length() == 0) { 314 lockInfo_lockOwner = DEFAULT_LOCK_OWNER; 315 } 318 } 319 320 326 protected void executeRequest() throws WebdavException { 327 328 slideToken.setForceStoreEnlistment(true); 330 331 SubjectNode toLockSubject = null; 332 boolean isCollection = isCollection(lockInfo_lockSubject); 333 boolean inheritance = false; 334 Date lockDate = null; 335 336 337 switch (lockType) { 338 339 case LOCK_CREATION: 340 if (lockInfo_lockType.equals(E_TRANSACTION)) { 341 try { 342 NamespaceConfig namespaceConfig = token 343 .getNamespaceConfig(); 344 toLockSubject = getToLockSubject(); 345 if (lockDate == null) 346 lockDate = new Date ((new Date ()).getTime() 347 + ((long) lockDuration * 1000L)); 348 NodeLock lockToken = new NodeLock(toLockSubject.getUri(),((SubjectNode)security.getPrincipal(slideToken)).getUri(), 349 namespaceConfig.getCreateObjectAction().getUri(), lockDate, 350 inheritance, NodeLock.LOCAL, lockInfo_lockOwner); 351 token.setTransactionTimeout(lockDuration * 1000); 352 Transaction transaction = token.getTransactionManager().suspend(); 353 String fullTxId = "<" + S_LOCK_TOKEN + lockToken.getLockId() + ">"; 355 ExternalTransactionContext.registerContext(fullTxId, transaction); 356 slideToken.setExternalTx(); 357 resp.setHeader("Lock-Token", fullTxId); 358 showLockDiscoveryInfo(lockToken); 359 } catch (Exception e) { 360 int statusCode = getErrorCode(e); 361 sendError(statusCode, e); 362 throw new WebdavException(statusCode); 363 } 364 } else if (lockInfo_lockType.equals(E_WRITE)) { 365 try { 366 367 if (!checkIfHeaders()) { 368 return; 369 } 370 371 NamespaceConfig namespaceConfig = token 372 .getNamespaceConfig(); 373 toLockSubject = getToLockSubject(); 374 NodeLock lockToken = null; 375 376 inheritance = (depth != 0); 377 boolean exclusive = !(lockInfo_lockScope.equals(E_SHARED)); 378 379 if (lockDate == null) 380 lockDate = new Date ((new Date ()).getTime() 381 + ((long) lockDuration * 1000L)); 382 383 lockToken = new NodeLock(toLockSubject, 384 (SubjectNode) security.getPrincipal(slideToken), 385 namespaceConfig.getCreateObjectAction(), lockDate, 386 inheritance, exclusive, lockInfo_lockOwner); 387 lock.lock(slideToken, lockToken); 388 389 resp.setHeader("Lock-Token", "<" + S_LOCK_TOKEN 396 + lockToken.getLockId() + ">"); 397 398 resp.setStatus(WebdavStatus.SC_OK); 399 400 402 showLockDiscoveryInfo(lockToken); 403 } catch (ObjectIsAlreadyLockedException e) { 404 if (inheritance 405 && generateMultiStatusResponse(isCollection, e, 406 requestUri)) { 407 String errorMessage = generateErrorMessage(e); 409 resp.setContentType(TEXT_XML_UTF_8); 411 resp.setStatus(WebdavStatus.SC_MULTI_STATUS); 412 try { 413 resp.getWriter().write(errorMessage); 414 } catch (IOException ex) { 415 int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR; 418 sendError(statusCode, e); 419 throw new WebdavException(statusCode); 420 } 421 } else { 422 resp.setStatus(WebdavStatus.SC_LOCKED); 426 } 427 throw new WebdavException(WebdavStatus.SC_ACCEPTED, false); 433 } catch (Exception e) { 434 int statusCode = getErrorCode(e); 435 sendError(statusCode, e); 436 throw new WebdavException(statusCode); 437 } 438 } 439 break; 440 441 case LOCK_REFRESH: 442 443 try { 444 445 Enumeration lockTokens = lock.enumerateLocks(slideToken, 446 lockInfo_lockSubject, false); 447 448 NodeLock currentLockToken = null; 449 Date newExpirationDate = new Date ((new Date ()).getTime() 450 + ((long) lockDuration * 1000L)); 451 while (lockTokens.hasMoreElements()) { 452 currentLockToken = (NodeLock) lockTokens.nextElement(); 453 lock.renew(slideToken, currentLockToken, newExpirationDate); 454 } 455 456 showLockDiscoveryInfo(currentLockToken); 457 458 } catch (SlideException e) { 459 int statusCode = WebdavStatus.SC_PRECONDITION_FAILED; 460 sendError(statusCode, e); 461 throw new WebdavException(statusCode); 462 } 463 464 break; 465 466 } 467 468 } 469 470 protected SubjectNode getToLockSubject() throws ObjectAlreadyExistsException, ObjectNotFoundException, 471 AccessDeniedException, RevisionAlreadyExistException, LinkedObjectNotFoundException, ObjectLockedException, 472 ServiceAccessException, VetoException { 473 474 SubjectNode toLockSubject; 475 try { 476 toLockSubject = (SubjectNode) structure.retrieve(slideToken, lockInfo_lockSubject); 477 } catch (ObjectNotFoundException ex) { 478 479 toLockSubject = new SubjectNode(); 481 482 structure.create(slideToken, toLockSubject, lockInfo_lockSubject); 484 485 NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(0); 486 487 XMLValue lockNull = new XMLValue(new Element(E_LOCKNULL, DNSP)); 489 revisionDescriptor.setResourceType(lockNull.toString()); 490 491 NodeRevisionContent nrc = new NodeRevisionContent(); 492 nrc.setContent(new byte[0]); 493 494 content.create(slideToken, lockInfo_lockSubject, revisionDescriptor, nrc); 496 } 497 return toLockSubject; 498 } 499 500 503 protected int getErrorCode(Exception ex) { 504 try { 505 throw ex; 506 } catch (ObjectNotFoundException e) { 507 return WebdavStatus.SC_PRECONDITION_FAILED; 508 } catch (Exception e) { 509 return super.getErrorCode(e); 510 } 511 } 512 513 519 protected void showLockDiscoveryInfo(NodeLock token) throws WebdavException { 520 521 org.jdom.Element prop = new org.jdom.Element(E_PROP, DNSP); 523 org.jdom.Element lockdiscovery = new org.jdom.Element(E_LOCKDISCOVERY, 524 DNSP); 525 prop.addContent(lockdiscovery); 526 XMLValue xmlValue = propertyHelper.computeLockDiscovery(token, 527 getSlideContextPath()); 528 Iterator iterator = xmlValue.iterator(); 529 while (iterator.hasNext()) { 530 lockdiscovery.addContent((org.jdom.Element) iterator.next()); 531 } 532 533 try { 534 resp.setContentType(TEXT_XML_UTF_8); 537 Writer writer = resp.getWriter(); 538 org.jdom.output.Format format = org.jdom.output.Format 539 .getPrettyFormat(); 540 format.setIndent(XML_RESPONSE_INDENT); 541 new org.jdom.output.XMLOutputter(format).output( 542 new org.jdom.Document(prop), writer); 543 writer.flush(); 544 } catch (Exception e) { 545 int statusCode = WebdavStatus.SC_INTERNAL_SERVER_ERROR; 546 sendError(statusCode, e); 547 throw new WebdavException(statusCode); 548 } 549 550 } 551 552 private boolean checkIfHeaders() throws AccessDeniedException, LinkedObjectNotFoundException, ServiceAccessException, ObjectLockedException, VetoException, IOException 553 { 554 try { 555 NodeRevisionDescriptors revisionDescriptors = 556 content.retrieve(slideToken, this.requestUri); 557 NodeRevisionDescriptor revisionDescriptor = 559 content.retrieve(slideToken, revisionDescriptors); 560 if (revisionDescriptor != null) { 561 ResourceInfo resourceInfo = 562 new ResourceInfo(this.requestUri, revisionDescriptor); 563 return checkIfHeaders(req, resp, resourceInfo); 564 } else { 565 return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri)); 566 } 567 } 568 catch (RevisionDescriptorNotFoundException e) { 569 return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri)); 570 } 571 catch (ObjectNotFoundException e) { 572 return checkIfHeaders(req, resp, new ResourceInfo(this.requestUri)); 573 } 574 } 575 } 576 577 | Popular Tags |