You can subscribe to this list here.
| 2004 |
Jan
|
Feb
|
Mar
(57) |
Apr
(103) |
May
(164) |
Jun
(139) |
Jul
(173) |
Aug
(196) |
Sep
(221) |
Oct
(333) |
Nov
(214) |
Dec
(88) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2005 |
Jan
(163) |
Feb
(165) |
Mar
(98) |
Apr
(93) |
May
(199) |
Jun
(118) |
Jul
(200) |
Aug
(212) |
Sep
(185) |
Oct
(297) |
Nov
(437) |
Dec
(272) |
| 2006 |
Jan
(542) |
Feb
(329) |
Mar
(267) |
Apr
(332) |
May
(267) |
Jun
(130) |
Jul
(161) |
Aug
(348) |
Sep
(166) |
Oct
(305) |
Nov
(173) |
Dec
(173) |
| 2007 |
Jan
(199) |
Feb
(118) |
Mar
(133) |
Apr
(200) |
May
(208) |
Jun
(146) |
Jul
(198) |
Aug
(146) |
Sep
(187) |
Oct
(182) |
Nov
(181) |
Dec
(83) |
| 2008 |
Jan
(252) |
Feb
(124) |
Mar
(124) |
Apr
(101) |
May
(143) |
Jun
(122) |
Jul
(129) |
Aug
(60) |
Sep
(80) |
Oct
(89) |
Nov
(54) |
Dec
(112) |
| 2009 |
Jan
(88) |
Feb
(145) |
Mar
(105) |
Apr
(164) |
May
(123) |
Jun
(154) |
Jul
(374) |
Aug
(341) |
Sep
(219) |
Oct
(137) |
Nov
(373) |
Dec
(240) |
| 2010 |
Jan
(197) |
Feb
(270) |
Mar
(253) |
Apr
(150) |
May
(102) |
Jun
(51) |
Jul
(300) |
Aug
(512) |
Sep
(254) |
Oct
(258) |
Nov
(288) |
Dec
(143) |
| 2011 |
Jan
(238) |
Feb
(179) |
Mar
(253) |
Apr
(332) |
May
(248) |
Jun
(255) |
Jul
(216) |
Aug
(282) |
Sep
(146) |
Oct
(77) |
Nov
(86) |
Dec
(69) |
| 2012 |
Jan
(172) |
Feb
(234) |
Mar
(229) |
Apr
(101) |
May
(212) |
Jun
(267) |
Jul
(129) |
Aug
(210) |
Sep
(239) |
Oct
(271) |
Nov
(368) |
Dec
(220) |
| 2013 |
Jan
(179) |
Feb
(155) |
Mar
(59) |
Apr
(47) |
May
(99) |
Jun
(158) |
Jul
(185) |
Aug
(16) |
Sep
(16) |
Oct
(7) |
Nov
(20) |
Dec
(12) |
| 2014 |
Jan
(21) |
Feb
(17) |
Mar
(18) |
Apr
(13) |
May
(27) |
Jun
(15) |
Jul
(19) |
Aug
(22) |
Sep
(30) |
Oct
(16) |
Nov
(19) |
Dec
(16) |
| 2015 |
Jan
(14) |
Feb
(24) |
Mar
(33) |
Apr
(41) |
May
(14) |
Jun
(80) |
Jul
(53) |
Aug
(8) |
Sep
(7) |
Oct
(15) |
Nov
(13) |
Dec
(2) |
| 2016 |
Jan
(22) |
Feb
(12) |
Mar
(30) |
Apr
(6) |
May
(33) |
Jun
(16) |
Jul
(8) |
Aug
(20) |
Sep
(12) |
Oct
(18) |
Nov
(12) |
Dec
(11) |
| 2017 |
Jan
(24) |
Feb
(26) |
Mar
(47) |
Apr
(23) |
May
(19) |
Jun
(14) |
Jul
(28) |
Aug
(30) |
Sep
(17) |
Oct
|
Nov
|
Dec
|
| 2019 |
Jan
(1) |
Feb
(73) |
Mar
(90) |
Apr
(42) |
May
(116) |
Jun
(90) |
Jul
(127) |
Aug
(103) |
Sep
(56) |
Oct
(42) |
Nov
(95) |
Dec
(58) |
| 2020 |
Jan
(102) |
Feb
(31) |
Mar
(93) |
Apr
(60) |
May
(57) |
Jun
(45) |
Jul
(29) |
Aug
(32) |
Sep
(44) |
Oct
(86) |
Nov
(51) |
Dec
(71) |
| 2021 |
Jan
(44) |
Feb
(25) |
Mar
(78) |
Apr
(130) |
May
(64) |
Jun
(74) |
Jul
(21) |
Aug
(64) |
Sep
(40) |
Oct
(43) |
Nov
(21) |
Dec
(99) |
| 2022 |
Jan
(154) |
Feb
(64) |
Mar
(45) |
Apr
(95) |
May
(62) |
Jun
(48) |
Jul
(73) |
Aug
(37) |
Sep
(71) |
Oct
(27) |
Nov
(40) |
Dec
(65) |
| 2023 |
Jan
(89) |
Feb
(130) |
Mar
(124) |
Apr
(50) |
May
(93) |
Jun
(46) |
Jul
(45) |
Aug
(68) |
Sep
(62) |
Oct
(71) |
Nov
(108) |
Dec
(82) |
| 2024 |
Jan
(53) |
Feb
(76) |
Mar
(64) |
Apr
(75) |
May
(36) |
Jun
(54) |
Jul
(98) |
Aug
(137) |
Sep
(58) |
Oct
(177) |
Nov
(84) |
Dec
(52) |
| 2025 |
Jan
(70) |
Feb
(53) |
Mar
(72) |
Apr
(47) |
May
(88) |
Jun
(49) |
Jul
(86) |
Aug
(51) |
Sep
(65) |
Oct
(91) |
Nov
(18) |
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
1
(5) |
2
(5) |
3
(7) |
4
(5) |
5
(5) |
6
|
|
7
(4) |
8
|
9
(3) |
10
(3) |
11
|
12
(2) |
13
(3) |
|
14
(2) |
15
(1) |
16
(2) |
17
|
18
(2) |
19
(7) |
20
(5) |
|
21
(1) |
22
(5) |
23
(4) |
24
(1) |
25
|
26
(3) |
27
|
|
28
(6) |
29
(12) |
30
(15) |
31
(4) |
|
|
|
|
From: <del...@us...> - 2008-12-31 15:18:52
|
Revision: 8456
http://exist.svn.sourceforge.net/exist/?rev=8456&view=rev
Author: deliriumsky
Date: 2008-12-31 15:18:48 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
equals support
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java 2008-12-31 15:18:30 UTC (rev 8455)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java 2008-12-31 15:18:48 UTC (rev 8456)
@@ -344,7 +344,41 @@
// TODO Auto-generated method stub
return null;
}
-
+
+ public boolean equals(Object obj)
+ {
+ EXistXQItemType otherItemType = null;
+
+ if(obj instanceof EXistXQItemType)
+ otherItemType = (EXistXQItemType)obj;
+ else
+ return false;
+
+
+
+ if(otherItemType.itemKind != itemKind)
+ return false;
+
+ if(otherItemType.baseType != baseType)
+ return false;
+
+ if(!otherItemType.nodeName.equals(nodeName))
+ return false;
+
+ if(!otherItemType.typeName.equals(typeName))
+ return false;
+
+ if(!otherItemType.typeSchemaURI.equals(typeSchemaURI))
+ return false;
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return itemKind ^ baseType ^ nodeName.hashCode() ^ typeName.hashCode() ^ typeSchemaURI.hashCode();
+ }
+
public Object clone()
{
EXistXQItemType newItemType = new EXistXQItemType();
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-31 15:18:34
|
Revision: 8455
http://exist.svn.sourceforge.net/exist/?rev=8455&view=rev
Author: deliriumsky
Date: 2008-12-31 15:18:30 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
equals support
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java 2008-12-31 08:37:48 UTC (rev 8454)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java 2008-12-31 15:18:30 UTC (rev 8455)
@@ -349,6 +349,91 @@
this.scrollability = scrollability;
}
+ public boolean equals(Object obj)
+ {
+ EXistXQStaticContext otherStaticContext = null;
+
+ if(obj instanceof EXistXQStaticContext)
+ otherStaticContext = (EXistXQStaticContext)obj;
+ else
+ return false;
+
+
+ if(otherStaticContext.scrollability != scrollability)
+ return false;
+
+ if(otherStaticContext.holdability != holdability)
+ return false;
+
+ if(!otherStaticContext.namespaces.equals(namespaces))
+ return false;
+
+ if(otherStaticContext.baseURI != baseURI)
+ return false;
+
+ if(otherStaticContext.bindingMode != bindingMode)
+ return false;
+
+ if(otherStaticContext.constructionMode != constructionMode)
+ return false;
+
+ if(otherStaticContext.orderingMode != orderingMode)
+ return false;
+
+ if(otherStaticContext.queryTimeout != queryTimeout)
+ return false;
+
+ if(otherStaticContext.defaultCollation != defaultCollation)
+ return false;
+
+ if(otherStaticContext.defaultElementTypeNamespace != defaultElementTypeNamespace)
+ return false;
+
+ if(otherStaticContext.defaultFunctionNamespace != defaultFunctionNamespace)
+ return false;
+
+ if(!otherStaticContext.ctxtItemType.equals(ctxtItemType))
+ return false;
+
+ if(otherStaticContext.copyNamespacesModeInherit != copyNamespacesModeInherit)
+ return false;
+
+ if(otherStaticContext.copyNamespacesModePreserve != copyNamespacesModePreserve)
+ return false;
+
+ if(otherStaticContext.boundarySpacePolicy != boundarySpacePolicy)
+ return false;
+
+ if(otherStaticContext.defaultOrderForEmptySequence != defaultOrderForEmptySequence)
+ return false;
+
+ if(otherStaticContext.langType != langType)
+ return false;
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return
+ (scrollability + holdability) ^
+ namespaces.hashCode() ^
+ baseURI.hashCode() ^
+ bindingMode ^
+ constructionMode ^
+ orderingMode ^
+ queryTimeout ^
+ defaultCollation.hashCode() ^
+ defaultElementTypeNamespace.hashCode() ^
+ defaultFunctionNamespace.hashCode() ^
+ ctxtItemType.hashCode() ^
+ copyNamespacesModeInherit ^
+ copyNamespacesModePreserve ^
+ boundarySpacePolicy ^
+ defaultOrderForEmptySequence ^
+ langType;
+ }
+
public Object clone() throws CloneNotSupportedException
{
EXistXQStaticContext newContext = new EXistXQStaticContext();
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <sha...@us...> - 2008-12-31 08:37:52
|
Revision: 8454
http://exist.svn.sourceforge.net/exist/?rev=8454&view=rev
Author: shabanovd
Date: 2008-12-31 08:37:48 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
[feature] fixing bug and adding support to use as key at HashMap (HashSet and so on)
Modified Paths:
--------------
branches/shabanovd/karma/src/org/exist/numbering/DLN.java
branches/shabanovd/karma/src/org/exist/numbering/DLNBase.java
branches/shabanovd/karma/src/org/exist/numbering/NodeId.java
branches/shabanovd/karma/test/src/org/exist/numbering/DLNTest.java
Modified: branches/shabanovd/karma/src/org/exist/numbering/DLN.java
===================================================================
--- branches/shabanovd/karma/src/org/exist/numbering/DLN.java 2008-12-31 00:10:53 UTC (rev 8453)
+++ branches/shabanovd/karma/src/org/exist/numbering/DLN.java 2008-12-31 08:37:48 UTC (rev 8454)
@@ -289,10 +289,6 @@
return getLevelCount(0);
}
- public boolean equals(NodeId other) {
- return super.equals((DLNBase) other);
- }
-
public int compareTo(Object other) {
return compareTo((DLN) other);
}
Modified: branches/shabanovd/karma/src/org/exist/numbering/DLNBase.java
===================================================================
--- branches/shabanovd/karma/src/org/exist/numbering/DLNBase.java 2008-12-31 00:10:53 UTC (rev 8453)
+++ branches/shabanovd/karma/src/org/exist/numbering/DLNBase.java 2008-12-31 08:37:48 UTC (rev 8454)
@@ -463,6 +463,13 @@
return Arrays.equals(bits, other.bits);
}
+ public boolean equals(Object other) {
+ if (other instanceof DLNBase) {
+ return equals((DLNBase) other);
+ }
+ return false;
+ }
+
// public int compareTo(final DLNBase other) {
// if (other == null)
// return 1;
@@ -572,4 +579,10 @@
}
return new String(buf);
}
+
+ //adding to work as key at map
+ public int hashCode() {
+ //TODO: optimize
+ return toString().hashCode();
+ }
}
Modified: branches/shabanovd/karma/src/org/exist/numbering/NodeId.java
===================================================================
--- branches/shabanovd/karma/src/org/exist/numbering/NodeId.java 2008-12-31 00:10:53 UTC (rev 8453)
+++ branches/shabanovd/karma/src/org/exist/numbering/NodeId.java 2008-12-31 08:37:48 UTC (rev 8454)
@@ -177,8 +177,6 @@
int compareTo(NodeId other);
- boolean equals(NodeId other);
-
/**
* Returns the size (in bytes) of this node id. Depends on
* the concrete implementation.
Modified: branches/shabanovd/karma/test/src/org/exist/numbering/DLNTest.java
===================================================================
--- branches/shabanovd/karma/test/src/org/exist/numbering/DLNTest.java 2008-12-31 00:10:53 UTC (rev 8453)
+++ branches/shabanovd/karma/test/src/org/exist/numbering/DLNTest.java 2008-12-31 08:37:48 UTC (rev 8454)
@@ -24,6 +24,8 @@
import junit.framework.TestCase;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Random;
public class DLNTest extends TestCase {
@@ -345,4 +347,29 @@
System.out.println("------ testInsertion: PASSED ------");
}
+
+ public void testHash() {
+ System.out.println("------ testHash ------");
+ Map<DLN, String> map = new HashMap<DLN, String>();
+
+ DLN fisrt = new DLN("1.1");
+ DLN second = new DLN("1.1");
+ assertEquals(fisrt.toString(), second.toString());
+ assertEquals(fisrt.hashCode(), second.hashCode());
+ assertTrue(fisrt.equals(second));
+
+ map.put(fisrt, fisrt.toString());
+ String maped = map.get(second);
+ assertNotNull(maped);
+ assertEquals("1.1", maped);
+
+
+ second = new DLN("1.2");
+ assertNotSame(fisrt.toString(), second.toString());
+ assertNotSame(fisrt.hashCode(), second.hashCode());
+
+
+
+ System.out.println("------ testHash: PASSED ------");
+ }
}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <wol...@us...> - 2008-12-31 00:10:58
|
Revision: 8453
http://exist.svn.sourceforge.net/exist/?rev=8453&view=rev
Author: wolfgang_m
Date: 2008-12-31 00:10:53 +0000 (Wed, 31 Dec 2008)
Log Message:
-----------
[feature] versioning extension: display revisions through web admin client.
Modified Paths:
--------------
trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/versioning.xqm
trunk/eXist/webapp/admin/admin.css
trunk/eXist/webapp/admin/admin.xql
trunk/eXist/webapp/admin/browse.xqm
Added Paths:
-----------
trunk/eXist/webapp/admin/scripts/
trunk/eXist/webapp/admin/scripts/admin.js
trunk/eXist/webapp/admin/scripts/prettify.js
trunk/eXist/webapp/admin/scripts/utilities.js
trunk/eXist/webapp/admin/styles/
trunk/eXist/webapp/admin/styles/prettify.css
trunk/eXist/webapp/admin/versions.xql
trunk/eXist/webapp/admin/versions.xqm
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java 2008-12-30 21:47:32 UTC (rev 8452)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java 2008-12-31 00:10:53 UTC (rev 8453)
@@ -107,7 +107,7 @@
SAXSerializer.class);
Properties outputProperties = new Properties();
outputProperties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
- outputProperties.setProperty(OutputKeys.INDENT, "yes");
+ outputProperties.setProperty(OutputKeys.INDENT, "no");
sax.setOutput(writer, outputProperties);
sax.startDocument();
sax.startElement(DIFF_ELEMENT, null);
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/versioning.xqm
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/versioning.xqm 2008-12-30 21:47:32 UTC (rev 8452)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/versioning.xqm 2008-12-31 00:10:53 UTC (rev 8453)
@@ -4,6 +4,9 @@
at "java:org.exist.versioning.xquery.VersioningModule";
import module namespace util="http://exist-db.org/xquery/util";
+declare function v:version-collection($collectionPath as xs:string) as xs:string {
+ concat("/db/system/versions/", replace($collectionPath, "^/?(.*)$", "$1"))
+};
declare function v:list-revisions($root as node()) as xs:long* {
let $collection := util:collection-name($root)
@@ -16,6 +19,16 @@
$rev
};
+declare function v:list-versions($root as node()) as element(v:version)* {
+ let $collection := util:collection-name($root)
+ let $docName := util:document-name($root)
+ let $vCollection := concat("/db/system/versions", $collection)
+ for $version in collection($vCollection)/v:version[v:properties[v:document = $docName]]
+ order by xs:long($version/v:properties/v:revision) ascending
+ return
+ $version
+};
+
declare function v:get-revision($root as node(), $rev as xs:long) {
let $collection := util:collection-name($root)
let $docName := util:document-name($root)
Modified: trunk/eXist/webapp/admin/admin.css
===================================================================
--- trunk/eXist/webapp/admin/admin.css 2008-12-30 21:47:32 UTC (rev 8452)
+++ trunk/eXist/webapp/admin/admin.css 2008-12-31 00:10:53 UTC (rev 8453)
@@ -93,18 +93,18 @@
#status td.key {
}
-#browse {
+.browse {
margin-left: 15px;
font-size: smaller;
border-bottom: 1px solid black;
}
-#browse th {
+.browse th {
text-align: left;
border-bottom: 1px solid black;
}
-#browse td.perm {
+.browse td.perm {
font-family: Courier, monospace;
}
@@ -189,3 +189,12 @@
.high {
color: #00ff00;
}
+
+.diffsource {
+ width: 600px;
+ overflow: auto;
+}
+
+.revisions {
+ width: 620px;
+}
Modified: trunk/eXist/webapp/admin/admin.xql
===================================================================
--- trunk/eXist/webapp/admin/admin.xql 2008-12-30 21:47:32 UTC (rev 8452)
+++ trunk/eXist/webapp/admin/admin.xql 2008-12-31 00:10:53 UTC (rev 8453)
@@ -17,7 +17,10 @@
import module namespace xqueries = "http://exist-db.org/xquery/admin-interface/xqueries" at "xqueries.xqm";
import module namespace shut = "http://exist-db.org/xquery/admin-interface/shutdown" at "shutdown.xqm";
import module namespace setup = "http://exist-db.org/xquery/admin-interface/setup" at "setup.xqm";
+import module namespace rev="http://exist-db.org/xquery/admin-interface/revisions" at "versions.xqm";
+declare option exist:serialize "method=xhtml media-type=text/html";
+
(:
Display the version, SVN revision and user info in the top right corner
:)
@@ -59,6 +62,10 @@
(
setup:main()
)
+ else if ($panel eq "revisions") then
+ (
+ rev:main()
+ )
else
(
status:main()
@@ -140,8 +147,12 @@
<head>
<title>eXist Database Administration</title>
<link type="text/css" href="admin.css" rel="stylesheet"/>
+ <link type="text/css" href="styles/prettify.css" rel="stylesheet"/>
<link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>
+ <script type="text/javascript" src="scripts/prettify.js"/>
+ <script type="text/javascript" src="scripts/utilities.js"></script>
+ <script type="text/javascript" src="scripts/admin.js"></script>
</head>
<body>
<div class="header">
@@ -178,4 +189,4 @@
}
</div>
</body>
- </html>
\ No newline at end of file
+ </html>
Modified: trunk/eXist/webapp/admin/browse.xqm
===================================================================
--- trunk/eXist/webapp/admin/browse.xqm 2008-12-30 21:47:32 UTC (rev 8452)
+++ trunk/eXist/webapp/admin/browse.xqm 2008-12-31 00:10:53 UTC (rev 8453)
@@ -9,6 +9,7 @@
declare namespace request="http://exist-db.org/xquery/request";
declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace util="http://exist-db.org/xquery/util";
+declare namespace v="http://exist-db.org/versioning";
import module namespace date="http://exist-db.org/xquery/admin-interface/date" at "dates.xqm";
@@ -200,7 +201,7 @@
:)
declare function browse:display-collection($colName as xs:string) as element()
{
- <table cellspacing="0" cellpadding="5" id="browse">
+ <table cellspacing="0" cellpadding="5" class="browse">
<tr>
<th/>
<th>Name</th>
@@ -210,6 +211,7 @@
<th>Created</th>
<th>Modified</th>
<th>Size (KB)</th>
+ <th>Revision</th>
</tr>
<tr>
<td/>
@@ -220,6 +222,7 @@
<td/>
<td/>
<td/>
+ <td/>
</tr>
{
browse:display-child-collections($colName),
@@ -243,12 +246,14 @@
<td>{date:format-dateTime($created)}</td>
<td/>
<td/>
+ <td/>
</tr>
};
declare function browse:display-child-resources($colName as xs:string) as element()*
{
- for $child in xdb:get-child-resources($colName) order by $child return
+ for $child in xdb:get-child-resources($colName) order by $child
+ return
<tr>
<td><input type="checkbox" name="resource" value="{$colName}/{$child}"/></td>
<td><a target="_new" href="../rest/{xdb:encode-uri($colName)}/{xdb:encode-uri($child)}">{xdb:decode-uri(xs:anyURI($child))}</a></td>
@@ -258,9 +263,26 @@
<td>{date:format-dateTime(xdb:created($colName, $child))}</td>
<td>{date:format-dateTime(xdb:last-modified($colName, $child))}</td>
<td>{fn:ceiling(xdb:size($colName, $child) div 1024)}</td>
+ <td>
+ <a href="?panel=revisions&resource={$colName}/{$child}">
+ {browse:last-revision($colName, $child)//v:properties/v:revision/string()}
+ </a>
+ </td>
</tr>
};
+declare function browse:last-revision($collection as xs:string, $resource as xs:string) {
+ let $vCollection := concat("/db/system/versions", $collection)
+ let $versions :=
+ for $version in collection($vCollection)/v:version[
+ v:properties[v:document = $resource]
+ ]
+ order by xs:long($version/v:properties/v:revision) descending
+ return $version
+ return
+ $versions[1]
+};
+
(:
Get the name of the parent collection from a specified collection path.
:)
@@ -270,4 +292,4 @@
$path
else
replace($path, "/[^/]*$", "")
-};
\ No newline at end of file
+};
Added: trunk/eXist/webapp/admin/scripts/admin.js
===================================================================
--- trunk/eXist/webapp/admin/scripts/admin.js (rev 0)
+++ trunk/eXist/webapp/admin/scripts/admin.js 2008-12-31 00:10:53 UTC (rev 8453)
@@ -0,0 +1,39 @@
+var Dom = YAHOO.util.Dom;
+
+function displayDiff(id, resource, revision) {
+ var div = document.getElementById(id);
+ if (Dom.getStyle(div, 'display') == 'none')
+ Dom.setStyle(div, 'display', '');
+ else
+ Dom.setStyle(div, 'display', 'none');
+
+ if (div.innerHTML == '') {
+ var callback = {
+ success: function (response) {
+ document.getElementById(id).innerHTML =
+ '<pre class="prettyprint lang-xml">' +
+ escapeXML(response.responseText) +
+ '</pre>';
+ prettyPrint();
+ },
+ failure: function (response) {
+ alert('Failed to retrieve diff: ' + response.responseText);
+ }
+ };
+ var url = 'versions.xql?action=diff&resource=' + resource + '&rev=' + revision;
+ YAHOO.util.Connect.asyncRequest('GET', url, callback);
+ }
+ return false;
+}
+
+function escapeXML(xml) {
+ var out = '';
+ for (var i = 0; i < xml.length; i++) {
+ ch = xml.charAt(i);
+ if (ch == '<') out += '<'
+ else if (ch == '>') out += '>'
+ else if (ch == '&') out += '&'
+ else out += ch;
+ }
+ return out;
+}
Added: trunk/eXist/webapp/admin/scripts/prettify.js
===================================================================
--- trunk/eXist/webapp/admin/scripts/prettify.js (rev 0)
+++ trunk/eXist/webapp/admin/scripts/prettify.js 2008-12-31 00:10:53 UTC (rev 8453)
@@ -0,0 +1,1275 @@
+// Copyright (C) 2006 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/**
+ * @fileoverview
+ * some functions for browser-side pretty printing of code contained in html.
+ *
+ * The lexer should work on a number of languages including C and friends,
+ * Java, Python, Bash, SQL, HTML, XML, CSS, Javascript, and Makefiles.
+ * It works passably on Ruby, PHP and Awk and a decent subset of Perl, but,
+ * because of commenting conventions, doesn't work on Smalltalk, Lisp-like, or
+ * CAML-like languages.
+ *
+ * If there's a language not mentioned here, then I don't know it, and don't
+ * know whether it works. If it has a C-like, Bash-like, or XML-like syntax
+ * then it should work passably.
+ *
+ * Usage:
+ * 1) include this source file in an html page via
+ * <script type="text/javascript" src="/path/to/prettify.js"></script>
+ * 2) define style rules. See the example page for examples.
+ * 3) mark the <pre> and <code> tags in your source with class=prettyprint.
+ * You can also use the (html deprecated) <xmp> tag, but the pretty printer
+ * needs to do more substantial DOM manipulations to support that, so some
+ * css styles may not be preserved.
+ * That's it. I wanted to keep the API as simple as possible, so there's no
+ * need to specify which language the code is in.
+ *
+ * Change log:
+ * cbeust, 2006/08/22
+ * Java annotations (start with "@") are now captured as literals ("lit")
+ */
+
+// JSLint declarations
+/*global console, document, navigator, setTimeout, window */
+
+/**
+ * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
+ * UI events.
+ * If set to {@code false}, {@code prettyPrint()} is synchronous.
+ */
+var PR_SHOULD_USE_CONTINUATION = true;
+
+/** the number of characters between tab columns */
+var PR_TAB_WIDTH = 8;
+
+/** Walks the DOM returning a properly escaped version of innerHTML.
+ * @param {Node} node
+ * @param {Array.<string>} out output buffer that receives chunks of HTML.
+ */
+var PR_normalizedHtml;
+
+/** Contains functions for creating and registering new language handlers.
+ * @type {Object}
+ */
+var PR;
+
+/** Pretty print a chunk of code.
+ *
+ * @param {string} sourceCodeHtml code as html
+ * @return {string} code as html, but prettier
+ */
+var prettyPrintOne;
+/** find all the < pre > and < code > tags in the DOM with class=prettyprint
+ * and prettify them.
+ * @param {Function} opt_whenDone if specified, called when the last entry
+ * has been finished.
+ */
+var prettyPrint;
+
+/** browser detection. @extern */
+function _pr_isIE6() {
+ var isIE6 = navigator && navigator.userAgent &&
+ /\bMSIE 6\./.test(navigator.userAgent);
+ _pr_isIE6 = function () { return isIE6; };
+ return isIE6;
+}
+
+
+(function () {
+ /** Splits input on space and returns an Object mapping each non-empty part to
+ * true.
+ */
+ function wordSet(words) {
+ words = words.split(/ /g);
+ var set = {};
+ for (var i = words.length; --i >= 0;) {
+ var w = words[i];
+ if (w) { set[w] = null; }
+ }
+ return set;
+ }
+
+ // Keyword lists for various languages.
+ var FLOW_CONTROL_KEYWORDS =
+ "break continue do else for if return while ";
+ var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
+ "double enum extern float goto int long register short signed sizeof " +
+ "static struct switch typedef union unsigned void volatile ";
+ var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
+ "new operator private protected public this throw true try ";
+ var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
+ "concept concept_map const_cast constexpr decltype " +
+ "dynamic_cast explicit export friend inline late_check " +
+ "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
+ "template typeid typename typeof using virtual wchar_t where ";
+ var JAVA_KEYWORDS = COMMON_KEYWORDS +
+ "boolean byte extends final finally implements import instanceof null " +
+ "native package strictfp super synchronized throws transient ";
+ var CSHARP_KEYWORDS = JAVA_KEYWORDS +
+ "as base by checked decimal delegate descending event " +
+ "fixed foreach from group implicit in interface internal into is lock " +
+ "object out override orderby params readonly ref sbyte sealed " +
+ "stackalloc string select uint ulong unchecked unsafe ushort var ";
+ var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
+ "debugger eval export function get null set undefined var with " +
+ "Infinity NaN ";
+ var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
+ "goto if import last local my next no our print package redo require " +
+ "sub undef unless until use wantarray while BEGIN END ";
+ var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
+ "elif except exec finally from global import in is lambda " +
+ "nonlocal not or pass print raise try with yield " +
+ "False True None ";
+ var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
+ " defined elsif end ensure false in module next nil not or redo rescue " +
+ "retry self super then true undef unless until when yield BEGIN END ";
+ var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
+ "function in local set then until ";
+ var ALL_KEYWORDS = (
+ CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
+ PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
+
+ // token style names. correspond to css classes
+ /** token style for a string literal */
+ var PR_STRING = 'str';
+ /** token style for a keyword */
+ var PR_KEYWORD = 'kwd';
+ /** token style for a comment */
+ var PR_COMMENT = 'com';
+ /** token style for a type */
+ var PR_TYPE = 'typ';
+ /** token style for a literal value. e.g. 1, null, true. */
+ var PR_LITERAL = 'lit';
+ /** token style for a punctuation string. */
+ var PR_PUNCTUATION = 'pun';
+ /** token style for a punctuation string. */
+ var PR_PLAIN = 'pln';
+
+ /** token style for an sgml tag. */
+ var PR_TAG = 'tag';
+ /** token style for a markup declaration such as a DOCTYPE. */
+ var PR_DECLARATION = 'dec';
+ /** token style for embedded source. */
+ var PR_SOURCE = 'src';
+ /** token style for an sgml attribute name. */
+ var PR_ATTRIB_NAME = 'atn';
+ /** token style for an sgml attribute value. */
+ var PR_ATTRIB_VALUE = 'atv';
+
+ /**
+ * A class that indicates a section of markup that is not code, e.g. to allow
+ * embedding of line numbers within code listings.
+ */
+ var PR_NOCODE = 'nocode';
+
+ function isWordChar(ch) {
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
+ }
+
+ /** Splice one array into another.
+ * Like the python <code>
+ * container[containerPosition:containerPosition + countReplaced] = inserted
+ * </code>
+ * @param {Array} inserted
+ * @param {Array} container modified in place
+ * @param {Number} containerPosition
+ * @param {Number} countReplaced
+ */
+ function spliceArrayInto(
+ inserted, container, containerPosition, countReplaced) {
+ inserted.unshift(containerPosition, countReplaced || 0);
+ try {
+ container.splice.apply(container, inserted);
+ } finally {
+ inserted.splice(0, 2);
+ }
+ }
+
+ /** A set of tokens that can precede a regular expression literal in
+ * javascript.
+ * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
+ * list, but I've removed ones that might be problematic when seen in
+ * languages that don't support regular expression literals.
+ *
+ * <p>Specifically, I've removed any keywords that can't precede a regexp
+ * literal in a syntactically legal javascript program, and I've removed the
+ * "in" keyword since it's not a keyword in many languages, and might be used
+ * as a count of inches.
+ * @private
+ */
+ var REGEXP_PRECEDER_PATTERN = function () {
+ var preceders = [
+ "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
+ "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
+ "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
+ "<", "<<", "<<=", "<=", "=", "==", "===", ">",
+ ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
+ "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
+ "||=", "~" /* handles =~ and !~ */,
+ "break", "case", "continue", "delete",
+ "do", "else", "finally", "instanceof",
+ "return", "throw", "try", "typeof"
+ ];
+ var pattern = '(?:' +
+ '(?:(?:^|[^0-9.])\\.{1,3})|' + // a dot that's not part of a number
+ '(?:(?:^|[^\\+])\\+)|' + // allow + but not ++
+ '(?:(?:^|[^\\-])-)'; // allow - but not --
+ for (var i = 0; i < preceders.length; ++i) {
+ var preceder = preceders[i];
+ if (isWordChar(preceder.charAt(0))) {
+ pattern += '|\\b' + preceder;
+ } else {
+ pattern += '|' + preceder.replace(/([^=<>:&])/g, '\\$1');
+ }
+ }
+ pattern += '|^)\\s*$'; // matches at end, and matches empty string
+ return new RegExp(pattern);
+ // CAVEAT: this does not properly handle the case where a regular
+ // expression immediately follows another since a regular expression may
+ // have flags for case-sensitivity and the like. Having regexp tokens
+ // adjacent is not
+ // valid in any language I'm aware of, so I'm punting.
+ // TODO: maybe style special characters inside a regexp as punctuation.
+ }();
+
+ // Define regexps here so that the interpreter doesn't have to create an
+ // object each time the function containing them is called.
+ // The language spec requires a new object created even if you don't access
+ // the $1 members.
+ var pr_amp = /&/g;
+ var pr_lt = /</g;
+ var pr_gt = />/g;
+ var pr_quot = /\"/g;
+ /** like textToHtml but escapes double quotes to be attribute safe. */
+ function attribToHtml(str) {
+ return str.replace(pr_amp, '&')
+ .replace(pr_lt, '<')
+ .replace(pr_gt, '>')
+ .replace(pr_quot, '"');
+ }
+
+ /** escapest html special characters to html. */
+ function textToHtml(str) {
+ return str.replace(pr_amp, '&')
+ .replace(pr_lt, '<')
+ .replace(pr_gt, '>');
+ }
+
+
+ var pr_ltEnt = /</g;
+ var pr_gtEnt = />/g;
+ var pr_aposEnt = /'/g;
+ var pr_quotEnt = /"/g;
+ var pr_ampEnt = /&/g;
+ var pr_nbspEnt = / /g;
+ /** unescapes html to plain text. */
+ function htmlToText(html) {
+ var pos = html.indexOf('&');
+ if (pos < 0) { return html; }
+ // Handle numeric entities specially. We can't use functional substitution
+ // since that doesn't work in older versions of Safari.
+ // These should be rare since most browsers convert them to normal chars.
+ for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
+ var end = html.indexOf(';', pos);
+ if (end >= 0) {
+ var num = html.substring(pos + 3, end);
+ var radix = 10;
+ if (num && num.charAt(0) === 'x') {
+ num = num.substring(1);
+ radix = 16;
+ }
+ var codePoint = parseInt(num, radix);
+ if (!isNaN(codePoint)) {
+ html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
+ html.substring(end + 1));
+ }
+ }
+ }
+
+ return html.replace(pr_ltEnt, '<')
+ .replace(pr_gtEnt, '>')
+ .replace(pr_aposEnt, "'")
+ .replace(pr_quotEnt, '"')
+ .replace(pr_ampEnt, '&')
+ .replace(pr_nbspEnt, ' ');
+ }
+
+ /** is the given node's innerHTML normally unescaped? */
+ function isRawContent(node) {
+ return 'XMP' === node.tagName;
+ }
+
+ function normalizedHtml(node, out) {
+ switch (node.nodeType) {
+ case 1: // an element
+ var name = node.tagName.toLowerCase();
+ out.push('<', name);
+ for (var i = 0; i < node.attributes.length; ++i) {
+ var attr = node.attributes[i];
+ if (!attr.specified) { continue; }
+ out.push(' ');
+ normalizedHtml(attr, out);
+ }
+ out.push('>');
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ normalizedHtml(child, out);
+ }
+ if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
+ out.push('<\/', name, '>');
+ }
+ break;
+ case 2: // an attribute
+ out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"');
+ break;
+ case 3: case 4: // text
+ out.push(textToHtml(node.nodeValue));
+ break;
+ }
+ }
+
+ var PR_innerHtmlWorks = null;
+ function getInnerHtml(node) {
+ // inner html is hopelessly broken in Safari 2.0.4 when the content is
+ // an html description of well formed XML and the containing tag is a PRE
+ // tag, so we detect that case and emulate innerHTML.
+ if (null === PR_innerHtmlWorks) {
+ var testNode = document.createElement('PRE');
+ testNode.appendChild(
+ document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
+ PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
+ }
+
+ if (PR_innerHtmlWorks) {
+ var content = node.innerHTML;
+ // XMP tags contain unescaped entities so require special handling.
+ if (isRawContent(node)) {
+ content = textToHtml(content);
+ }
+ return content;
+ }
+
+ var out = [];
+ for (var child = node.firstChild; child; child = child.nextSibling) {
+ normalizedHtml(child, out);
+ }
+ return out.join('');
+ }
+
+ /** returns a function that expand tabs to spaces. This function can be fed
+ * successive chunks of text, and will maintain its own internal state to
+ * keep track of how tabs are expanded.
+ * @return {function (string) : string} a function that takes
+ * plain text and return the text with tabs expanded.
+ * @private
+ */
+ function makeTabExpander(tabWidth) {
+ var SPACES = ' ';
+ var charInLine = 0;
+
+ return function (plainText) {
+ // walk over each character looking for tabs and newlines.
+ // On tabs, expand them. On newlines, reset charInLine.
+ // Otherwise increment charInLine
+ var out = null;
+ var pos = 0;
+ for (var i = 0, n = plainText.length; i < n; ++i) {
+ var ch = plainText.charAt(i);
+
+ switch (ch) {
+ case '\t':
+ if (!out) { out = []; }
+ out.push(plainText.substring(pos, i));
+ // calculate how much space we need in front of this part
+ // nSpaces is the amount of padding -- the number of spaces needed
+ // to move us to the next column, where columns occur at factors of
+ // tabWidth.
+ var nSpaces = tabWidth - (charInLine % tabWidth);
+ charInLine += nSpaces;
+ for (; nSpaces >= 0; nSpaces -= SPACES.length) {
+ out.push(SPACES.substring(0, nSpaces));
+ }
+ pos = i + 1;
+ break;
+ case '\n':
+ charInLine = 0;
+ break;
+ default:
+ ++charInLine;
+ }
+ }
+ if (!out) { return plainText; }
+ out.push(plainText.substring(pos));
+ return out.join('');
+ };
+ }
+
+ // The below pattern matches one of the following
+ // (1) /[^<]+/ : A run of characters other than '<'
+ // (2) /<!--.*?-->/: an HTML comment
+ // (3) /<!\[CDATA\[.*?\]\]>/: a cdata section
+ // (3) /<\/?[a-zA-Z][^>]*>/ : A probably tag that should not be highlighted
+ // (4) /</ : A '<' that does not begin a larger chunk. Treated as 1
+ var pr_chunkPattern =
+ /(?:[^<]+|<!--[\s\S]*?-->|<!\[CDATA\[([\s\S]*?)\]\]>|<\/?[a-zA-Z][^>]*>|<)/g;
+ var pr_commentPrefix = /^<!--/;
+ var pr_cdataPrefix = /^<\[CDATA\[/;
+ var pr_brPrefix = /^<br\b/i;
+ var pr_tagNameRe = /^<(\/?)([a-zA-Z]+)/;
+
+ /** split markup into chunks of html tags (style null) and
+ * plain text (style {@link #PR_PLAIN}), converting tags which are
+ * significant for tokenization (<br>) into their textual equivalent.
+ *
+ * @param {string} s html where whitespace is considered significant.
+ * @return {Object} source code and extracted tags.
+ * @private
+ */
+ function extractTags(s) {
+ // since the pattern has the 'g' modifier and defines no capturing groups,
+ // this will return a list of all chunks which we then classify and wrap as
+ // PR_Tokens
+ var matches = s.match(pr_chunkPattern);
+ var sourceBuf = [];
+ var sourceBufLen = 0;
+ var extractedTags = [];
+ if (matches) {
+ for (var i = 0, n = matches.length; i < n; ++i) {
+ var match = matches[i];
+ if (match.length > 1 && match.charAt(0) === '<') {
+ if (pr_commentPrefix.test(match)) { continue; }
+ if (pr_cdataPrefix.test(match)) {
+ // strip CDATA prefix and suffix. Don't unescape since it's CDATA
+ sourceBuf.push(match.substring(9, match.length - 3));
+ sourceBufLen += match.length - 12;
+ } else if (pr_brPrefix.test(match)) {
+ // <br> tags are lexically significant so convert them to text.
+ // This is undone later.
+ sourceBuf.push('\n');
+ ++sourceBufLen;
+ } else {
+ if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
+ // A <span class="nocode"> will start a section that should be
+ // ignored. Continue walking the list until we see a matching end
+ // tag.
+ var name = match.match(pr_tagNameRe)[2];
+ var depth = 1;
+ end_tag_loop:
+ for (var j = i + 1; j < n; ++j) {
+ var name2 = matches[j].match(pr_tagNameRe);
+ if (name2 && name2[2] === name) {
+ if (name2[1] === '/') {
+ if (--depth === 0) { break end_tag_loop; }
+ } else {
+ ++depth;
+ }
+ }
+ }
+ if (j < n) {
+ extractedTags.push(
+ sourceBufLen, matches.slice(i, j + 1).join(''));
+ i = j;
+ } else { // Ignore unclosed sections.
+ extractedTags.push(sourceBufLen, match);
+ }
+ } else {
+ extractedTags.push(sourceBufLen, match);
+ }
+ }
+ } else {
+ var literalText = htmlToText(match);
+ sourceBuf.push(literalText);
+ sourceBufLen += literalText.length;
+ }
+ }
+ }
+ return { source: sourceBuf.join(''), tags: extractedTags };
+ }
+
+ /** True if the given tag contains a class attribute with the nocode class. */
+ function isNoCodeTag(tag) {
+ return !!tag
+ // First canonicalize the representation of attributes
+ .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
+ ' $1="$2$3$4"')
+ // Then look for the attribute we want.
+ .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
+ }
+
+ /** Given triples of [style, pattern, context] returns a lexing function,
+ * The lexing function interprets the patterns to find token boundaries and
+ * returns a decoration list of the form
+ * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
+ * where index_n is an index into the sourceCode, and style_n is a style
+ * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to
+ * all characters in sourceCode[index_n-1:index_n].
+ *
+ * The stylePatterns is a list whose elements have the form
+ * [style : string, pattern : RegExp, context : RegExp, shortcut : string].
+ &
+ * Style is a style constant like PR_PLAIN.
+ *
+ * Pattern must only match prefixes, and if it matches a prefix and context
+ * is null or matches the last non-comment token parsed, then that match is
+ * considered a token with the same style.
+ *
+ * Context is applied to the last non-whitespace, non-comment token
+ * recognized.
+ *
+ * Shortcut is an optional string of characters, any of which, if the first
+ * character, gurantee that this pattern and only this pattern matches.
+ *
+ * @param {Array} shortcutStylePatterns patterns that always start with
+ * a known character. Must have a shortcut string.
+ * @param {Array} fallthroughStylePatterns patterns that will be tried in
+ * order if the shortcut ones fail. May have shortcuts.
+ *
+ * @return {function (string, number?) : Array.<number|string>} a
+ * function that takes source code and returns a list of decorations.
+ */
+ function createSimpleLexer(shortcutStylePatterns,
+ fallthroughStylePatterns) {
+ var shortcuts = {};
+ (function () {
+ var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
+ for (var i = allPatterns.length; --i >= 0;) {
+ var patternParts = allPatterns[i];
+ var shortcutChars = patternParts[3];
+ if (shortcutChars) {
+ for (var c = shortcutChars.length; --c >= 0;) {
+ shortcuts[shortcutChars.charAt(c)] = patternParts;
+ }
+ }
+ }
+ })();
+
+ var nPatterns = fallthroughStylePatterns.length;
+ var notWs = /\S/;
+
+ return function (sourceCode, opt_basePos) {
+ opt_basePos = opt_basePos || 0;
+ var decorations = [opt_basePos, PR_PLAIN];
+ var lastToken = '';
+ var pos = 0; // index into sourceCode
+ var tail = sourceCode;
+
+ while (tail.length) {
+ var style;
+ var token = null;
+ var match;
+
+ var patternParts = shortcuts[tail.charAt(0)];
+ if (patternParts) {
+ match = tail.match(patternParts[1]);
+ token = match[0];
+ style = patternParts[0];
+ } else {
+ for (var i = 0; i < nPatterns; ++i) {
+ patternParts = fallthroughStylePatterns[i];
+ var contextPattern = patternParts[2];
+ if (contextPattern && !contextPattern.test(lastToken)) {
+ // rule can't be used
+ continue;
+ }
+ match = tail.match(patternParts[1]);
+ if (match) {
+ token = match[0];
+ style = patternParts[0];
+ break;
+ }
+ }
+
+ if (!token) { // make sure that we make progress
+ style = PR_PLAIN;
+ token = tail.substring(0, 1);
+ }
+ }
+
+ decorations.push(opt_basePos + pos, style);
+ pos += token.length;
+ tail = tail.substring(token.length);
+ if (style !== PR_COMMENT && notWs.test(token)) { lastToken = token; }
+ }
+ return decorations;
+ };
+ }
+
+ var PR_MARKUP_LEXER = createSimpleLexer([], [
+ [PR_PLAIN, /^[^<]+/, null],
+ [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/, null],
+ [PR_COMMENT, /^<!--[\s\S]*?(?:-->|$)/, null],
+ [PR_SOURCE, /^<\?[\s\S]*?(?:\?>|$)/, null],
+ [PR_SOURCE, /^<%[\s\S]*?(?:%>|$)/, null],
+ [PR_SOURCE,
+ // Tags whose content is not escaped, and which contain source code.
+ /^<(script|style|xmp)\b[^>]*>[\s\S]*?<\/\1\b[^>]*>/i, null],
+ [PR_TAG, /^<\/?\w[^<>]*>/, null]
+ ]);
+ // Splits any of the source|style|xmp entries above into a start tag,
+ // source content, and end tag.
+ var PR_SOURCE_CHUNK_PARTS = /^(<[^>]*>)([\s\S]*)(<\/[^>]*>)$/;
+ /** split markup on tags, comments, application directives, and other top
+ * level constructs. Tags are returned as a single token - attributes are
+ * not yet broken out.
+ * @private
+ */
+ function tokenizeMarkup(source) {
+ var decorations = PR_MARKUP_LEXER(source);
+ for (var i = 0; i < decorations.length; i += 2) {
+ if (decorations[i + 1] === PR_SOURCE) {
+ var start, end;
+ start = decorations[i];
+ end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+ // Split out start and end script tags as actual tags, and leave the
+ // body with style SCRIPT.
+ var sourceChunk = source.substring(start, end);
+ var match = sourceChunk.match(PR_SOURCE_CHUNK_PARTS);
+ if (match) {
+ decorations.splice(
+ i, 2,
+ start, PR_TAG, // the open chunk
+ start + match[1].length, PR_SOURCE,
+ start + match[1].length + (match[2] || '').length, PR_TAG);
+ }
+ }
+ }
+ return decorations;
+ }
+
+ var PR_TAG_LEXER = createSimpleLexer([
+ [PR_ATTRIB_VALUE, /^\'[^\']*(?:\'|$)/, null, "'"],
+ [PR_ATTRIB_VALUE, /^\"[^\"]*(?:\"|$)/, null, '"'],
+ [PR_PUNCTUATION, /^[<>\/=]+/, null, '<>/=']
+ ], [
+ [PR_TAG, /^[\w:\-]+/, /^</],
+ [PR_ATTRIB_VALUE, /^[\w\-]+/, /^=/],
+ [PR_ATTRIB_NAME, /^[\w:\-]+/, null],
+ [PR_PLAIN, /^\s+/, null, ' \t\r\n']
+ ]);
+ /** split tags attributes and their values out from the tag name, and
+ * recursively lex source chunks.
+ * @private
+ */
+ function splitTagAttributes(source, decorations) {
+ for (var i = 0; i < decorations.length; i += 2) {
+ var style = decorations[i + 1];
+ if (style === PR_TAG) {
+ var start, end;
+ start = decorations[i];
+ end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+ var chunk = source.substring(start, end);
+ var subDecorations = PR_TAG_LEXER(chunk, start);
+ spliceArrayInto(subDecorations, decorations, i, 2);
+ i += subDecorations.length - 2;
+ }
+ }
+ return decorations;
+ }
+
+ /** returns a function that produces a list of decorations from source text.
+ *
+ * This code treats ", ', and ` as string delimiters, and \ as a string
+ * escape. It does not recognize perl's qq() style strings.
+ * It has no special handling for double delimiter escapes as in basic, or
+ * the tripled delimiters used in python, but should work on those regardless
+ * although in those cases a single string literal may be broken up into
+ * multiple adjacent string literals.
+ *
+ * It recognizes C, C++, and shell style comments.
+ *
+ * @param {Object} options a set of optional parameters.
+ * @return {function (string) : Array.<string|number>} a
+ * decorator that takes sourceCode as plain text and that returns a
+ * decoration list
+ */
+ function sourceDecorator(options) {
+ var shortcutStylePatterns = [], fallthroughStylePatterns = [];
+ if (options.tripleQuotedStrings) {
+ // '''multi-line-string''', 'single-line-string', and double-quoted
+ shortcutStylePatterns.push(
+ [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
+ null, '\'"']);
+ } else if (options.multiLineStrings) {
+ // 'multi-line-string', "multi-line-string"
+ shortcutStylePatterns.push(
+ [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
+ null, '\'"`']);
+ } else {
+ // 'single-line-string', "single-line-string"
+ shortcutStylePatterns.push(
+ [PR_STRING,
+ /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
+ null, '"\'']);
+ }
+ fallthroughStylePatterns.push(
+ [PR_PLAIN, /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n']);
+ if (options.hashComments) {
+ shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
+ }
+ if (options.cStyleComments) {
+ fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
+ fallthroughStylePatterns.push(
+ [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
+ }
+ if (options.regexLiterals) {
+ var REGEX_LITERAL = (
+ // A regular expression literal starts with a slash that is
+ // not followed by * or / so that it is not confused with
+ // comments.
+ '^/(?=[^/*])'
+ // and then contains any number of raw characters,
+ + '(?:[^/\\x5B\\x5C]'
+ // escape sequences (\x5C),
+ + '|\\x5C[\\s\\S]'
+ // or non-nesting character sets (\x5B\x5D);
+ + '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
+ // finally closed by a /.
+ + '(?:/|$)');
+ fallthroughStylePatterns.push(
+ [PR_STRING, new RegExp(REGEX_LITERAL), REGEXP_PRECEDER_PATTERN]);
+ }
+
+ var keywords = wordSet(options.keywords);
+
+ options = null;
+
+ /** splits the given string into comment, string, and "other" tokens.
+ * @param {string} sourceCode as plain text
+ * @return {Array.<number|string>} a decoration list.
+ * @private
+ */
+ var splitStringAndCommentTokens = createSimpleLexer(
+ shortcutStylePatterns, fallthroughStylePatterns);
+
+ var styleLiteralIdentifierPuncRecognizer = createSimpleLexer([], [
+ [PR_PLAIN, /^\s+/, null, ' \r\n'],
+ // TODO(mikesamuel): recognize non-latin letters and numerals in idents
+ [PR_PLAIN, /^[a-z_$@][a-z_$@0-9]*/i, null],
+ // A hex number
+ [PR_LITERAL, /^0x[a-f0-9]+[a-z]/i, null],
+ // An octal or decimal number, possibly in scientific notation
+ [PR_LITERAL,
+ /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i,
+ null, '123456789'],
+ [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null]
+ // Fallback will handle decimal points not adjacent to a digit
+ ]);
+
+ /** splits plain text tokens into more specific tokens, and then tries to
+ * recognize keywords, and types.
+ * @private
+ */
+ function splitNonStringNonCommentTokens(source, decorations) {
+ for (var i = 0; i < decorations.length; i += 2) {
+ var style = decorations[i + 1];
+ if (style === PR_PLAIN) {
+ var start, end, chunk, subDecs;
+ start = decorations[i];
+ end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+ chunk = source.substring(start, end);
+ subDecs = styleLiteralIdentifierPuncRecognizer(chunk, start);
+ for (var j = 0, m = subDecs.length; j < m; j += 2) {
+ var subStyle = subDecs[j + 1];
+ if (subStyle === PR_PLAIN) {
+ var subStart = subDecs[j];
+ var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length;
+ var token = source.substring(subStart, subEnd);
+ if (token === '.') {
+ subDecs[j + 1] = PR_PUNCTUATION;
+ } else if (token in keywords) {
+ subDecs[j + 1] = PR_KEYWORD;
+ } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) {
+ // classify types and annotations using Java's style conventions
+ subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE;
+ }
+ }
+ }
+ spliceArrayInto(subDecs, decorations, i, 2);
+ i += subDecs.length - 2;
+ }
+ }
+ return decorations;
+ }
+
+ return function (sourceCode) {
+ // Split into strings, comments, and other.
+ // We do this because strings and comments are easily recognizable and can
+ // contain stuff that looks like other tokens, so we want to mark those
+ // early so we don't recurse into them.
+ var decorations = splitStringAndCommentTokens(sourceCode);
+
+ // Split non comment|string tokens on whitespace and word boundaries
+ decorations = splitNonStringNonCommentTokens(sourceCode, decorations);
+
+ return decorations;
+ };
+ }
+
+ var decorateSource = sourceDecorator({
+ keywords: ALL_KEYWORDS,
+ hashComments: true,
+ cStyleComments: true,
+ multiLineStrings: true,
+ regexLiterals: true
+ });
+
+ /** identify regions of markup that are really source code, and recursivley
+ * lex them.
+ * @private
+ */
+ function splitSourceNodes(source, decorations) {
+ for (var i = 0; i < decorations.length; i += 2) {
+ var style = decorations[i + 1];
+ if (style === PR_SOURCE) {
+ // Recurse using the non-markup lexer
+ var start, end;
+ start = decorations[i];
+ end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+ var subDecorations = decorateSource(source.substring(start, end));
+ for (var j = 0, m = subDecorations.length; j < m; j += 2) {
+ subDecorations[j] += start;
+ }
+ spliceArrayInto(subDecorations, decorations, i, 2);
+ i += subDecorations.length - 2;
+ }
+ }
+ return decorations;
+ }
+
+ /** identify attribute values that really contain source code and recursively
+ * lex them.
+ * @private
+ */
+ function splitSourceAttributes(source, decorations) {
+ var nextValueIsSource = false;
+ for (var i = 0; i < decorations.length; i += 2) {
+ var style = decorations[i + 1];
+ var start, end;
+ if (style === PR_ATTRIB_NAME) {
+ start = decorations[i];
+ end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+ nextValueIsSource = /^on|^style$/i.test(source.substring(start, end));
+ } else if (style === PR_ATTRIB_VALUE) {
+ if (nextValueIsSource) {
+ start = decorations[i];
+ end = i + 2 < decorations.length ? decorations[i + 2] : source.length;
+ var attribValue = source.substring(start, end);
+ var attribLen = attribValue.length;
+ var quoted =
+ (attribLen >= 2 && /^[\"\']/.test(attribValue) &&
+ attribValue.charAt(0) === attribValue.charAt(attribLen - 1));
+
+ var attribSource;
+ var attribSourceStart;
+ var attribSourceEnd;
+ if (quoted) {
+ attribSourceStart = start + 1;
+ attribSourceEnd = end - 1;
+ attribSource = attribValue;
+ } else {
+ attribSourceStart = start + 1;
+ attribSourceEnd = end - 1;
+ attribSource = attribValue.substring(1, attribValue.length - 1);
+ }
+
+ var attribSourceDecorations = decorateSource(attribSource);
+ for (var j = 0, m = attribSourceDecorations.length; j < m; j += 2) {
+ attribSourceDecorations[j] += attribSourceStart;
+ }
+
+ if (quoted) {
+ attribSourceDecorations.push(attribSourceEnd, PR_ATTRIB_VALUE);
+ spliceArrayInto(attribSourceDecorations, decorations, i + 2, 0);
+ } else {
+ spliceArrayInto(attribSourceDecorations, decorations, i, 2);
+ }
+ }
+ nextValueIsSource = false;
+ }
+ }
+ return decorations;
+ }
+
+ /** returns a decoration list given a string of markup.
+ *
+ * This code recognizes a number of constructs.
+ * <!-- ... --> comment
+ * <!\w ... > declaration
+ * <\w ... > tag
+ * </\w ... > tag
+ * <?...?> embedded source
+ * <%...%> embedded source
+ * &[#\w]...; entity
+ *
+ * It does not recognizes %foo; doctype entities from .
+ *
+ * It will recurse into any <style>, <script>, and on* attributes using
+ * PR_lexSource.
+ */
+ function decorateMarkup(sourceCode) {
+ // This function works as follows:
+ // 1) Start by splitting the markup into text and tag chunks
+ // Input: string s
+ // Output: List<PR_Token> where style in (PR_PLAIN, null)
+ // 2) Then split the text chunks further into comments, declarations,
+ // tags, etc.
+ // After each split, consider whether the token is the start of an
+ // embedded source section, i.e. is an open <script> tag. If it is, find
+ // the corresponding close token, and don't bother to lex in between.
+ // Input: List<string>
+ // Output: List<PR_Token> with style in
+ // (PR_TAG, PR_PLAIN, PR_SOURCE, null)
+ // 3) Finally go over each tag token and split out attribute names and
+ // values.
+ // Input: List<PR_Token>
+ // Output: List<PR_Token> where style in
+ // (PR_TAG, PR_PLAIN, PR_SOURCE, NAME, VALUE, null)
+ var decorations = tokenizeMarkup(sourceCode);
+ decorations = splitTagAttributes(sourceCode, decorations);
+ decorations = splitSourceNodes(sourceCode, decorations);
+ decorations = splitSourceAttributes(sourceCode, decorations);
+ return decorations;
+ }
+
+ /**
+ * @param {string} sourceText plain text
+ * @param {Array.<number|string>} extractedTags chunks of raw html preceded
+ * by their position in sourceText in order.
+ * @param {Array.<number|string>} decorations style classes preceded by their
+ * position in sourceText in order.
+ * @return {string} html
+ * @private
+ */
+ function recombineTagsAndDecorations(sourceText, extractedTags, decorations) {
+ var html = [];
+ // index past the last char in sourceText written to html
+ var outputIdx = 0;
+
+ var openDecoration = null;
+ var currentDecoration = null;
+ var tagPos = 0; // index into extractedTags
+ var decPos = 0; // index into decorations
+ var tabExpander = makeTabExpander(PR_TAB_WIDTH);
+
+ var adjacentSpaceRe = /([\r\n ]) /g;
+ var startOrSpaceRe = /(^| ) /gm;
+ var newlineRe = /\r\n?|\n/g;
+ var trailingSpaceRe = /[ \r\n]$/;
+ var lastWasSpace = true; // the last text chunk emitted ended with a space.
+
+ // A helper function that is responsible for opening sections of decoration
+ // and outputing properly escaped chunks of source
+ function emitTextUpTo(sourceIdx) {
+ if (sourceIdx > outputIdx) {
+ if (openDecoration && openDecoration !== currentDecoration) {
+ // Close the current decoration
+ html.push('</span>');
+ openDecoration = null;
+ }
+ if (!openDecoration && currentDecoration) {
+ openDecoration = currentDecoration;
+ html.push('<span class="', openDecoration, '">');
+ }
+ // This interacts badly with some wikis which introduces paragraph tags
+ // into pre blocks for some strange reason.
+ // It's necessary for IE though which seems to lose the preformattedness
+ // of <pre> tags when their innerHTML is assigned.
+ // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
+ // and it serves to undo the conversion of <br>s to newlines done in
+ // chunkify.
+ var htmlChunk = textToHtml(
+ tabExpander(sourceText.substring(outputIdx, sourceIdx)))
+ .replace(lastWasSpace
+ ? startOrSpaceRe
+ : adjacentSpaceRe, '$1 ');
+ // Keep track of whether we need to escape space at the beginning of the
+ // next chunk.
+ lastWasSpace = trailingSpaceRe.test(htmlChunk);
+ html.push(htmlChunk.replace(newlineRe, '<br />'));
+ outputIdx = sourceIdx;
+ }
+ }
+
+ while (true) {
+ // Determine if we're going to consume a tag this time around. Otherwise
+ // we consume a decoration or exit.
+ var outputTag;
+ if (tagPos < extractedTags.length) {
+ if (decPos < decorations.length) {
+ // Pick one giving preference to extractedTags since we shouldn't open
+ // a new style that we're going to have to immediately close in order
+ // to output a tag.
+ outputTag = extractedTags[tagPos] <= decorations[decPos];
+ } else {
+ outputTag = true;
+ }
+ } else {
+ outputTag = false;
+ }
+ // Consume either a decoration or a tag or exit.
+ if (outputTag) {
+ emitTextUpTo(extractedTags[tagPos]);
+ if (openDecoration) {
+ // Close the current decoration
+ html.push('</span>');
+ openDecoration = null;
+ }
+ html.push(extractedTags[tagPos + 1]);
+ tagPos += 2;
+ } else if (decPos < decorations.length) {
+ emitTextUpTo(decorations[decPos]);
+ currentDecoration = decorations[decPos + 1];
+ decPos += 2;
+ } else {
+ break;
+ }
+ }
+ emitTextUpTo(sourceText.length);
+ if (openDecoration) {
+ html.push('</span>');
+ }
+
+ return html.join('');
+ }
+
+ /** Maps language-specific file extensions to handlers. */
+ var langHandlerRegistry = {};
+ /** Register a language handler for the given file extensions.
+ * @param {function (string) : Array.<number|string>} handler
+ * a function from source code to a list of decorations.
+ * @param {Array.<string>} fileExtensions
+ */
+ function registerLangHandler(handler, fileExtensions) {
+ for (var i = fileExtensions.length; --i >= 0;) {
+ var ext = fileExtensions[i];
+ if (!langHandlerRegistry.hasOwnProperty(ext)) {
+ langHandlerRegistry[ext] = handler;
+ } else if ('console' in window) {
+ console.log('cannot override language handler %s', ext);
+ }
+ }
+ }
+ registerLangHandler(decorateSource, ['default-code']);
+ registerLangHandler(decorateMarkup,
+ ['default-markup', 'html', 'htm', 'xhtml', 'xml', 'xsl']);
+ registerLangHandler(sourceDecorator({
+ keywords: CPP_KEYWORDS,
+ hashComments: true,
+ cStyleComments: true
+ }), ['c', 'cc', 'cpp', 'cs', 'cxx', 'cyc']);
+ registerLangHandler(sourceDecorator({
+ keywords: JAVA_KEYWORDS,
+ cStyleComments: true
+ }), ['java']);
+ registerLangHandler(sourceDecorator({
+ keywords: SH_KEYWORDS,
+ hashComments: true,
+ multiLineStrings: true
+ }), ['bsh', 'csh', 'sh']);
+ registerLangHandler(sourceDecorator({
+ keywords: PYTHON_KEYWORDS,
+ hashComments: true,
+ multiLineStrings: true,
+ tripleQuotedStrings: true
+ }), ['cv', 'py']);
+ registerLangHandler(sourceDecorator({
+ keywords: PERL_KEYWORDS,
+ hashComments: true,
+ multiLineStrings: true,
+ regexLiterals: true
+ }), ['perl', 'pl', 'pm']);
+ registerLangHandler(sourceDecorator({
+ keywords: RUBY_KEYWORDS,
+ hashComments: true,
+ multiLineStrings: true,
+ regexLiterals: true
+ }), ['rb']);
+ registerLangHandler(sourceDecorator({
+ keywords: JSCRIPT_KEYWORDS,
+ cStyleComments: true,
+ regexLiterals: true
+ }), ['js']);
+
+ function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
+ try {
+ // Extract tags, and convert the source code to plain text.
+ var sourceAndExtractedTags = extractTags(sourceCodeHtml);
+ /** Plain text. @type {string} */
+ var source = sourceAndExtractedTags.source;
+
+ /** Even entries are positions in source in ascending order. Odd entries
+ * are tags that were extracted at that position.
+ * @type {Array.<number|string>}
+ */
+ var extractedTags = sourceAndExtractedTags.tags;
+
+ // Pick a lexer and apply it.
+ if (!langHandlerRegistry.hasOwnProperty(opt_langExtension)) {
+ // Treat it as markup if the first non whitespace character is a < and
+ // the last non-whitespace character is a >.
+ opt_langExtension =
+ /^\s*</.test(source) ? 'default-markup' : 'default-code';
+ }
+
+ /** Even entries are positions in source in ascending order. Odd enties
+ * are style markers (e.g., PR_COMMENT) that run from that position until
+ * the end.
+ * @type {Array.<number|string>}
+ */
+ var decorations = langHandlerRegistry[opt_langExtension].call({}, source);
+
+ // Integrate the decorations and tags back into the source code to produce
+ // a decorated html string.
+ return recombineTagsAndDecorations(source, extractedTags, decorations);
+ } catch (e) {
+ if ('console' in window) {
+ console.log(e);
+ console.trace();
+ }
+ return sourceCodeHtml;
+ }
+ }
+
+ function prettyPrint(opt_whenDone) {
+ var isIE6 = _pr_isIE6();
+
+ // fetch a list of nodes to rewrite
+ var codeSegments = [
+ document.getElementsByTagName('pre'),
+ document.getElementsByTagName('code'),
+ document.getElementsByTagName('xmp') ];
+ var elements = [];
+ for (var i = 0; i < codeSegments.length; ++i) {
+ for (var j = 0; j < codeSegments[i].length; ++j) {
+ elements.push(codeSegments[i][j]);
+ }
+ }
+ codeSegments = null;
+
+ // the loop is broken into a series of continuations to make sure that we
+ // don't make the browser unresponsive when rewriting a large page.
+ var k = 0;
+
+ function doWork() {
+ var endTime = (PR_SHOULD_USE_CONTINUATION ?
+ new Date().getTime() + 250 /* ms */ :
+ Infinity);
+ for (; k < elements.length && new Date().getTime() < endTime; k++) {
+ var cs = elements[k];
+ if (cs.className && cs.className.indexOf('prettyprint') >= 0) {
+ // If the classes includes a language extensions, use it.
+ // Language extensions can be specified like
+ // <pre class="prettyprint lang-cpp">
+ // the language extension "cpp" is used to find a language handler as
+ // passed to PR_registerLangHandler.
+ var langExtension = cs.className.match(/\blang-(\w+)\b/);
+ if (langExtension) { langExtension = langExtension[1]; }
+
+ // make sure this is not nested in an already prettified element
+ var nested = false;
+ for (var p = cs.parentNode; p; p = p.parentNode) {
+ if ((p.tagName === 'pre' || p.tagName === 'code' ||
+ p.tagName === 'xmp') &&
+ p.className && p.className.indexOf('prettyprint') >= 0) {
+ nested = true;
+ break;
+ }
+ }
+ if (!nested) {
+ // fetch the content as a snippet of properly escaped HTML.
+ // Firefox adds newlines at the end.
+ var content = getInnerHtml(cs);
+ content = content.replace(/(?:\r\n?|\n)$/, '');
+
+ // do the pretty printing
+ var newContent = prettyPrintOne(content, langExtension);
+
+ // push the prettified html back into the tag.
+ if (!isRawContent(cs)) {
+ // just replace the old html with the new
+ cs.innerHTML = newContent;
+ } else {
+ // we need to change the tag to a <pre> since <xmp>s do not allow
+ // embedded tags such as the span tags used to attach styles to
+ // sections of source code.
+ var pre = document.createElement('PRE');
+ for (var i = 0; i < cs.attributes.length; ++i) {
+ var a = cs.attributes[i];
+ if (a.specified) {
+ var aname = a.name.toLowerCase();
+ if (aname === 'class') {
+ pre.className = a.value; // For IE 6
+ } else {
+ pre.setAttribute(a.name, a.value);
+ }
+ }
+ }
+ pre.innerHTML = newContent;
+
+ // remove the old
+ cs.parentNode.replaceChild(pre, cs);
+ cs = pre;
+ }
+
+ // Replace <br>s with line-feeds so that copying and pasting works
+ // on IE 6.
+ // Doing this on other browsers breaks lots of stuff since \r\n is
+ // treated as two newlines on Firefox, and doing this also slows
+ // down rendering.
+ if (isIE6 && cs.tagName === 'PRE') {
+ var lineBreaks = cs.getElementsByTagName('br');
+ for (var j = lineBreaks.length; --j >= 0;) {
+ var lineBreak = lineBreaks[j];
+ lineBreak.parentNode.replaceChild(
+ document.createTextNode('\r\n'), lineBreak);
+ }
+ }
+ }
+ }
+ }
+ if (k < elements.length) {
+ // finish up in a continuation
+ setTimeout(doWork, 250);
+ } else if (opt_whenDone) {
+ opt_whenDone();
+ }
+ }
+
+ doWork();
+ }
+
+ window['PR_normalizedHtml'] = normalizedHtml;
+ window['prettyPrintOne'] = prettyPrintOne;
+ window['prettyPrint'] = prettyPrint;
+ window['PR'] = {
+ 'createSimpleLexer': createSimpleLexer,
+ 'registerLangHandler': registerLangHandler,
+ 'sourceDecorator': sourceDecorator,
+ 'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
+ 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
+ 'PR_COMMENT': PR_COMMENT,
+ 'PR_DECLARATION': PR_DECLARATION,
+ 'PR_KEYWORD': PR_KEYWORD,
+ 'PR_LITERAL': PR_LITERAL,
+ 'PR_NOCODE': PR_NOCODE,
+ 'PR_PLAIN': PR_PLAIN,
+ 'PR_PUNCTUATION': PR_PUNCTUATION,
+ 'PR_SOURCE': PR_SOURCE,
+ 'P...
[truncated message content] |
|
From: <br...@us...> - 2008-12-30 21:57:59
|
Revision: 8452
http://exist.svn.sourceforge.net/exist/?rev=8452&view=rev
Author: brihaye
Date: 2008-12-30 21:47:32 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
[ignore] refactored imports
Modified Paths:
--------------
trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/LuceneModule.java
trunk/eXist/src/org/exist/dom/MutableDocumentSet.java
trunk/eXist/src/org/exist/fulltext/FTIndex.java
trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java
trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java
trunk/eXist/src/org/exist/storage/TextSearchEngine.java
trunk/eXist/src/org/exist/storage/journal/Journal.java
trunk/eXist/src/org/exist/storage/serializers/Serializer.java
trunk/eXist/src/org/exist/util/ZipEntryInputSource.java
trunk/eXist/src/org/exist/xmldb/ExtendedBinaryResource.java
trunk/eXist/src/org/exist/xmldb/LocalBinaryResource.java
trunk/eXist/src/org/exist/xmldb/RemoteIndexQueryService.java
trunk/eXist/src/org/exist/xmldb/RemoteXUpdateQueryService.java
trunk/eXist/src/org/exist/xslt/TransformerFactoryAllocator.java
Modified: trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/LuceneModule.java
===================================================================
--- trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/LuceneModule.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/LuceneModule.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -27,7 +27,7 @@
}
public String getDescription() {
- return "Extension functions for NGram search.";
+ return "Extension functions for Lucene search.";
}
}
Modified: trunk/eXist/src/org/exist/dom/MutableDocumentSet.java
===================================================================
--- trunk/eXist/src/org/exist/dom/MutableDocumentSet.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/dom/MutableDocumentSet.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -4,7 +4,6 @@
import org.exist.storage.DBBroker;
import org.exist.storage.lock.LockedDocumentMap;
import org.exist.util.LockException;
-import org.w3c.dom.NodeList;
/**
*
Modified: trunk/eXist/src/org/exist/fulltext/FTIndex.java
===================================================================
--- trunk/eXist/src/org/exist/fulltext/FTIndex.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/fulltext/FTIndex.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -21,6 +21,10 @@
*/
package org.exist.fulltext;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+
import org.apache.log4j.Logger;
import org.exist.backup.RawDataBackup;
import org.exist.indexing.AbstractIndex;
@@ -28,17 +32,12 @@
import org.exist.indexing.RawBackupSupport;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
-import org.exist.storage.NativeBroker;
import org.exist.storage.NativeTextEngine;
import org.exist.storage.btree.DBException;
import org.exist.storage.index.BFile;
import org.exist.util.DatabaseConfigurationException;
import org.w3c.dom.Element;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-
/**
* Implementation of the full text index. We are currently in a redesign process which is
* not yet complete. We still have dependencies on FTIndex in the database core. Once
Modified: trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java
===================================================================
--- trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -21,17 +21,16 @@
*/
package org.exist.memtree;
-import org.w3c.dom.Node;
-import org.exist.stax.EmbeddedXMLStreamReader;
-import org.exist.stax.ExtendedXMLStreamReader;
-import org.exist.numbering.NodeId;
-
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import org.exist.numbering.NodeId;
+import org.exist.stax.ExtendedXMLStreamReader;
+import org.w3c.dom.Node;
+
/**
* Implementation of a StAX {@link javax.xml.stream.XMLStreamReader}, which wraps around
* eXist's in-memory DOM. This class complements {@link org.exist.stax.EmbeddedXMLStreamReader}
Modified: trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java
===================================================================
--- trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -21,8 +21,24 @@
*/
package org.exist.stax;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
import org.apache.log4j.Logger;
-import org.exist.dom.*;
+import org.exist.dom.AttrImpl;
+import org.exist.dom.CharacterDataImpl;
+import org.exist.dom.DocumentImpl;
+import org.exist.dom.ElementImpl;
+import org.exist.dom.NodeHandle;
+import org.exist.dom.StoredNode;
import org.exist.numbering.NodeId;
import org.exist.storage.DBBroker;
import org.exist.storage.Signatures;
@@ -34,17 +50,6 @@
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.namespace.QName;
-import javax.xml.stream.Location;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Stack;
-
/**
* Lazy implementation of a StAX {@link javax.xml.stream.XMLStreamReader}, which directly reads
* information from the persistent DOM. The class is optimized to support fast scanning of the DOM, where only
Modified: trunk/eXist/src/org/exist/storage/TextSearchEngine.java
===================================================================
--- trunk/eXist/src/org/exist/storage/TextSearchEngine.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/storage/TextSearchEngine.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -20,10 +20,21 @@
*/
package org.exist.storage;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.Observable;
+import java.util.TreeSet;
+
import org.apache.log4j.Logger;
import org.exist.collections.Collection;
-import org.exist.dom.*;
-import org.exist.fulltext.FTIndexWorker;
+import org.exist.dom.DocumentImpl;
+import org.exist.dom.DocumentSet;
+import org.exist.dom.NodeSet;
+import org.exist.dom.QName;
+import org.exist.dom.StoredNode;
+import org.exist.dom.TextImpl;
import org.exist.fulltext.ElementContent;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.analysis.SimpleTokenizer;
@@ -36,13 +47,6 @@
import org.exist.xquery.TerminatedException;
import org.exist.xquery.XQueryContext;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.StreamTokenizer;
-import java.util.Observable;
-import java.util.TreeSet;
-
/**
* This is the base class for all classes providing access to the fulltext index.
*
Modified: trunk/eXist/src/org/exist/storage/journal/Journal.java
===================================================================
--- trunk/eXist/src/org/exist/storage/journal/Journal.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/storage/journal/Journal.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -25,7 +25,6 @@
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.FileFilter;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
Modified: trunk/eXist/src/org/exist/storage/serializers/Serializer.java
===================================================================
--- trunk/eXist/src/org/exist/storage/serializers/Serializer.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/storage/serializers/Serializer.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -22,6 +22,31 @@
*/
package org.exist.storage.serializers;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TemplatesHandler;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
import org.apache.log4j.Logger;
import org.exist.Namespaces;
import org.exist.dom.DocumentImpl;
@@ -65,31 +90,6 @@
import org.xml.sax.XMLReader;
import org.xml.sax.ext.LexicalHandler;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Source;
-import javax.xml.transform.Templates;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.URIResolver;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.SAXSource;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TemplatesHandler;
-import javax.xml.transform.sax.TransformerHandler;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.HashMap;
-
/**
* Serializer base class, used to serialize a document or document fragment
* back to XML. A serializer may be obtained by calling DBBroker.getSerializer().
Modified: trunk/eXist/src/org/exist/util/ZipEntryInputSource.java
===================================================================
--- trunk/eXist/src/org/exist/util/ZipEntryInputSource.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/util/ZipEntryInputSource.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -1,13 +1,11 @@
package org.exist.util;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.Reader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import org.xml.sax.InputSource;
-
/**
* This class extends InputSource to be able to deal with
* ZipEntry objects from ZIP compressed files. Its main
Modified: trunk/eXist/src/org/exist/xmldb/ExtendedBinaryResource.java
===================================================================
--- trunk/eXist/src/org/exist/xmldb/ExtendedBinaryResource.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/xmldb/ExtendedBinaryResource.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -25,7 +25,6 @@
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.Writer;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.BinaryResource;
Modified: trunk/eXist/src/org/exist/xmldb/LocalBinaryResource.java
===================================================================
--- trunk/eXist/src/org/exist/xmldb/LocalBinaryResource.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/xmldb/LocalBinaryResource.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -29,7 +29,6 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.InputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Modified: trunk/eXist/src/org/exist/xmldb/RemoteIndexQueryService.java
===================================================================
--- trunk/eXist/src/org/exist/xmldb/RemoteIndexQueryService.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/xmldb/RemoteIndexQueryService.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -21,7 +21,6 @@
*/
package org.exist.xmldb;
-import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
Modified: trunk/eXist/src/org/exist/xmldb/RemoteXUpdateQueryService.java
===================================================================
--- trunk/eXist/src/org/exist/xmldb/RemoteXUpdateQueryService.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/xmldb/RemoteXUpdateQueryService.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -5,7 +5,6 @@
*/
package org.exist.xmldb;
-import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Vector;
Modified: trunk/eXist/src/org/exist/xslt/TransformerFactoryAllocator.java
===================================================================
--- trunk/eXist/src/org/exist/xslt/TransformerFactoryAllocator.java 2008-12-30 21:21:57 UTC (rev 8451)
+++ trunk/eXist/src/org/exist/xslt/TransformerFactoryAllocator.java 2008-12-30 21:47:32 UTC (rev 8452)
@@ -21,14 +21,13 @@
*/
package org.exist.xslt;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.sax.SAXTransformerFactory;
-
import java.util.Enumeration;
import java.util.Hashtable;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+
import org.apache.log4j.Logger;
-import org.exist.storage.DBBroker;
import org.exist.storage.BrokerPool;
/**
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 21:22:01
|
Revision: 8451
http://exist.svn.sourceforge.net/exist/?rev=8451&view=rev
Author: deliriumsky
Date: 2008-12-30 21:21:57 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Support for namespaces on remote expressions and bug fixes in various areas.
Next - continue the code review in XQRemoteConnection
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/xqj/EXistXQExpressionImpl.java
branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java
branches/allad/jsr-225/src/org/exist/xqj/local/XQLocalExpression.java
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpression.java
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpressionImpl.java
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemotePreparedExpression.java
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteResultSequence.java
Added Paths:
-----------
branches/allad/jsr-225/src/org/exist/xqj/EXistRESTOperation.java
Removed Paths:
-------------
branches/allad/jsr-225/src/org/exist/xqj/EXistRESTURL.java
Copied: branches/allad/jsr-225/src/org/exist/xqj/EXistRESTOperation.java (from rev 8421, branches/allad/jsr-225/src/org/exist/xqj/EXistRESTURL.java)
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistRESTOperation.java (rev 0)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistRESTOperation.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -0,0 +1,158 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-09 Wolfgang M. Meier
+ * wol...@ex...
+ * http://exist.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+package org.exist.xqj;
+
+import java.net.URLEncoder;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.exist.Namespaces;
+
+/**
+ * Helper class for building eXist REST URL.
+ *
+ * @author Cherif YAYA (allad)
+ * @author Adam Retter <ad...@ex...>
+ */
+public class EXistRESTOperation
+{
+ private String remotePath;
+ Hashtable params = new Hashtable();
+ Map namespaces = new HashMap();
+
+
+ public EXistRESTOperation(String url) {
+ remotePath = url;
+ }
+
+ public void addNamespace(String prefix, String uri)
+ {
+ namespaces.put(prefix, uri);
+ }
+
+ /**
+ * Adds a (key,value) pair to the URL
+ * @param k the parameter name to add
+ * @param v the value associated with the parameter k
+ */
+ public void addParameter(String k,String v) {
+ params.put(k, v);
+ }
+
+ public void removeParameter(String k) {
+ params.remove(k);
+ }
+
+ public String getRemoteURLPath() {
+ return remotePath;
+ }
+
+ /**
+ * Gets a string reprensentation of the URL to use for a GET request
+ * @return an encoded string representation of the URL
+ */
+ public String toHttpGETString() {
+ String tmp = remotePath+"?";
+
+
+ for(Enumeration e = params.keys(); e.hasMoreElements();) {
+ String k = (String)e.nextElement();
+ String v = URLEncoder.encode((String)params.get(k));
+ tmp += k+"="+v+"&";
+ }
+ //remove the last &
+ tmp = tmp.substring(0, tmp.length()-1);
+
+ //encode the result
+ return tmp;
+ }
+
+
+ /**
+ * Gets a string reprensentation of the parameters to use for a POST request
+ * @return an eXist POST request xml fragment representing the parameters
+ */
+ public String toHttpPOSTString() {
+ String tmp = remotePath+"?";
+
+ String _start = (String)params.get("_start");
+ if(_start == null)
+ _start = "1";
+ String _max = (String)params.get("_howmany");
+ if(_max == null)
+ _max = "10";
+ String _query = (String)params.get("_query");
+ String _namespaces = (String)params.get("_namespaces");
+ String _variables = (String)params.get("_variables");
+ String _typed = (String)params.get("_typed");
+
+ StringBuffer postString = new StringBuffer();
+ postString.append("<exist:query xmlns:exist=\"" + Namespaces.EXIST_NS + "\"");
+
+ //additional namespaces
+ for(Iterator itNsPrefix = namespaces.keySet().iterator(); itNsPrefix.hasNext(); )
+ {
+ String nsPrefix = (String)itNsPrefix.next();
+ String nsUri = (String)namespaces.get(nsPrefix);
+
+ postString.append(" xmlns:" + nsPrefix + "=\"" + nsUri + "\"");
+ }
+
+ postString.append(" start=\"" + _start+ "\"");
+ postString.append(" max=\"" + _max + "\"");
+
+ if(_typed != null)
+ {
+ postString.append(" typed=\"" + _typed + "\"");
+ }
+ postString.append(">");
+
+ if(_query != null)
+ postString.append("<exist:text><![CDATA[" + _query + "]]></exist:text>");
+
+ if(_variables != null)
+ postString.append(_variables);
+
+
+ //properties
+ postString.append("<exist:properties>");
+ for(Enumeration e = params.keys(); e.hasMoreElements();) {
+ String k = (String)e.nextElement();
+ if(k.equals("_query") || k.equals("_start") || k.equals("_howmany") || k.equals("_variables"))
+ continue;
+ String v = (String)params.get(k);
+
+ postString.append("<exist:property name=\"" + k + "\" value=\"" + v + "\"/>");
+ }
+
+ postString.append("</exist:properties>");
+
+ postString.append("</exist:query>");
+
+ //encode the result
+ return postString.toString();
+ }
+}
Property changes on: branches/allad/jsr-225/src/org/exist/xqj/EXistRESTOperation.java
___________________________________________________________________
Added: svn:keywords
+ Id
Added: svn:mergeinfo
+ /trunk/eXist/src/org/exist/xqj/EXistRESTURL.java:7822-8288,8290-8401
Deleted: branches/allad/jsr-225/src/org/exist/xqj/EXistRESTURL.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistRESTURL.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistRESTURL.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -1,130 +0,0 @@
-/*
- * eXist Open Source Native XML Database
- * Copyright (C) 2001-09 Wolfgang M. Meier
- * wol...@ex...
- * http://exist.sourceforge.net
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id$
- */
-package org.exist.xqj;
-
-import java.net.URLEncoder;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-import org.exist.Namespaces;
-
-/**
- * Helper class for building eXist REST URL.
- *
- * @author Cherif YAYA (allad)
- */
-public class EXistRESTURL {
- private String remotePath;
- Hashtable params = new Hashtable();
-
- public EXistRESTURL(String url) {
- remotePath = url;
- }
-
- /**
- * Adds a (key,value) pair to the URL
- * @param k the parameter name to add
- * @param v the value associated with the parameter k
- */
- public void addParameter(String k,String v) {
- params.put(k, v);
- }
-
- public void removeParameter(String k) {
- params.remove(k);
- }
-
- public String getRemoteURLPath() {
- return remotePath;
- }
-
- /**
- * Gets a string reprensentation of the URL to use for a GET request
- * @return an encoded string representation of the URL
- */
- public String toHttpGETString() {
- String tmp = remotePath+"?";
-
-
- for(Enumeration e = params.keys(); e.hasMoreElements();) {
- String k = (String)e.nextElement();
- String v = URLEncoder.encode((String)params.get(k));
- tmp += k+"="+v+"&";
- }
- //remove the last &
- tmp = tmp.substring(0, tmp.length()-1);
-
- //encode the result
- return tmp;
- }
-
-
- /**
- * Gets a string reprensentation of the parameters to use for a POST request
- * @return an eXist POST request xml fragment representing the parameters
- */
- public String toHttpPOSTString() {
- String tmp = remotePath+"?";
-
- String _start = (String)params.get("_start");
- if(_start == null)
- _start = "1";
- String _max = (String)params.get("_howmany");
- if(_max == null)
- _max = "10";
- String _query = (String)params.get("_query");
- String _variables = (String)params.get("_variables");
- String _typed = (String)params.get("_typed");
-
-
- String frag = "<exist:query xmlns:exist=\"" + Namespaces.EXIST_NS + "\" "+
- "start=\""+_start+"\" "+
- "max=\""+_max+"\" ";
- if(_typed != null)
- {
- frag += "typed=\""+_typed+"\" ";
- }
- frag += ">";
- if(_query != null)
- frag += "<exist:text>"+_query+"</exist:text>";
- if(_variables != null)
- frag += _variables;
- frag += "<exist:properties>";
-
- //properties
- for(Enumeration e = params.keys(); e.hasMoreElements();) {
- String k = (String)e.nextElement();
- if(k.equals("_query") || k.equals("_start") || k.equals("_howmany") || k.equals("_variables"))
- continue;
- String v = (String)params.get(k);
-
- frag += "<exist:property name=\""+k+"\" value=\""+v+"\"/>";
- }
-
- frag += "</exist:properties>";
- frag += "</exist:query>";
-
- //encode the result
- return frag;
- }
-}
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQExpressionImpl.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQExpressionImpl.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQExpressionImpl.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -82,7 +82,7 @@
* if so
* @throws XQException
*/
- protected void isExpressionClosed() throws XQException
+ protected void throwIfClosed() throws XQException
{
if(expressionClosed)
throw new XQException("The expression is no longer valid.");
@@ -119,7 +119,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindAtomicValue(javax.xml.namespace.QName, java.lang.String, javax.xml.xquery.XQItemType)
*/
public void bindAtomicValue(QName arg0, String arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindAtomicValue(arg0, arg1, arg2);
}
@@ -128,7 +128,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindBoolean(javax.xml.namespace.QName, boolean, javax.xml.xquery.XQItemType)
*/
public void bindBoolean(QName arg0, boolean arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindBoolean(arg0, arg1, arg2);
}
@@ -136,7 +136,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindByte(javax.xml.namespace.QName, byte, javax.xml.xquery.XQItemType)
*/
public void bindByte(QName arg0, byte arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindByte(arg0, arg1, arg2);
}
@@ -144,7 +144,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDouble(javax.xml.namespace.QName, double, javax.xml.xquery.XQItemType)
*/
public void bindDouble(QName arg0, double arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDouble(arg0, arg1, arg2);
}
@@ -152,7 +152,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindFloat(javax.xml.namespace.QName, float, javax.xml.xquery.XQItemType)
*/
public void bindFloat(QName arg0, float arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindFloat(arg0, arg1, arg2);
}
@@ -160,7 +160,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindInt(javax.xml.namespace.QName, int, javax.xml.xquery.XQItemType)
*/
public void bindInt(QName arg0, int arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindInt(arg0, arg1, arg2);
}
@@ -168,7 +168,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindItem(javax.xml.namespace.QName, javax.xml.xquery.XQItem)
*/
public void bindItem(QName arg0, XQItem arg1) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindItem(arg0, arg1);
}
@@ -176,7 +176,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindLong(javax.xml.namespace.QName, long, javax.xml.xquery.XQItemType)
*/
public void bindLong(QName arg0, long arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindLong(arg0, arg1, arg2);
}
@@ -184,7 +184,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindNode(javax.xml.namespace.QName, org.w3c.dom.Node, javax.xml.xquery.XQItemType)
*/
public void bindNode(QName arg0, Node arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindNode(arg0, arg1, arg2);
}
@@ -192,7 +192,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindObject(javax.xml.namespace.QName, java.lang.Object, javax.xml.xquery.XQItemType)
*/
public void bindObject(QName arg0, Object arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindObject(arg0, arg1, arg2);
}
@@ -200,7 +200,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindSequence(javax.xml.namespace.QName, javax.xml.xquery.XQSequence)
*/
public void bindSequence(QName arg0, XQSequence arg1) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindSequence(arg0, arg1);
}
@@ -208,7 +208,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindShort(javax.xml.namespace.QName, short, javax.xml.xquery.XQItemType)
*/
public void bindShort(QName arg0, short arg1, XQItemType arg2) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindShort(arg0, arg1, arg2);
}
@@ -216,7 +216,7 @@
* @see javax.xml.xquery.XQDynamicContext#getImplicitTimeZone()
*/
public TimeZone getImplicitTimeZone() throws XQException {
- isExpressionClosed();
+ throwIfClosed();
return dynamicContext.getImplicitTimeZone();
}
@@ -224,7 +224,7 @@
* @see javax.xml.xquery.XQDynamicContext#setImplicitTimeZone(java.util.TimeZone)
*/
public void setImplicitTimeZone(TimeZone arg0) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.setImplicitTimeZone(arg0);
}
@@ -233,7 +233,7 @@
* @throws XQException
*/
public XQStaticContext getStaticContext() throws XQException {
- isExpressionClosed();
+ throwIfClosed();
return this.staticContext;
}
@@ -241,7 +241,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDocument(javax.xml.namespace.QName, java.io.InputStream, javax.xml.xquery.XQItemType)
*/
public void bindDocument(QName varname, InputStream source, String namespaceURI, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDocument(varname, source, namespaceURI, type);
}
@@ -249,7 +249,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDocument(javax.xml.namespace.QName, java.io.Reader, javax.xml.xquery.XQItemType)
*/
public void bindDocument(QName varname, Reader source, String namespaceURI, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDocument(varname, source, namespaceURI, type);
}
@@ -257,7 +257,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDocument(javax.xml.namespace.QName, javax.xml.transform.Source, javax.xml.xquery.XQItemType)
*/
public void bindDocument(QName varName, Source value, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDocument(varName, value, type);
}
@@ -265,7 +265,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDocument(javax.xml.namespace.QName, java.lang.String, javax.xml.xquery.XQItemType)
*/
public void bindDocument(QName varName, String value, String namespaceURI, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDocument(varName, value, namespaceURI, type);
}
@@ -273,7 +273,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDocument(javax.xml.namespace.QName, org.xml.sax.XMLReader, javax.xml.xquery.XQItemType)
*/
public void bindDocument(QName varName, XMLReader value, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDocument(varName, value, type);
}
@@ -281,7 +281,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindDocument(javax.xml.namespace.QName, javax.xml.stream.XMLStreamReader, javax.xml.xquery.XQItemType)
*/
public void bindDocument(QName varName, XMLStreamReader value, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindDocument(varName, value, type);
}
@@ -289,7 +289,7 @@
* @see javax.xml.xquery.XQDynamicContext#bindString(javax.xml.namespace.QName, java.lang.String, javax.xml.xquery.XQItemType)
*/
public void bindString(QName varName, String value, XQItemType type) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
dynamicContext.bindString(varName, value, type);
}
}
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -22,6 +22,7 @@
*/
package org.exist.xqj;
+import java.util.Enumeration;
import java.util.Hashtable;
import javax.xml.xquery.XQConstants;
@@ -162,14 +163,18 @@
/* (non-Javadoc)
* @see javax.xml.xquery.XQStaticContext#getNamespacePrefixes()
*/
- public String[] getNamespacePrefixes() {
- String[] l = new String[this.namespaces.size()];
- int i=0;
- while(namespaces.keys().hasMoreElements()) {
- String v = (String)namespaces.keys().nextElement();
- l[i++] = v;
+ public String[] getNamespacePrefixes()
+ {
+ String[] prefixes = new String[this.namespaces.size()];
+
+ int i = 0;
+ Enumeration enumPrefixes = namespaces.keys();
+ while(enumPrefixes.hasMoreElements())
+ {
+ String prefix = (String)enumPrefixes.nextElement();
+ prefixes[i++] = prefix;
}
- return l;
+ return prefixes;
}
/* (non-Javadoc)
Modified: branches/allad/jsr-225/src/org/exist/xqj/local/XQLocalExpression.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/local/XQLocalExpression.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/local/XQLocalExpression.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -106,7 +106,7 @@
* @see javax.xml.xquery.XQExpression#executeCommand(java.io.Reader)
*/
public void executeCommand(Reader reader) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
try {
StringBuilder str = new StringBuilder();
@@ -170,7 +170,7 @@
*/
public XQResultSequence executeQuery(String query) throws XQException
{
- isExpressionClosed();
+ throwIfClosed();
//close previous results seqences
closeResultSequences();
@@ -249,7 +249,7 @@
return broker == null;
}
- protected void isExpressionClosed() throws XQException
+ protected void throwIfClosed() throws XQException
{
if(broker == null)
throw new XQException("The expression is no longer valid.");
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -50,7 +50,8 @@
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpUriRequest;
import org.apache.log4j.Logger;
import org.exist.xqj.Constants;
import org.exist.xqj.EXistXQDataFactoryImpl;
@@ -132,14 +133,14 @@
private void checkResourceAvailable() throws XQException
{
- HttpGet get = new HttpGet(remoteURL); //TODO understand why HEAD isnt supported here probably in RESTServer?
+ HttpUriRequest head = new HttpHead(remoteURL); //TODO understand why HEAD isnt supported here probably in RESTServer?
try
{
//TODO replace head with get and check that the response looks like this -
//<rest:response xmlns:rest="" rel="nofollow">http://exist-db.org/rest">
//<rest:http method="GET" url="http://localhost:8080/exist/rest/db/mydoc.xml" status="200"/>
- HttpResponse response = httpClient.execute(get);
+ HttpResponse response = httpClient.execute(head);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
throw new XQException("Could not connect to the remote resource, response code: " + response.getStatusLine().getStatusCode() + " reason: " + response.getStatusLine().getReasonPhrase());
@@ -242,13 +243,13 @@
return;
//try and close each expression, if an exception occurs continue with the next
- //we can only throw one exception, so if there is one or more only catch the first one and then thow it at the end
- XQExpression expr = null;
+ //we can only throw one exception, so if there is one or more only catch the first one and then throw it at the end
XQException xqException = null;
try
{
- for(Iterator itExpr = expressions.iterator(); itExpr.hasNext(); expr = (XQExpression)itExpr.next())
+ for(Iterator itExpr = expressions.iterator(); itExpr.hasNext();)
{
+ XQExpression expr = (XQExpression)itExpr.next();
if(!expr.isClosed())
{
try
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpression.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpression.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpression.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -67,7 +67,7 @@
* @see javax.xml.xquery.XQExpression#executeCommand(java.io.Reader)
*/
public void executeCommand(Reader reader) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
try {
StringBuilder str = new StringBuilder();
char[] buf = new char[512];
@@ -91,7 +91,7 @@
* @see javax.xml.xquery.XQExpression#executeQuery(java.io.InputStream)
*/
public XQResultSequence executeQuery(InputStream arg) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
InputStreamReader reader = new InputStreamReader(arg);
return executeQuery(reader);
}
@@ -100,7 +100,7 @@
* @see javax.xml.xquery.XQExpression#executeQuery(java.io.Reader)
*/
public XQResultSequence executeQuery(Reader reader) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
try {
StringBuilder str = new StringBuilder();
char[] buf = new char[512];
@@ -116,12 +116,12 @@
* @see javax.xml.xquery.XQExpression#executeQuery(java.lang.String)
*/
public XQResultSequence executeQuery(String query) throws XQException {
- isExpressionClosed();
+ throwIfClosed();
//close previous results seqences
closeResultSequences();
- XQRemoteResultSequence seq = new XQRemoteResultSequence(this,query,dynamicContext,staticContext.getScrollability(),staticContext.getHoldability());
+ XQRemoteResultSequence seq = new XQRemoteResultSequence(this, query, dynamicContext, staticContext.getScrollability(), staticContext.getHoldability());
//cache
results.add(seq);
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpressionImpl.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpressionImpl.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteExpressionImpl.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -42,7 +42,7 @@
this.conn = conn;
}
- protected void isExpressionClosed() throws XQException
+ protected void throwIfClosed() throws XQException
{
if(conn == null)
throw new XQException("The expression is no longer valid.");
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemotePreparedExpression.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemotePreparedExpression.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemotePreparedExpression.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -67,7 +67,7 @@
}
public XQResultSequence executeQuery() throws XQException {
- isExpressionClosed();
+ throwIfClosed();
if(results != null) {
results.close();
}
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteResultSequence.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteResultSequence.java 2008-12-30 21:12:29 UTC (rev 8450)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteResultSequence.java 2008-12-30 21:21:57 UTC (rev 8451)
@@ -49,7 +49,7 @@
import org.apache.log4j.Logger;
import org.exist.memtree.SAXAdapter;
-import org.exist.xqj.EXistRESTURL;
+import org.exist.xqj.EXistRESTOperation;
import org.exist.xqj.EXistXQDynamicContext;
import org.exist.xqj.EXistXQResultSequence;
import org.exist.xqj.Marshaller;
@@ -191,18 +191,26 @@
*/
private InputStream getResultSet(int start) throws XQException{
String remote = this.expression.getRemoteConnection().getRemoteURL();
- EXistRESTURL url = new EXistRESTURL(remote);
- url.addParameter("_query", query);
- url.addParameter("_start", Integer.toString(start));
- url.addParameter("_howmany",Integer.toString(MAX_CACHE));
- url.addParameter("_encoding","UTF-8");
- url.addParameter("_variables", dynamicContext.externalVariables());
- url.addParameter("_typed","yes"); //tells the REST server to include type information about sequences
+ EXistRESTOperation rest = new EXistRESTOperation(remote);
+ rest.addParameter("_query", query);
+ rest.addParameter("_start", Integer.toString(start));
+ rest.addParameter("_howmany",Integer.toString(MAX_CACHE));
+ rest.addParameter("_encoding","UTF-8");
+ rest.addParameter("_variables", dynamicContext.externalVariables());
+ //quick hack for namespaces, following existing design conventions for external variables (this ALL needs to be revisited/re-designed!) - adam
+ String nsPrefixes[] = expression.getStaticContext().getNamespacePrefixes();
+ for(int i = 0; i < nsPrefixes.length; i++)
+ {
+ rest.addNamespace(nsPrefixes[i], expression.getStaticContext().getNamespaceURI(nsPrefixes[i]));
+ }
+
+ rest.addParameter("_typed","yes"); //tells the REST server to include type information about sequences
+
String user = this.expression.getRemoteConnection().getUsername();
String pwd = this.expression.getRemoteConnection().getPassword();
//get the response from the remote server
- return postResource(url.getRemoteURLPath(),url.toHttpPOSTString(),this.expression.getStaticContext().getQueryTimeout(),user,pwd);//TODO
+ return postResource(rest.getRemoteURLPath(),rest.toHttpPOSTString(),this.expression.getStaticContext().getQueryTimeout(),user,pwd);//TODO
/*String response=null;
try {
response = new String(resp,"UTF-8");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 21:12:33
|
Revision: 8450
http://exist.svn.sourceforge.net/exist/?rev=8450&view=rev
Author: deliriumsky
Date: 2008-12-30 21:12:29 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Partial merge of rev 8447 and 8449 from JSR-225/XQJ branch. Should ease future merges.
Support for namespaces in the POST Query message
Revision Links:
--------------
http://exist.svn.sourceforge.net/exist/?rev=8447&view=rev
Modified Paths:
--------------
trunk/eXist/src/org/exist/http/RESTServer.java
Modified: trunk/eXist/src/org/exist/http/RESTServer.java
===================================================================
--- trunk/eXist/src/org/exist/http/RESTServer.java 2008-12-30 21:10:16 UTC (rev 8449)
+++ trunk/eXist/src/org/exist/http/RESTServer.java 2008-12-30 21:12:29 UTC (rev 8450)
@@ -35,6 +35,8 @@
import org.exist.http.servlets.HttpRequestWrapper;
import org.exist.http.servlets.HttpResponseWrapper;
import org.exist.http.servlets.ResponseWrapper;
+import org.exist.memtree.ElementImpl;
+import org.exist.memtree.SAXAdapter;
import org.exist.security.Permission;
import org.exist.security.PermissionDeniedException;
import org.exist.security.xacml.AccessContext;
@@ -76,13 +78,17 @@
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.XMLFilterImpl;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerConfigurationException;
import java.io.File;
@@ -98,8 +104,10 @@
import java.io.Writer;
import java.net.URI;
import java.net.URLDecoder;
+import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
+import java.util.List;
import java.util.Properties;
/**
@@ -297,7 +305,7 @@
// query parameter specified, search method does all the rest of the
// work
try {
- search(broker, query, path, howmany, start, outputProperties,
+ search(broker, query, path, null, howmany, start, outputProperties,
wrap, cache, request, response);
} catch (XPathException e) {
@@ -595,20 +603,8 @@
Txn transaction = transact.beginTransaction();
try {
String content = getRequestContent(request);
- InputSource src = new InputSource(new StringReader(content));
- DocumentBuilderFactory docFactory = DocumentBuilderFactory
- .newInstance();
- docFactory.setNamespaceAware(true);
- DocumentBuilder docBuilder;
- try {
- docBuilder = docFactory.newDocumentBuilder();
- } catch (ParserConfigurationException e) {
- LOG.warn(e);
- transact.abort(transaction);
- throw new BadRequestException(e.getMessage());
- }
- Document doc = docBuilder.parse(src);
- Element root = doc.getDocumentElement();
+ NamespaceExtractor nsExtractor = new NamespaceExtractor();
+ Element root = parseXML(content, nsExtractor);
String rootNS = root.getNamespaceURI();
if (rootNS != null && rootNS.equals(Namespaces.EXIST_NS)) {
if (root.getLocalName().equals("query")) {
@@ -692,7 +688,7 @@
if (query != null) {
String result;
try {
- search(broker, query, path, howmany, start,
+ search(broker, query, path, nsExtractor.getNamespaces(), howmany, start,
outputProperties, enclose, cache, request,
response);
} catch (Exception e) {
@@ -777,6 +773,62 @@
}
}
+ private ElementImpl parseXML(String content, NamespaceExtractor nsExtractor) throws ParserConfigurationException, SAXException, IOException
+ {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ InputSource src = new InputSource(new StringReader(content));
+ SAXParser parser = factory.newSAXParser();
+ XMLReader reader = parser.getXMLReader();
+ SAXAdapter adapter = new SAXAdapter();
+ //reader.setContentHandler(adapter);
+ //reader.parse(src);
+ nsExtractor.setContentHandler(adapter);
+ nsExtractor.setParent(reader);
+ nsExtractor.parse(src);
+
+ Document doc = adapter.getDocument();
+
+ return (ElementImpl) doc.getDocumentElement();
+ }
+
+ private class NamespaceExtractor extends XMLFilterImpl
+ {
+ List namespaces = new ArrayList(); //<Namespace>
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException
+ {
+ Namespace ns = new Namespace(prefix, uri);
+ namespaces.add(ns);
+ super.startPrefixMapping(prefix, uri);
+ }
+
+ public List getNamespaces()
+ {
+ return namespaces;
+ }
+ }
+
+ private class Namespace
+ {
+ private String prefix = null;
+ private String uri = null;
+
+ public Namespace(String prefix, String uri)
+ {
+ this.prefix = prefix;
+ this.uri = uri;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+ }
+
/**
* Creates an input source from a URL location with an optional known
* charset.
@@ -974,7 +1026,7 @@
* @throws XPathException
*/
protected void search(DBBroker broker, String query, String path,
- int howmany, int start, Properties outputProperties, boolean wrap,
+ List/*<Namespace>*/ namespaces, int howmany, int start, Properties outputProperties, boolean wrap,
boolean cache, HttpServletRequest request,
HttpServletResponse response) throws BadRequestException,
PermissionDeniedException, XPathException {
@@ -1013,6 +1065,7 @@
context = compiled.getContext();
context.setStaticallyKnownDocuments(new XmldbURI[] { pathUri });
context.setBaseURI(new AnyURIValue(pathUri.toString()));
+ declareNamespaces(context, namespaces);
declareVariables(context, request, response);
if (compiled == null)
@@ -1047,6 +1100,18 @@
}
}
+ private void declareNamespaces(XQueryContext context, List/*<Namespace>*/ namespaces) throws XPathException
+ {
+ if(namespaces == null)
+ return;
+
+ for(int i = 0; i < namespaces.size(); i++)
+ {
+ Namespace ns = (Namespace)namespaces.get(i);
+ context.declareNamespace(ns.getPrefix(), ns.getUri());
+ }
+ }
+
/**
* Pass the request, response and session objects to the XQuery context.
*
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 21:10:25
|
Revision: 8449
http://exist.svn.sourceforge.net/exist/?rev=8449&view=rev
Author: deliriumsky
Date: 2008-12-30 21:10:16 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
fixed typo
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/http/RESTServer.java
Modified: branches/allad/jsr-225/src/org/exist/http/RESTServer.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/http/RESTServer.java 2008-12-30 21:02:17 UTC (rev 8448)
+++ branches/allad/jsr-225/src/org/exist/http/RESTServer.java 2008-12-30 21:10:16 UTC (rev 8449)
@@ -1162,7 +1162,7 @@
context = compiled.getContext();
context.setStaticallyKnownDocuments(new XmldbURI[] { pathUri });
context.setBaseURI(new AnyURIValue(pathUri.toString()));
- declareNamespace(context, namespaces);
+ declareNamespaces(context, namespaces);
declareVariables(context, variables, request, response);
if (compiled == null)
@@ -1197,7 +1197,7 @@
}
}
- private void declareNamespace(XQueryContext context, List/*<Namespace>*/ namespaces) throws XPathException
+ private void declareNamespaces(XQueryContext context, List/*<Namespace>*/ namespaces) throws XPathException
{
if(namespaces == null)
return;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 21:02:20
|
Revision: 8448
http://exist.svn.sourceforge.net/exist/?rev=8448&view=rev
Author: deliriumsky
Date: 2008-12-30 21:02:17 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Partial merge of rev 8441 from JSR-225/XQJ branch. Should ease future merges.
HTTP HEAD support for Collections.
Revision Links:
--------------
http://exist.svn.sourceforge.net/exist/?rev=8441&view=rev
Modified Paths:
--------------
trunk/eXist/src/org/exist/http/RESTServer.java
Modified: trunk/eXist/src/org/exist/http/RESTServer.java
===================================================================
--- trunk/eXist/src/org/exist/http/RESTServer.java 2008-12-30 20:51:04 UTC (rev 8447)
+++ trunk/eXist/src/org/exist/http/RESTServer.java 2008-12-30 21:02:17 UTC (rev 8448)
@@ -435,29 +435,58 @@
}
}
- public void doHead(DBBroker broker, HttpServletRequest request,
- HttpServletResponse response, String path)
- throws BadRequestException, PermissionDeniedException,
- NotFoundException, IOException {
+ public void doHead(DBBroker broker, HttpServletRequest request, HttpServletResponse response, String path) throws BadRequestException, PermissionDeniedException, NotFoundException, IOException
+ {
+ Properties outputProperties = new Properties(defaultOutputKeysProperties);
+ String mimeType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
+
+ String encoding;
+ if ((encoding = request.getParameter("_encoding")) != null)
+ outputProperties.setProperty(OutputKeys.ENCODING, encoding);
+ else
+ encoding = "UTF-8";
+
DocumentImpl resource = null;
XmldbURI pathUri = XmldbURI.create(path);
- try {
+ try
+ {
resource = broker.getXMLResource(pathUri, Lock.READ_LOCK);
- if (resource == null) {
- throw new NotFoundException("Resource " + pathUri
- + " not found");
+
+ if(resource != null)
+ {
+ if (!resource.getPermissions().validate(broker.getUser(),
+ Permission.READ)) {
+ throw new PermissionDeniedException(
+ "Permission to read resource " + path + " denied");
+ }
+ DocumentMetadata metadata = resource.getMetadata();
+ response.setContentType(metadata.getMimeType());
+ response.setContentLength(resource.getContentLength());
+ response.addDateHeader("Last-Modified", metadata.getLastModified());
+ response.addDateHeader("Created", metadata.getCreated());
}
- if (!resource.getPermissions().validate(broker.getUser(),
- Permission.READ)) {
- throw new PermissionDeniedException(
- "Permission to read resource " + path + " denied");
+ else
+ {
+ Collection col = broker.getCollection(pathUri);
+ //no resource or collection
+ if(col == null)
+ {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "No resource at location: " + path);
+
+ return;
+ }
+
+ if(!col.getPermissions().validate(broker.getUser(), Permission.READ))
+ {
+ throw new PermissionDeniedException(
+ "Permission to read resource " + path + " denied");
+ }
+ response.setContentType(MimeType.XML_TYPE.getName() + "; charset=" + encoding);
+ response.addDateHeader("Created", col.getCreationTime());
}
- DocumentMetadata metadata = resource.getMetadata();
- response.setContentType(metadata.getMimeType());
- response.setContentLength(resource.getContentLength());
- response.addDateHeader("Last-Modified", metadata.getLastModified());
- response.addDateHeader("Created", metadata.getCreated());
- } finally {
+ }
+ finally
+ {
if (resource != null)
resource.getUpdateLock().release(Lock.READ_LOCK);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 20:51:08
|
Revision: 8447
http://exist.svn.sourceforge.net/exist/?rev=8447&view=rev
Author: deliriumsky
Date: 2008-12-30 20:51:04 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Support for namespaces in the POST Query message
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/http/RESTServer.java
Modified: branches/allad/jsr-225/src/org/exist/http/RESTServer.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/http/RESTServer.java 2008-12-30 20:44:51 UTC (rev 8446)
+++ branches/allad/jsr-225/src/org/exist/http/RESTServer.java 2008-12-30 20:51:04 UTC (rev 8447)
@@ -34,8 +34,10 @@
import java.io.Writer;
import java.net.URI;
import java.net.URLDecoder;
+import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
+import java.util.List;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
@@ -111,6 +113,7 @@
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.XMLFilterImpl;
/**
*
@@ -248,10 +251,15 @@
query = request.getParameter("_query");
String _var = request.getParameter("_variables");
+ List /*<Namespace>*/ namespaces = null;
NodeImpl variables = null;
try {
if (_var != null)
- variables = parseXML(_var);
+ {
+ NamespaceExtractor nsExtractor = new NamespaceExtractor();
+ variables = parseXML(_var, nsExtractor);
+ namespaces = nsExtractor.getNamespaces();
+ }
} catch (SAXException e) {
XPathException x = new XPathException(e.toString());
EXistServlet.SendXMLResponse(request, response,
@@ -330,7 +338,7 @@
// query parameter specified, search method does all the rest of the
// work
try {
- search(broker, query, path, variables, howmany, start, typed,
+ search(broker, query, path, namespaces, variables, howmany, start, typed,
outputProperties, wrap, cache, request, response);
} catch (XPathException e) {
@@ -659,7 +667,8 @@
Txn transaction = null;
try {
String content = getRequestContent(request);
- Element root = parseXML(content);
+ NamespaceExtractor nsExtractor = new NamespaceExtractor();
+ Element root = parseXML(content, nsExtractor);
String rootNS = root.getNamespaceURI();
if (rootNS != null && rootNS.equals(Namespaces.EXIST_NS)) {
if (root.getLocalName().equals("query")) {
@@ -752,7 +761,7 @@
if (query != null) {
String result;
try {
- search(broker, query, path, variables, howmany, start,
+ search(broker, query, path, nsExtractor.getNamespaces(), variables, howmany, start,
typed, outputProperties, enclose, cache,
request, response);
} catch (XPathException xpe) {
@@ -847,7 +856,7 @@
}
}
- private ElementImpl parseXML(String content)
+ private ElementImpl parseXML(String content, NamespaceExtractor nsExtractor)
throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
@@ -855,14 +864,54 @@
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
SAXAdapter adapter = new SAXAdapter();
- reader.setContentHandler(adapter);
- reader.parse(src);
-
+ //reader.setContentHandler(adapter);
+ //reader.parse(src);
+ nsExtractor.setContentHandler(adapter);
+ nsExtractor.setParent(reader);
+ nsExtractor.parse(src);
+
Document doc = adapter.getDocument();
return (ElementImpl) doc.getDocumentElement();
}
+ private class NamespaceExtractor extends XMLFilterImpl
+ {
+ List namespaces = new ArrayList(); //<Namespace>
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException
+ {
+ Namespace ns = new Namespace(prefix, uri);
+ namespaces.add(ns);
+ super.startPrefixMapping(prefix, uri);
+ }
+
+ public List getNamespaces()
+ {
+ return namespaces;
+ }
+ }
+
+ private class Namespace
+ {
+ private String prefix = null;
+ private String uri = null;
+
+ public Namespace(String prefix, String uri)
+ {
+ this.prefix = prefix;
+ this.uri = uri;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public String getUri() {
+ return uri;
+ }
+ }
+
/**
* Creates an input source from a URL location with an optional known
* charset.
@@ -1073,7 +1122,7 @@
* @throws XPathException
*/
protected void search(DBBroker broker, String query, String path,
- Node variables, int howmany, int start, boolean typed,
+ List /*<Namespace>*/namespaces, Node variables, int howmany, int start, boolean typed,
Properties outputProperties, boolean wrap, boolean cache,
HttpServletRequest request, HttpServletResponse response)
throws BadRequestException, PermissionDeniedException,
@@ -1113,6 +1162,7 @@
context = compiled.getContext();
context.setStaticallyKnownDocuments(new XmldbURI[] { pathUri });
context.setBaseURI(new AnyURIValue(pathUri.toString()));
+ declareNamespace(context, namespaces);
declareVariables(context, variables, request, response);
if (compiled == null)
@@ -1147,6 +1197,18 @@
}
}
+ private void declareNamespace(XQueryContext context, List/*<Namespace>*/ namespaces) throws XPathException
+ {
+ if(namespaces == null)
+ return;
+
+ for(int i = 0; i < namespaces.size(); i++)
+ {
+ Namespace ns = (Namespace)namespaces.get(i);
+ context.declareNamespace(ns.getPrefix(), ns.getUri());
+ }
+ }
+
/**
* Pass the request, response and session objects to the XQuery context.
*
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2008-12-30 20:44:57
|
Revision: 8446
http://exist.svn.sourceforge.net/exist/?rev=8446&view=rev
Author: brihaye
Date: 2008-12-30 20:44:51 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
[ignore] refactored imports
Modified Paths:
--------------
trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/Query.java
Modified: trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/Query.java
===================================================================
--- trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/Query.java 2008-12-30 20:41:59 UTC (rev 8445)
+++ trunk/eXist/extensions/indexes/lucene/src/org/exist/xquery/modules/lucene/Query.java 2008-12-30 20:44:51 UTC (rev 8446)
@@ -1,38 +1,37 @@
package org.exist.xquery.modules.lucene;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
import org.apache.lucene.queryParser.ParseException;
import org.exist.dom.DocumentSet;
import org.exist.dom.NodeSet;
import org.exist.dom.QName;
import org.exist.indexing.lucene.LuceneIndex;
import org.exist.indexing.lucene.LuceneIndexWorker;
-import org.exist.indexing.ngram.NGramIndexWorker;
-import org.exist.indexing.ngram.NGramIndex;
+import org.exist.storage.ElementValue;
import org.exist.xquery.AnalyzeContextInfo;
import org.exist.xquery.Atomize;
+import org.exist.xquery.BasicExpressionVisitor;
import org.exist.xquery.Cardinality;
+import org.exist.xquery.Constants;
import org.exist.xquery.Dependency;
import org.exist.xquery.DynamicCardinalityCheck;
import org.exist.xquery.Expression;
import org.exist.xquery.Function;
import org.exist.xquery.FunctionSignature;
-import org.exist.xquery.XPathException;
-import org.exist.xquery.XQueryContext;
-import org.exist.xquery.BasicExpressionVisitor;
import org.exist.xquery.LocationStep;
-import org.exist.xquery.Constants;
import org.exist.xquery.NodeTest;
import org.exist.xquery.Optimizable;
+import org.exist.xquery.XPathException;
+import org.exist.xquery.XQueryContext;
+import org.exist.xquery.modules.lucene.LuceneModule;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;
-import org.exist.storage.ElementValue;
-import java.io.IOException;
-import java.util.List;
-import java.util.ArrayList;
-
public class Query extends Function implements Optimizable {
public final static FunctionSignature signature =
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2008-12-30 20:42:05
|
Revision: 8445
http://exist.svn.sourceforge.net/exist/?rev=8445&view=rev
Author: brihaye
Date: 2008-12-30 20:41:59 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
[ignore] Removed Eclipse's builder, which has never worked AFAICT
Modified Paths:
--------------
trunk/eXist/.project
Modified: trunk/eXist/.project
===================================================================
--- trunk/eXist/.project 2008-12-30 20:38:40 UTC (rev 8444)
+++ trunk/eXist/.project 2008-12-30 20:41:59 UTC (rev 8445)
@@ -6,16 +6,6 @@
</projects>
<buildSpec>
<buildCommand>
- <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
- <triggers>full,incremental,</triggers>
- <arguments>
- <dictionary>
- <key>LaunchConfigHandle</key>
- <value><project>/.externalToolBuilders/Ant builder.launch</value>
- </dictionary>
- </arguments>
- </buildCommand>
- <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <br...@us...> - 2008-12-30 20:38:43
|
Revision: 8444
http://exist.svn.sourceforge.net/exist/?rev=8444&view=rev
Author: brihaye
Date: 2008-12-30 20:38:40 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
[ignore] upgraded Eclipse's source paths
Modified Paths:
--------------
trunk/eXist/.classpath
Modified: trunk/eXist/.classpath
===================================================================
--- trunk/eXist/.classpath 2008-12-30 20:26:56 UTC (rev 8443)
+++ trunk/eXist/.classpath 2008-12-30 20:38:40 UTC (rev 8444)
@@ -1,16 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="extensions/fluent/src"/>
+ <classpathentry kind="src" path="extensions/fluent/test/src"/>
+ <classpathentry kind="src" path="extensions/indexes/lucene/src"/>
+ <classpathentry kind="src" path="extensions/indexes/lucene/test/src"/>
+ <classpathentry kind="src" path="extensions/indexes/ngram/src"/>
+ <classpathentry kind="src" path="extensions/indexes/ngram/test/src"/>
+ <classpathentry kind="src" path="extensions/indexes/spatial/src"/>
+ <classpathentry kind="src" path="extensions/indexes/spatial/test/src"/>
+ <classpathentry kind="src" path="extensions/modules/src"/>
<classpathentry kind="src" path="tools/ircbot/src"/>
<classpathentry kind="src" path="tools/requestlog/src"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test/src"/>
<classpathentry kind="src" path="tools/wrapper/src"/>
- <classpathentry kind="src" path="extensions/modules/src"/>
- <classpathentry kind="src" path="extensions/indexes/ngram/src"/>
- <classpathentry kind="src" path="extensions/indexes/ngram/test/src"/>
- <classpathentry kind="src" path="extensions/indexes/spatial/src"/>
- <classpathentry kind="src" path="extensions/indexes/spatial/test/src"/>
<classpathentry kind="src" path="samples/src"/>
<classpathentry kind="lib" path="lib/core/jEdit-syntax.jar" sourcepath="/jEdit-syntax"/>
<classpathentry kind="lib" path="extensions/indexes/spatial/lib/gt2-api-2.4-M1.jar"/>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ch...@us...> - 2008-12-30 20:27:00
|
Revision: 8443
http://exist.svn.sourceforge.net/exist/?rev=8443&view=rev
Author: chaeron
Date: 2008-12-30 20:26:56 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
SQL Extension Module refactored to use memtree builder rather than constructing XML as a string and then parsing it.
Required the addition of a setNodeValue() method in org.exist.memtree.AttributeImpl to make it possible to set the count attribute on the root element to the number of rows returned in a SQL ResultSet.
Modified Paths:
--------------
trunk/eXist/extensions/modules/src/org/exist/xquery/modules/sql/ExecuteFunction.java
trunk/eXist/src/org/exist/memtree/AttributeImpl.java
Modified: trunk/eXist/extensions/modules/src/org/exist/xquery/modules/sql/ExecuteFunction.java
===================================================================
--- trunk/eXist/extensions/modules/src/org/exist/xquery/modules/sql/ExecuteFunction.java 2008-12-30 17:56:02 UTC (rev 8442)
+++ trunk/eXist/extensions/modules/src/org/exist/xquery/modules/sql/ExecuteFunction.java 2008-12-30 20:26:56 UTC (rev 8443)
@@ -31,6 +31,9 @@
import org.exist.Namespaces;
import org.exist.dom.QName;
+import org.exist.memtree.DocumentBuilderReceiver;
+import org.exist.memtree.MemTreeBuilder;
+import org.exist.memtree.NodeImpl;
import org.exist.xquery.BasicFunction;
import org.exist.xquery.Cardinality;
import org.exist.xquery.FunctionSignature;
@@ -39,11 +42,16 @@
import org.exist.xquery.modules.ModuleUtils;
import org.exist.xquery.value.BooleanValue;
import org.exist.xquery.value.IntegerValue;
+import org.exist.xquery.value.NodeValue;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceType;
import org.exist.xquery.value.Type;
-import org.xml.sax.SAXException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
/**
* eXist SQL Module Extension ExecuteFunction
*
@@ -56,15 +64,17 @@
* @see org.exist.xquery.BasicFunction#BasicFunction(org.exist.xquery.XQueryContext,
* org.exist.xquery.FunctionSignature)
*/
-public class ExecuteFunction extends BasicFunction {
+public class ExecuteFunction extends BasicFunction
+{
public final static FunctionSignature[] signatures = { new FunctionSignature(
- new QName("execute", SQLModule.NAMESPACE_URI, SQLModule.PREFIX),
- "Executes a SQL statement $b against a SQL db using the connection indicated by the connection handle in $a. $c indicates whether the xml nodes should be formed from the column names (in this mode a space in a Column Name will be replaced by an underscore!)",
- new SequenceType[] {
- new SequenceType(Type.INTEGER, Cardinality.EXACTLY_ONE),
- new SequenceType(Type.STRING, Cardinality.EXACTLY_ONE),
- new SequenceType(Type.BOOLEAN, Cardinality.EXACTLY_ONE) },
- new SequenceType(Type.NODE, Cardinality.ZERO_OR_ONE)) };
+ new QName( "execute", SQLModule.NAMESPACE_URI, SQLModule.PREFIX ),
+ "Executes a SQL statement $b against a SQL db using the connection indicated by the connection handle in $a. $c indicates whether the xml nodes should be formed from the column names (in this mode a space in a Column Name will be replaced by an underscore!)",
+ new SequenceType[] {
+ new SequenceType( Type.INTEGER, Cardinality.EXACTLY_ONE ),
+ new SequenceType( Type.STRING, Cardinality.EXACTLY_ONE ),
+ new SequenceType( Type.BOOLEAN, Cardinality.EXACTLY_ONE ) },
+ new SequenceType( Type.NODE, Cardinality.ZERO_OR_ONE )
+ ) };
/**
* ExecuteFunction Constructor
@@ -72,8 +82,9 @@
* @param context
* The Context of the calling XQuery
*/
- public ExecuteFunction(XQueryContext context, FunctionSignature signature) {
- super(context, signature);
+ public ExecuteFunction( XQueryContext context, FunctionSignature signature )
+ {
+ super( context, signature );
}
/**
@@ -89,18 +100,18 @@
* @see org.exist.xquery.BasicFunction#eval(org.exist.xquery.value.Sequence[],
* org.exist.xquery.value.Sequence)
*/
- public Sequence eval(Sequence[] args, Sequence contextSequence)
- throws XPathException {
+ public Sequence eval( Sequence[] args, Sequence contextSequence ) throws XPathException
+ {
// was a connection and SQL statement specified?
- if (args[0].isEmpty() || args[1].isEmpty()) {
- return (Sequence.EMPTY_SEQUENCE );
+ if( args[0].isEmpty() || args[1].isEmpty() ) {
+ return( Sequence.EMPTY_SEQUENCE );
}
// get the Connection
long connectionUID = ((IntegerValue) args[0].itemAt(0)).getLong();
- Connection con = SQLModule.retrieveConnection(context, connectionUID);
- if (con == null) {
- return Sequence.EMPTY_SEQUENCE;
+ Connection con = SQLModule.retrieveConnection( context, connectionUID );
+ if( con == null ) {
+ return( Sequence.EMPTY_SEQUENCE );
}
// get the SQL statement
@@ -110,134 +121,131 @@
ResultSet rs = null;
try {
- StringBuffer xmlBuf = new StringBuffer();
+ MemTreeBuilder builder = context.getDocumentBuilder();
+ int iRow = 0;
// execute the SQL statement
stmt = con.createStatement();
// execute the query statement
- if (stmt.execute(sql)) {
+ if( stmt.execute( sql ) ) {
/* SQL Query returned results */
// iterate through the result set building an XML document
rs = stmt.getResultSet();
ResultSetMetaData rsmd = rs.getMetaData();
int iColumns = rsmd.getColumnCount();
- int iRows = 0;
+
+ builder.startDocument();
+
+ builder.startElement( new QName( "result", SQLModule.NAMESPACE_URI, SQLModule.PREFIX ), null );
+ builder.addAttribute( new QName( "count", null, null ), String.valueOf( -1 ) );
+
+ while( rs.next() ) {
+ builder.startElement( new QName( "row", SQLModule.NAMESPACE_URI, SQLModule.PREFIX ), null );
+ builder.addAttribute( new QName( "index", null, null ), String.valueOf( rs.getRow() ) );
- while (rs.next()) {
- xmlBuf.append("<" + SQLModule.PREFIX + ":row index=\""
- + rs.getRow() + "\">");
-
// get each tuple in the row
- for (int i = 0; i < iColumns; i++) {
- String columnName = rsmd.getColumnName(i + 1);
+ for( int i = 0; i < iColumns; i++ ) {
+ String columnName = rsmd.getColumnName( i + 1 );
- if (columnName != null) {
+ if( columnName != null ) {
- String colValue = rs.getString(i + 1);
- String sqlNull = "";
+ String colValue = rs.getString( i + 1 );
+
+ String colElement = "field";
- if (rs.wasNull()) {
- // Add a null indicator attributed if the value
- // was SQL Null
- sqlNull = " " + SQLModule.PREFIX
- + ":null=\"true\"";
- }
-
- if (((BooleanValue) args[2].itemAt(0))
- .effectiveBooleanValue()) {
+ if( ((BooleanValue)args[2].itemAt(0)).effectiveBooleanValue() && columnName.length() > 0 ) {
// use column names as the XML node
/**
* Spaces in column names are replaced with
* underscore's
*/
- xmlBuf
- .append("<"
- + escapeXmlAttr(columnName
- .replace(' ', '_'))
- + " "
- + SQLModule.PREFIX
- + ":type=\""
- + rsmd.getColumnTypeName(i + 1)
- + "\" xs:type=\""
- + Type
- .getTypeName(sqlTypeToXMLType(rsmd
- .getColumnType(i + 1)))
- + "\"" + sqlNull + " >");
- if (colValue != null) {
- xmlBuf.append(escapeXmlText(colValue));
+
+ colElement = escapeXmlAttr( columnName.replace( ' ', '_' ) );
+ }
+
+ builder.startElement( new QName( colElement, SQLModule.NAMESPACE_URI, SQLModule.PREFIX ), null );
+
+ if( !((BooleanValue)args[2].itemAt(0)).effectiveBooleanValue() || columnName.length() <= 0 ) {
+ String name;
+
+ if( columnName.length() > 0 ) {
+ name = escapeXmlAttr( columnName );
+ } else {
+ name = "Column: " + String.valueOf( i + 1 );
}
- xmlBuf.append("</"
- + escapeXmlAttr(columnName.replace(' ',
- '_')) + ">");
- } else {
- // DONT use column names as the XML node
- xmlBuf
- .append("<"
- + SQLModule.PREFIX
- + ":field name=\""
- + escapeXmlAttr(columnName)
- + "\" sql:type=\""
- + rsmd.getColumnTypeName(i + 1)
- + "\" xs:type=\""
- + Type
- .getTypeName(sqlTypeToXMLType(rsmd
- .getColumnType(i + 1)))
- + "\"" + sqlNull + " >");
- if (colValue != null) {
- xmlBuf.append(escapeXmlText(colValue));
- }
- xmlBuf.append("</" + SQLModule.PREFIX
- + ":field>");
+
+ builder.addAttribute( new QName( "name", null, null ), name );
}
+
+ builder.addAttribute( new QName( "type", SQLModule.NAMESPACE_URI, SQLModule.PREFIX ), rsmd.getColumnTypeName( i + 1 ) );
+ builder.addAttribute( new QName( "type", Namespaces.SCHEMA_NS, "xs" ), Type.getTypeName( sqlTypeToXMLType( rsmd.getColumnType( i + 1 ) ) ) );
+
+ if( rs.wasNull() ) {
+ // Add a null indicator attribute if the value was SQL Null
+ builder.addAttribute( new QName( "null", SQLModule.NAMESPACE_URI, SQLModule.PREFIX ), "true" );
+ }
+
+ if( colValue != null ) {
+ builder.characters( escapeXmlText( colValue ) );
+ }
+
+ builder.endElement();
}
}
- xmlBuf.append("</" + SQLModule.PREFIX + ":row>");
-
- iRows++;
+ builder.endElement();
+
+ iRow++;
}
- xmlBuf.insert(0, "<" + SQLModule.PREFIX + ":result xmlns:"
- + SQLModule.PREFIX + "=\"" + SQLModule.NAMESPACE_URI
- + "\" xmlns:xs=\"" + Namespaces.SCHEMA_NS
- + "\" count=\"" + iRows + "\">");
- xmlBuf.append("</" + SQLModule.PREFIX + ":result>");
+
+ builder.endElement();
+
} else {
/* SQL Query performed updates */
- xmlBuf.append("<" + SQLModule.PREFIX + ":result xmlns:"
- + SQLModule.PREFIX + "=\"" + SQLModule.NAMESPACE_URI
- + "\" updateCount=\"" + stmt.getUpdateCount() + "\"/>");
+
+ builder.startDocument();
+
+ builder.startElement( new QName( "result", SQLModule.NAMESPACE_URI, SQLModule.PREFIX ), null );
+ builder.addAttribute( new QName( "updateCount", null, null ), String.valueOf( stmt.getUpdateCount() ) );
+
+ builder.endElement();
}
+
+ // Change the root element count attribute to have the correct value
+
+ NodeValue node = (NodeValue)builder.getDocument().getDocumentElement();
+ Node count = node.getNode().getAttributes().getNamedItem( "count" );
+
+ if( count != null ) {
+ count.setNodeValue( String.valueOf( iRow ) );
+ }
+
// return the XML result set
- return ModuleUtils.stringToXML(context, xmlBuf.toString());
- } catch (SAXException saxe) {
- LOG.error(
- "sql:execute() Could not serialize SQL results to XML for SQL: \""
- + sql + "\"", saxe);
- throw new XPathException(getASTNode(),
- "sql:execute() Could not serialize SQL results to XML for SQL: \""
- + sql + "\"", saxe);
- } catch (SQLException sqle) {
- LOG.error("sql:execute() Caught SQLException for SQL: \"" + sql
- + "\"", sqle);
- throw new XPathException(getASTNode(),
- "sql:execute() Caught SQLException for SQL: \"" + sql
- + "\"", sqle);
- } finally {
+
+ return( node );
+
+ }
+ catch( SQLException sqle ) {
+ LOG.error( "sql:execute() Caught SQLException for SQL: \"" + sql + "\"", sqle );
+ throw( new XPathException( getASTNode(), "sql:execute() Caught SQLException for SQL: \"" + sql + "\"", sqle ) );
+ }
+ finally {
// close any record set or statement
try {
- if (rs != null) {
+ if( rs != null ) {
rs.close();
}
- if (stmt != null) {
+ if( stmt != null ) {
stmt.close();
}
- } catch (SQLException se) {
- LOG.debug("Unable to cleanup JDBC results", se);
+ }
+ catch( SQLException se ) {
+ LOG.debug( "Unable to cleanup JDBC results", se );
}
// explicitly ready for Garbage Collection
@@ -254,7 +262,8 @@
*
* @return The XML Type as specified by eXist
*/
- private int sqlTypeToXMLType(int sqlType) {
+ private int sqlTypeToXMLType( int sqlType )
+ {
switch (sqlType) {
case Types.ARRAY:
return Type.NODE;
@@ -312,27 +321,29 @@
}
}
- private static String escapeXmlText(String text) {
+ private static String escapeXmlText( String text )
+ {
String work = null;
- if (text != null) {
- work = text.replaceAll("\\&", "\\&");
- work = work.replaceAll("<", "\\<");
- work = work.replaceAll(">", "\\>");
+ if( text != null ) {
+ work = text.replaceAll( "\\&", "\\&" );
+ work = work.replaceAll( "<", "\\<" );
+ work = work.replaceAll( ">", "\\>" );
}
- return (work);
+ return( work );
}
- private static String escapeXmlAttr(String attr) {
+ private static String escapeXmlAttr( String attr )
+ {
String work = null;
- if (attr != null) {
- work = escapeXmlText(attr);
- work = work.replaceAll("'", "\\'");
- work = work.replaceAll("\"", "\\"");
+ if( attr != null ) {
+ work = escapeXmlText( attr );
+ work = work.replaceAll( "'", "\\'" );
+ work = work.replaceAll( "\"", "\\"" );
}
- return (work);
+ return( work );
}
}
Modified: trunk/eXist/src/org/exist/memtree/AttributeImpl.java
===================================================================
--- trunk/eXist/src/org/exist/memtree/AttributeImpl.java 2008-12-30 17:56:02 UTC (rev 8442)
+++ trunk/eXist/src/org/exist/memtree/AttributeImpl.java 2008-12-30 20:26:56 UTC (rev 8443)
@@ -139,6 +139,14 @@
}
/* (non-Javadoc)
+ * @see org.w3c.dom.Node#setNodeValue(java.lang.String)
+ */
+ public void setNodeValue( String arg0 ) throws DOMException {
+ // This method was added to enable the SQL XQuery Exztension Module to change the value of an attribute after the fact - Andrzej
+ document.attrValue[nodeNumber] = arg0;
+ }
+
+ /* (non-Javadoc)
* @see org.w3c.dom.Attr#setValue(java.lang.String)
*/
public void setValue(String arg0) throws DOMException {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <ch...@us...> - 2008-12-30 17:56:07
|
Revision: 8442
http://exist.svn.sourceforge.net/exist/?rev=8442&view=rev
Author: chaeron
Date: 2008-12-30 17:56:02 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Reworked httpclient module so that it doesn't use getResponseBody() or getResponseBodyAsString(), to avoid the warnings that can be generated by the Apache Commons HTTPClient library.
Still buffers the response in memory, so large responses can potentially use up all the JVM heap space.
Modified Paths:
--------------
trunk/eXist/extensions/modules/src/org/exist/xquery/modules/ModuleUtils.java
trunk/eXist/extensions/modules/src/org/exist/xquery/modules/httpclient/BaseHTTPClientFunction.java
Modified: trunk/eXist/extensions/modules/src/org/exist/xquery/modules/ModuleUtils.java
===================================================================
--- trunk/eXist/extensions/modules/src/org/exist/xquery/modules/ModuleUtils.java 2008-12-30 17:08:26 UTC (rev 8441)
+++ trunk/eXist/extensions/modules/src/org/exist/xquery/modules/ModuleUtils.java 2008-12-30 17:56:02 UTC (rev 8442)
@@ -21,6 +21,7 @@
*/
package org.exist.xquery.modules;
+import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Properties;
@@ -62,30 +63,51 @@
*
* @return The NodeValue of XML
*/
- public static NodeValue stringToXML(XQueryContext context, String xml)
- throws XPathException, SAXException {
+ public static NodeValue stringToXML( XQueryContext context, String xml ) throws XPathException, SAXException
+ {
+ return( streamToXML( context, new ByteArrayInputStream( xml.getBytes() ) ) );
+ }
+
+
+ /**
+ * Takes a InputStream of XML and Creates an XML Node from it using SAX in the
+ * context of the query
+ *
+ * @param context
+ * The Context of the calling XQuery
+ * @param xml
+ * The InputStream of XML
+ *
+ * @return The NodeValue of XML
+ */
+ public static NodeValue streamToXML( XQueryContext context, InputStream xml ) throws XPathException, SAXException
+ {
context.pushDocumentContext();
+
try {
// try and construct xml document from input stream, we use eXist's
// in-memory DOM implementation
- XMLReader reader= context.getBroker().getBrokerPool().getParserPool().borrowXMLReader();
- LOG.debug("Parsing XML response ...");
+ XMLReader reader= context.getBroker().getBrokerPool().getParserPool().borrowXMLReader();
+ LOG.debug( "Parsing XML response ..." );
+
// TODO : we should be able to cope with context.getBaseURI()
- InputSource src = new InputSource(new ByteArrayInputStream(xml.getBytes()));
+ InputSource src = new InputSource( xml );
MemTreeBuilder builder = context.getDocumentBuilder();
- DocumentBuilderReceiver receiver = new DocumentBuilderReceiver(
- builder);
- reader.setContentHandler(receiver);
- reader.parse(src);
+ DocumentBuilderReceiver receiver = new DocumentBuilderReceiver( builder );
+ reader.setContentHandler( receiver );
+ reader.parse( src );
Document doc = receiver.getDocument();
// return (NodeValue)doc.getDocumentElement();
- return (NodeValue) doc;
- } catch (IOException e) {
- throw new XPathException(e.getMessage());
- } finally {
+ return( (NodeValue)doc );
+ }
+ catch( IOException e ) {
+ throw( new XPathException(e.getMessage() ) );
+ }
+ finally {
context.popDocumentContext();
}
}
+
/**
* Takes a HTML InputSource and creates an XML representation of the HTML by
Modified: trunk/eXist/extensions/modules/src/org/exist/xquery/modules/httpclient/BaseHTTPClientFunction.java
===================================================================
--- trunk/eXist/extensions/modules/src/org/exist/xquery/modules/httpclient/BaseHTTPClientFunction.java 2008-12-30 17:08:26 UTC (rev 8441)
+++ trunk/eXist/extensions/modules/src/org/exist/xquery/modules/httpclient/BaseHTTPClientFunction.java 2008-12-30 17:56:02 UTC (rev 8442)
@@ -25,6 +25,8 @@
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.OptionsMethod;
+import org.apache.commons.httpclient.util.EncodingUtil;
+
import org.exist.dom.QName;
import org.exist.memtree.DocumentBuilderReceiver;
import org.exist.memtree.MemTreeBuilder;
@@ -39,12 +41,16 @@
import org.exist.xquery.value.Base64Binary;
import org.exist.xquery.value.NodeValue;
import org.exist.xquery.value.Sequence;
+
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.net.URLEncoder;
@@ -261,10 +267,25 @@
{
boolean parsed = false;
NodeImpl responseNode = null;
- String bodyAsString = method.getResponseBodyAsString();
+ InputStream bodyAsStream = method.getResponseBodyAsStream();
// check if there is a response body
- if( bodyAsString != null ) {
+ if( bodyAsStream != null ) {
+
+ long contentLength = ((HttpMethodBase)method).getResponseContentLength();
+ if( contentLength > Integer.MAX_VALUE ) { //guard from overflow
+ throw( new XPathException( getASTNode(), "HTTPClient response too large to be buffered: " + contentLength + " bytes" ) );
+ }
+
+ ByteArrayOutputStream outstream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int len;
+
+ while( ( len = bodyAsStream.read( buffer ) ) > 0 ) {
+ outstream.write( buffer, 0, len );
+ }
+ outstream.close();
+ byte[] body = outstream.toByteArray();
// determine the type of the response document
MimeType responseMimeType = getResponseMimeType( method.getResponseHeader( "Content-Type" ) );
@@ -272,8 +293,7 @@
//try and parse the response as XML
try {
- //TODO: replace getResponseBodyAsString() with getResponseBodyAsStream()
- responseNode = (NodeImpl)ModuleUtils.stringToXML( context, bodyAsString );
+ responseNode = (NodeImpl)ModuleUtils.streamToXML( context, new ByteArrayInputStream( body ) );
builder.addAttribute( new QName( "type", null, null ), "xml" );
responseNode.copyTo( null, new DocumentBuilderReceiver( builder ) );
}
@@ -289,7 +309,7 @@
//html document
try {
//parse html to xml(html)
- responseNode = (NodeImpl)ModuleUtils.htmlToXHtml(context, method.getURI().toString(), new InputSource(method.getResponseBodyAsStream() ) ).getDocumentElement();
+ responseNode = (NodeImpl)ModuleUtils.htmlToXHtml(context, method.getURI().toString(), new InputSource( new ByteArrayInputStream( body ) ) ).getDocumentElement();
builder.addAttribute( new QName( "type", null, null ), "xhtml" );
responseNode.copyTo( null, new DocumentBuilderReceiver( builder ) );
}
@@ -307,11 +327,9 @@
// Assume it's a text body and URL encode it
builder.addAttribute( new QName( "type", null, null ), "text" );
builder.addAttribute( new QName( "encoding", null, null ), "URLEncoded" );
- builder.characters( URLEncoder.encode( method.getResponseBodyAsString(), "UTF-8" ) );
+ builder.characters( URLEncoder.encode( EncodingUtil.getString( body, ((HttpMethodBase)method).getResponseCharSet() ), "UTF-8" ) );
} else {
- // Assume it's a binary body and Base64 encode it
- byte[] body = method.getResponseBody();
-
+ // Assume it's a binary body and Base64 encode it
builder.addAttribute( new QName( "type", null, null ), "binary" );
builder.addAttribute( new QName( "encoding", null, null ), "Base64Encoded" );
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 17:08:30
|
Revision: 8441
http://exist.svn.sourceforge.net/exist/?rev=8441&view=rev
Author: deliriumsky
Date: 2008-12-30 17:08:26 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
HTTP HEAD support for Collections
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/http/RESTServer.java
Modified: branches/allad/jsr-225/src/org/exist/http/RESTServer.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/http/RESTServer.java 2008-12-30 14:26:04 UTC (rev 8440)
+++ branches/allad/jsr-225/src/org/exist/http/RESTServer.java 2008-12-30 17:08:26 UTC (rev 8441)
@@ -490,29 +490,65 @@
}
}
- public void doHead(DBBroker broker, HttpServletRequest request,
- HttpServletResponse response, String path)
- throws BadRequestException, PermissionDeniedException,
- NotFoundException, IOException {
+ public void doHead(DBBroker broker, HttpServletRequest request, HttpServletResponse response, String path) throws BadRequestException, PermissionDeniedException, NotFoundException, IOException
+ {
+ Properties outputProperties = new Properties(defaultOutputKeysProperties);
+ String mimeType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
+
+ String encoding;
+ if ((encoding = request.getParameter("_encoding")) != null)
+ outputProperties.setProperty(OutputKeys.ENCODING, encoding);
+ else
+ encoding = "UTF-8";
+
DocumentImpl resource = null;
XmldbURI pathUri = XmldbURI.create(path);
- try {
+ try
+ {
resource = broker.getXMLResource(pathUri, Lock.READ_LOCK);
- if (resource == null) {
- throw new NotFoundException("Resource " + pathUri
- + " not found");
+
+ if(resource != null)
+ {
+ if (!resource.getPermissions().validate(broker.getUser(),
+ Permission.READ)) {
+ throw new PermissionDeniedException(
+ "Permission to read resource " + path + " denied");
+ }
+ DocumentMetadata metadata = resource.getMetadata();
+ response.setContentType(metadata.getMimeType());
+ response.setContentLength(resource.getContentLength());
+ response.addDateHeader("Last-Modified", metadata.getLastModified());
+ response.addDateHeader("Created", metadata.getCreated());
}
- if (!resource.getPermissions().validate(broker.getUser(),
- Permission.READ)) {
- throw new PermissionDeniedException(
- "Permission to read resource " + path + " denied");
+ else
+ {
+ Collection col = broker.getCollection(pathUri);
+
+ //no resource or collection
+ if(col == null)
+ {
+ if (MimeType.XML_TYPE.getName().equals(mimeType))
+ {
+ EXistServlet.SendXMLResponse(request, response, HttpServletResponse.SC_NOT_FOUND, "No resource at location: " + path, encoding);
+ }
+ else
+ {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "No resource at location: " + path);
+ }
+ return;
+ }
+
+ if(!col.getPermissions().validate(broker.getUser(), Permission.READ))
+ {
+ throw new PermissionDeniedException(
+ "Permission to read resource " + path + " denied");
+ }
+ response.setContentType(MimeType.XML_TYPE.getName() + "; charset=" + encoding);
+ response.addDateHeader("Created", col.getCreationTime());
}
- DocumentMetadata metadata = resource.getMetadata();
- response.setContentType(metadata.getMimeType());
- response.setContentLength(resource.getContentLength());
- response.addDateHeader("Last-Modified", metadata.getLastModified());
- response.addDateHeader("Created", metadata.getCreated());
- } finally {
+ }
+ finally
+ {
if (resource != null)
resource.getUpdateLock().release(Lock.READ_LOCK);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <wol...@us...> - 2008-12-30 14:26:08
|
Revision: 8440
http://exist.svn.sourceforge.net/exist/?rev=8440&view=rev
Author: wolfgang_m
Date: 2008-12-30 14:26:04 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
[feature] versioning extension: handle attribute insertion, deletion, modification. fixed some bugs; more tests.
Modified Paths:
--------------
trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/PatchFunction.java
trunk/eXist/extensions/versioning/test/test.xml
trunk/eXist/src/org/exist/dom/AttrImpl.java
trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java
trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java
trunk/eXist/src/org/exist/util/serializer/AttrList.java
Added Paths:
-----------
trunk/eXist/src/org/exist/stax/ExtendedXMLStreamReader.java
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -3,17 +3,20 @@
import org.exist.dom.NewArrayNodeSet;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
+import org.exist.dom.AttrImpl;
import org.exist.numbering.NodeId;
import org.exist.storage.DBBroker;
import org.exist.util.serializer.SAXSerializer;
import org.exist.util.serializer.SerializerPool;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.SequenceIterator;
+import org.exist.xquery.value.Type;
import org.exist.Namespaces;
import org.xml.sax.SAXException;
import org.xml.sax.ContentHandler;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.AttributesImpl;
+import org.w3c.dom.Node;
import java.io.StringWriter;
import java.util.Iterator;
@@ -34,7 +37,6 @@
public abstract void serialize(DBBroker broker, ContentHandler handler);
-
public static class Insert extends Difference {
protected NodeSet nodes = new NewArrayNodeSet(1, 8);
@@ -67,7 +69,15 @@
handler.startElement(XMLDiff.NAMESPACE, "insert", XMLDiff.PREFIX + ":insert", attribs);
for (SequenceIterator i = nodes.iterate(); i.hasNext(); ) {
NodeProxy proxy = (NodeProxy) i.nextItem();
- proxy.toSAX(broker, handler, null);
+ if (proxy.getType() == Type.ATTRIBUTE) {
+ AttrImpl attr = (AttrImpl) proxy.getNode();
+ attribs.clear();
+ attribs.addAttribute(attr.getNamespaceURI(), attr.getLocalName(), attr.getName(),
+ AttrImpl.getAttributeType(attr.getType()), attr.getValue());
+ handler.startElement(XMLDiff.NAMESPACE, "attribute", XMLDiff.PREFIX + ":attribute", attribs);
+ handler.endElement(XMLDiff.NAMESPACE, "attribute", XMLDiff.PREFIX + ":attribute");
+ } else
+ proxy.toSAX(broker, handler, null);
}
handler.endElement(XMLDiff.NAMESPACE, "insert", XMLDiff.PREFIX + ":insert");
} catch (XPathException e) {
@@ -91,7 +101,15 @@
handler.startElement(XMLDiff.NAMESPACE, "append", XMLDiff.PREFIX + ":append", attribs);
for (SequenceIterator i = nodes.iterate(); i.hasNext(); ) {
NodeProxy proxy = (NodeProxy) i.nextItem();
- proxy.toSAX(broker, handler, null);
+ if (proxy.getType() == Type.ATTRIBUTE) {
+ AttrImpl attr = (AttrImpl) proxy.getNode();
+ attribs.clear();
+ attribs.addAttribute(attr.getNamespaceURI(), attr.getLocalName(), attr.getName(),
+ AttrImpl.getAttributeType(attr.getType()), attr.getValue());
+ handler.startElement(XMLDiff.NAMESPACE, "attribute", XMLDiff.PREFIX + ":attribute", attribs);
+ handler.endElement(XMLDiff.NAMESPACE, "attribute", XMLDiff.PREFIX + ":attribute");
+ } else
+ proxy.toSAX(broker, handler, null);
}
handler.endElement(XMLDiff.NAMESPACE, "append", XMLDiff.PREFIX + ":append");
} catch (XPathException e) {
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -28,12 +28,15 @@
import org.exist.dom.StoredNode;
import org.exist.numbering.NodeId;
import org.exist.stax.EmbeddedXMLStreamReader;
+import org.exist.stax.ExtendedXMLStreamReader;
import org.exist.storage.DBBroker;
import org.exist.util.serializer.AttrList;
import org.exist.util.serializer.Receiver;
import org.exist.xquery.XPathException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Attr;
import org.xml.sax.SAXException;
import javax.xml.stream.XMLStreamException;
@@ -75,7 +78,7 @@
*
* @throws DiffException
*/
- public void patch(XMLStreamReader reader, Receiver receiver) throws DiffException {
+ public void patch(ExtendedXMLStreamReader reader, Receiver receiver) throws DiffException {
try {
NodeId skip = null;
while (reader.hasNext()) {
@@ -113,27 +116,59 @@
private void insertNode(Element insertedNode, Receiver receiver) throws XMLStreamException, IOException, SAXException {
StoredNode child = (StoredNode) insertedNode.getFirstChild();
while (child != null) {
- XMLStreamReader reader = broker.newXMLStreamReader(child, false);
- while (reader.hasNext()) {
- int status = reader.next();
- copyNode(reader, receiver, status);
+ if (XMLDiff.NAMESPACE.equals(child.getNamespaceURI()) && "attribute".equals(child.getLocalName())) {
+ NamedNodeMap attrs = child.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ AttrImpl attr = (AttrImpl) attrs.item(i);
+ if (!attr.getName().startsWith("xmlns"))
+ receiver.attribute(attr.getQName(), attr.getValue());
+ }
+ } else {
+ ExtendedXMLStreamReader reader = broker.newXMLStreamReader(child, false);
+ while (reader.hasNext()) {
+ int status = reader.next();
+ copyNode(reader, receiver, status);
+ }
}
child = (StoredNode) child.getNextSibling();
}
}
- private void copyNode(XMLStreamReader reader, Receiver receiver, int status) throws SAXException {
+ private void copyNode(ExtendedXMLStreamReader reader, Receiver receiver, int status) throws SAXException, XMLStreamException, IOException {
switch (status) {
case XMLStreamReader.START_ELEMENT:
AttrList attrs = new AttrList();
for (int i = 0; i < reader.getAttributeCount(); i++) {
- QName attrQn = new QName(reader.getAttributeLocalName(i), reader.getAttributeNamespace(i),
- reader.getAttributePrefix(i));
- attrs.addAttribute(
- attrQn,
- reader.getAttributeValue(i),
- getAttributeType(reader.getAttributeType(i))
- );
+ // check if an attribute has to be inserted before the current attribute
+ NodeId nodeId = reader.getAttributeId(i);
+
+ // check if an attribute has to be inserted before the current attribute
+ ElementImpl insertedNode = (ElementImpl) insertedNodes.get(nodeId);
+ if (insertedNode != null) {
+ StoredNode child = (StoredNode) insertedNode.getFirstChild();
+ while (child != null) {
+ if (XMLDiff.NAMESPACE.equals(child.getNamespaceURI()) && "attribute".equals(child.getLocalName())) {
+ NamedNodeMap map = child.getAttributes();
+ for (int j = 0; j < map.getLength(); j++) {
+ AttrImpl attr = (AttrImpl) map.item(j);
+ if (!attr.getName().startsWith("xmlns"))
+ attrs.addAttribute(attr.getQName(), attr.getValue(),
+ attr.getType(), attr.getNodeId());
+ }
+ }
+ child = (StoredNode) child.getNextSibling();
+ }
+ }
+
+ if (!deletedNodes.contains(nodeId)) {
+ QName attrQn = new QName(reader.getAttributeLocalName(i), reader.getAttributeNamespace(i),
+ reader.getAttributePrefix(i));
+ attrs.addAttribute(
+ attrQn,
+ reader.getAttributeValue(i),
+ getAttributeType(reader.getAttributeType(i))
+ );
+ }
}
receiver.startElement(new QName(reader.getLocalName(), reader.getNamespaceURI(), reader.getPrefix()),
attrs);
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -1,20 +1,21 @@
package org.exist.versioning;
+import bmsi.util.Diff;
import org.exist.dom.DocumentImpl;
import org.exist.dom.ElementImpl;
-import org.exist.dom.QName;
+import org.exist.dom.NewArrayNodeSet;
import org.exist.dom.NodeProxy;
import org.exist.dom.NodeSet;
-import org.exist.dom.NewArrayNodeSet;
+import org.exist.dom.QName;
+import org.exist.numbering.NodeId;
import org.exist.stax.EmbeddedXMLStreamReader;
import org.exist.storage.DBBroker;
-import org.exist.numbering.NodeId;
+import org.exist.util.serializer.Receiver;
import org.exist.util.serializer.SAXSerializer;
import org.exist.util.serializer.SerializerPool;
-import org.exist.util.serializer.Receiver;
+import org.exist.xquery.XPathException;
import org.exist.xquery.value.SequenceIterator;
-import org.exist.xquery.XPathException;
-import org.w3c.dom.Node;
+import org.exist.xquery.value.Type;
import org.xml.sax.SAXException;
import javax.xml.stream.XMLStreamException;
@@ -22,18 +23,14 @@
import javax.xml.transform.OutputKeys;
import java.io.IOException;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
-import java.util.ArrayList;
+import java.util.Map;
import java.util.Properties;
-import java.util.Set;
-import java.util.HashSet;
import java.util.Stack;
-import java.util.Iterator;
-import java.util.Map;
import java.util.TreeMap;
-import bmsi.util.Diff;
-
public class XMLDiff {
public final static String NAMESPACE = "http://exist-db.org/versioning";
@@ -149,46 +146,86 @@
int start = next.line1;
int last = start + next.inserted;
+ Stack elementStack = new Stack();
+
// sanitize the diff: move the start and end offsets of the chunk to properly include
// all required start and end tags.
- // step 1: at the end of the chunk, remove start tags with missing end tags
- for (int i = last - 1; i >= start; i--) {
- if (nodesB[i].nodeType == XMLStreamReader.START_ELEMENT) {
-// System.out.println("Found element out of context at end of chunk: " + nodesB[i].value);
- last--;
- } else
- break;
- }
- // step 2: search for end tags with missing start tags. adjust start to include the start tags.
- // this may need to be done for more than one tag.
- Stack elementStack = new Stack();
- boolean needRescan;
- do {
- needRescan = false;
- for (int i = start; i < last; i++) {
+ if (next.inserted > 0) {
+ // step 1: at the end of the chunk, remove start tags with missing end tags
+ for (int i = last - 1; i >= start; i--) {
if (nodesB[i].nodeType == XMLStreamReader.START_ELEMENT) {
- elementStack.push(nodesB[i]);
- } else if (nodesB[i].nodeType == XMLStreamReader.END_ELEMENT) {
- if (elementStack.isEmpty()) {
-// System.out.println("Found out of context element: " + nodesB[i].value);
- for (int j = start - 1; j > -1; j--) {
- if (nodesB[j].nodeId.equals(nodesB[i].nodeId)) {
- start0 = start0 - (start - j);
- start = j;
- last = start + next.inserted;
- needRescan = true;
+ System.out.println("Found element out of context at end of chunk: " + nodesB[i].value);
+ last--;
+ } else
+ break;
+ }
+ // step 2: search for end tags with missing start tags. adjust start to include the start tags.
+ // this may need to be done for more than one tag.
+ boolean needRescan;
+ do {
+ needRescan = false;
+ for (int i = start; i < last; i++) {
+ if (nodesB[i].nodeType == XMLStreamReader.START_ELEMENT) {
+ elementStack.push(nodesB[i]);
+ } else if (nodesB[i].nodeType == XMLStreamReader.END_ELEMENT) {
+ if (elementStack.isEmpty()) {
+ System.out.println("Found out of context element: " + nodesB[i].value);
+ for (int j = start - 1; j > -1; j--) {
+ if (nodesB[j].nodeId.equals(nodesB[i].nodeId)) {
+ start0 = start0 - (start - j);
+ start = j;
+ last = start + next.inserted;
+ needRescan = true;
+ }
}
+ } else {
+ DiffNode n = (DiffNode) elementStack.pop();
+ if (!n.nodeId.equals(nodesB[i].nodeId))
+ throw new XMLStreamException("Diff error: element is out of context: " + nodesB[i].value);
}
- } else {
- DiffNode n = (DiffNode) elementStack.pop();
- if (!n.nodeId.equals(nodesB[i].nodeId))
- throw new XMLStreamException("Diff error: element is out of context: " + nodesB[i].value);
}
}
+ elementStack.clear();
+ } while (needRescan);
+ } else if (next.deleted > 0) {
+ last = start0 + next.deleted;
+ // step 1: at the end of the chunk, remove start tags with missing end tags
+ for (int i = last - 1; i >= start0; i--) {
+ if (nodesA[i].nodeType == XMLStreamReader.START_ELEMENT) {
+ System.out.println("Found element out of context at end of chunk: " + nodesA[i].value);
+ last--;
+ } else
+ break;
}
- elementStack.clear();
- } while (needRescan);
+ // step 2: search for end tags with missing start tags. adjust start to include the start tags.
+ // this may need to be done for more than one tag.
+ boolean needRescan;
+ do {
+ needRescan = false;
+ for (int i = start0; i < last; i++) {
+ if (nodesA[i].nodeType == XMLStreamReader.START_ELEMENT) {
+ elementStack.push(nodesA[i]);
+ } else if (nodesA[i].nodeType == XMLStreamReader.END_ELEMENT) {
+ if (elementStack.isEmpty()) {
+ System.out.println("Found out of context element: " + nodesA[i].value);
+ for (int j = start0 - 1; j > -1; j--) {
+ if (nodesA[j].nodeId.equals(nodesA[i].nodeId)) {
+ start0 = j;
+ last = start0 + next.deleted;
+ needRescan = true;
+ }
+ }
+ } else {
+ DiffNode n = (DiffNode) elementStack.pop();
+ if (!n.nodeId.equals(nodesA[i].nodeId))
+ throw new XMLStreamException("Diff error: element is out of context: " + nodesB[i].value);
+ }
+ }
+ }
+ elementStack.clear();
+ } while (needRescan);
+ }
if (next.inserted > 0) {
// System.out.println("Insertion next.line1 = " + next.line1 + " next.inserted = " + next.inserted +
@@ -206,7 +243,8 @@
for (int i = start; i < last; i++) {
// System.out.println(Integer.toString(i) + " " + nodesB[i]);
NodeId nodeId = nodesB[i].nodeId;
- NodeProxy p = new NodeProxy(docB, nodeId);
+ NodeProxy p = new NodeProxy(docB, nodeId, (short)
+ (nodesB[i].nodeType == XMLStreamReader.ATTRIBUTE ? Type.ATTRIBUTE : Type.NODE));
if (nodesB[i].nodeType == XMLStreamReader.END_ELEMENT) {
elementStack.pop();
insertedNodes.add(p);
@@ -240,7 +278,9 @@
}
if (next.deleted > 0) {
- last = start0 + next.deleted;
+ if (next.inserted > 0)
+ last = start0 + next.deleted;
+// System.out.println("Deleted: " + start0 + " last: " + last);
for (int i = start0; i < last; i++) {
NodeId nodeId = nodesA[i].nodeId;
NodeProxy p = new NodeProxy(docA, nodeId);
@@ -282,6 +322,7 @@
nodes.add(node);
for (int i = 0; i < reader.getAttributeCount(); i++) {
+ nodeId = reader.getAttributeId(i);
String value = reader.getAttributeQName(i).getStringValue() + '=' +
reader.getAttributeValue(i);
node = new DiffNode(nodeId, XMLStreamReader.ATTRIBUTE, value);
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/PatchFunction.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/PatchFunction.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/PatchFunction.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -41,6 +41,7 @@
import org.exist.memtree.NodeImpl;
import org.exist.versioning.Patch;
import org.exist.versioning.DiffException;
+import org.exist.stax.ExtendedXMLStreamReader;
import org.xml.sax.SAXException;
import javax.xml.stream.XMLStreamReader;
@@ -67,7 +68,7 @@
public Sequence eval(Sequence[] args, Sequence contextSequence) throws XPathException {
context.pushDocumentContext();
try {
- XMLStreamReader reader;
+ ExtendedXMLStreamReader reader;
NodeValue nv = (NodeValue) args[0].itemAt(0);
if (nv.getImplementationType() == NodeValue.IN_MEMORY_NODE) {
NodeImpl node = (NodeImpl) nv;
Modified: trunk/eXist/extensions/versioning/test/test.xml
===================================================================
--- trunk/eXist/extensions/versioning/test/test.xml 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/extensions/versioning/test/test.xml 2008-12-30 14:26:04 UTC (rev 8440)
@@ -126,10 +126,45 @@
</book>
</v:revision>
</v:test>
+ <v:test id="simple-remove">
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ <para>First paragraph</para>
+ <para>Second paragraph</para>
+ <para>Third <emphasis>important</emphasis> paragraph.</para>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ <para>Second paragraph</para>
+ <para>Third paragraph.</para>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-remove-last">
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ <para>First paragraph</para>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ </book>
+ </v:revision>
+ </v:test>
<v:test id="simple-update-mixed">
<v:revision>
<book>
<title>Book Title</title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title>Book Title</title>
<para>First <emphasis>important</emphasis> paragraph</para>
</book>
</v:revision>
@@ -140,4 +175,246 @@
</book>
</v:revision>
</v:test>
-</v:testSuite>
\ No newline at end of file
+ <v:test id="simple-update-empty">
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ <ulink url="http://exist-db.org"/>
+ <para>First paragraph</para>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ <ulink url="" rel="nofollow">http://exist-db.org/"/>
+ <para>First paragraph</para>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ <ulink url="" rel="nofollow">http://exist-db.org/"/>
+ <para>First <emphasis>important</emphasis> paragraph</para>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-attribute-insert-mixed">
+ <v:revision>
+ <book>
+ <title></title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book xmlns:x="http://foo.org">
+ <title x:id="title1">Book Title</title>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-attribute-insert">
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book xmlns:x="http://foo.org">
+ <title x:id="title1">Book Title</title>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-attribute-insert2">
+ <v:revision>
+ <book>
+ <title id="title1">Book Title</title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title n="22" id="title1">Book Title</title>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-attribute-update">
+ <v:revision>
+ <book>
+ <title label="1.1" id="title1" n="22">Book Title</title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title label="1.1" id="title2" n="22">Book Title</title>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-attribute-delete">
+ <v:revision>
+ <book>
+ <title n="22" id="title1" label="1.1">Book Title</title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title id="title2">Book Title</title>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="simple-insert-namespace">
+ <v:revision>
+ <book>
+ <title>Book Title</title>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book xmlns:t="http://test.com">
+ <title>Book Title</title>
+ <t:test>Bla</t:test>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="complex-insert">
+ <v:revision>
+ <book>
+ <title>Backup</title>
+ <procedure>
+ <step>
+ <para>Select either the Backup Icon (arrow pointed upward) in the toolbar OR
+ <guimenuitem>Tools » Backup</guimenuitem> from the menu.</para>
+ </step>
+ <step>
+ <para>From the <guimenuitem>Collection</guimenuitem> drop-down menu, select the
+ collection to backup. To backup the entire database, select
+ <filename>/db</filename>. Otherwise, select the topmost collection that
+ should be stored. Note, however, that user data and permissions will only be
+ exported if you backup the entire database.</para>
+ <screenshot><graphic fileref="resources/backup1.png"/></screenshot>
+ </step>
+ <step>
+ <para>In the <command>Backup-Directory</command> field, enter the full directory
+ path to the where you want the backup database files to be stored or the
+ path to a zip file into which the backup will be written. In general, if the
+ file name ends with <filename>.zip</filename>, the client will attempt to
+ write to a ZIP. Otherwise, it tries to create the specified
+ directory.</para>
+ </step>
+ <step>
+ <para>Click <command>OK</command>.</para>
+ </step>
+ </procedure>
+ </book>
+ </v:revision>
+ <v:revision>
+ <book>
+ <title>Backup</title>
+ <procedure>
+ <step>
+ <para>From the <guimenuitem>Collection</guimenuitem> drop-down menu, select the
+ collection to backup. To backup the entire database, select
+ <filename>/db</filename>. Otherwise, select the topmost collection that
+ should be stored. Note, however, that user data and permissions will only be
+ exported if you backup the entire database.</para>
+ <screenshot><graphic fileref="resources/backup1.png"/></screenshot>
+ </step>
+ <step>
+ <para>Select either the Backup Icon (arrow pointed upward) in the toolbar OR
+ <guimenuitem>Tools » Backup</guimenuitem> from the menu.</para>
+ </step>
+ <step>
+ <para>In the <command>Backup-Directory</command> field, enter the full directory
+ path to the where you want the backup database files to be stored or the
+ path to a zip file into which the backup will be written. In general, if the
+ file name ends with <filename>.zip</filename>, the client will attempt to
+ write to a ZIP. Otherwise, it tries to create the specified
+ directory.</para>
+ </step>
+ <step>
+ <para>Click <command>OK</command>.</para>
+ </step>
+ </procedure>
+ </book>
+ </v:revision>
+ </v:test>
+ <v:test id="complex-atom">
+ <v:revision>
+ <feed xmlns="" rel="nofollow">http://www.w3.org/2005/Atom">
+ <id>urn:uuid:bbc0ae94-582f-4e8c-b937-58d6a0cd0757</id>
+ <updated>2008-10-16T22:23:14+02:00</updated>
+ <title>Help</title>
+ <subtitle>AtomicWiki Quick Help</subtitle>
+ <author>
+ <name>wolf</name>
+ </author>
+ <link href="#" rel="edit" type="application/atom+xml"/>
+ <link href="#" rel="self" type="application/atom+xml"/>
+ <entry>
+ <id>urn:uuid:1b976cef-bb06-4a4f-85e0-bc2a9c948147</id>
+ <updated>2008-10-16T22:23:14+02:00</updated>
+ <published>2008-03-03T10:48:51+01:00</published>
+ <link href="?id=urn:uuid:1b976cef-bb06-4a4f-85e0-bc2a9c948147" rel="edit" type="application/atom+xml"/>
+ <atom:title xmlns:atom="http://www.w3.org/2005/Atom" type="text">Quick Help</atom:title>
+ <wiki:id xmlns:wiki="QuickHelp" rel="nofollow">http://exist-db.org/xquery/wiki">QuickHelp</wiki:id>
+ <atom:content xmlns:atom="http://www.w3.org/2005/Atom" type="xhtml">
+ <div xmlns="" rel="nofollow">http://www.w3.org/1999/xhtml">
+ <h2>Addressing</h2>
+ <p>The hierarchical structure of feeds and entries is directly reflected in the URLs you use to access an entry or feed. In general, URLs that end with a <span class="strong">slash</span> point to a feed, while URLs not ending with a slash reference an entry within a feed. For example:</p>
+ </div>
+ </atom:content>
+ </entry>
+ </feed>
+ </v:revision>
+ <v:revision>
+ <feed xmlns="" rel="nofollow">http://www.w3.org/2005/Atom">
+ <id>urn:uuid:bbc0ae94-582f-4e8c-b937-58d6a0cd0757</id>
+ <updated>2008-10-16T22:23:14+02:00</updated>
+ <title>Quick Help</title>
+ <subtitle>AtomicWiki Quick Help</subtitle>
+ <author>
+ <name>wolf</name>
+ </author>
+ <category scheme="http://exist-db.org/NS/wiki/type/" term="wiki"/>
+ <link href="#" rel="edit" type="application/atom+xml"/>
+ <link href="#" rel="self" type="application/atom+xml"/>
+ <link href="#" rel="self" type="application/atom+xml"/>
+ <entry>
+ <id>urn:uuid:1b976cef-bb06-4a4f-85e0-bc2a9c948147</id>
+ <updated>2008-11-16T22:23:14+02:00</updated>
+ <link href="?id=urn:uuid:1b976cef-bb06-4a4f-85e0-bc2a9c948147" rel="edit" type="application/atom+xml"/>
+ <atom:title xmlns:atom="http://www.w3.org/2005/Atom" type="text">Quick Help</atom:title>
+ <wiki:id xmlns:wiki="QuickHelp" rel="nofollow">http://exist-db.org/xquery/wiki">QuickHelp</wiki:id>
+ <atom:content xmlns:atom="http://www.w3.org/2005/Atom" type="xhtml">
+ <div xmlns="" rel="nofollow">http://www.w3.org/1999/xhtml">
+ <h2>Addressing</h2>
+ <p>The hierarchical structure of feeds and entries is directly reflected in the URLs you use to access an entry or feed. In general, URLs that end with a <span class="strong">slash</span> point to a feed, while URLs not ending with a slash reference an entry within a feed. For example:</p>
+ </div>
+ </atom:content>
+ </entry>
+ </feed>
+ </v:revision>
+ <v:revision>
+ <feed xmlns="" rel="nofollow">http://www.w3.org/2005/Atom">
+ <id>urn:uuid:bbc0ae94-582f-4e8c-b937-58d6a0cd0757</id>
+ <updated>2008-10-16T22:23:14+02:00</updated>
+ <title>Quick Help</title>
+ <subtitle>AtomicWiki Quick Help</subtitle>
+ <author>
+ <name>wolf</name>
+ </author>
+ <category scheme="http://exist-db.org/NS/wiki/type/" term="wiki"/>
+ <link href="#" rel="edit" type="application/atom+xml"/>
+ <link href="#" rel="self" type="application/atom+xml"/>
+ <entry>
+ <id>urn:uuid:1b976cef-bb06-4a4f-85e0-bc2a9c948147</id>
+ <updated>2008-11-16T22:23:14+02:00</updated>
+ <link href="?id=urn:uuid:1b976cef-bb06-4a4f-85e0-bc2a9c948147" rel="edit" type="application/atom+xml"/>
+ <atom:title xmlns:atom="http://www.w3.org/2005/Atom" type="text">Quick Help</atom:title>
+ <wiki:id xmlns:wiki="QuickHelp" rel="nofollow">http://exist-db.org/xquery/wiki">QuickHelp</wiki:id>
+ <atom:content xmlns:atom="http://www.w3.org/2005/Atom" type="xhtml">
+ <div xmlns="" rel="nofollow">http://www.w3.org/1999/xhtml">
+ <h2>Addressing</h2>
+ <p>The <b>hierarchical</b> structure of feeds and entries is directly reflected in the URLs you use to access an entry or feed. In general, URLs that end with a <span class="strong">slash</span> point to a feed, while URLs not ending with a slash reference an entry within a feed. For example:</p>
+ </div>
+ </atom:content>
+ </entry>
+ </feed>
+ </v:revision>
+ </v:test>
+</v:testSuite>
Modified: trunk/eXist/src/org/exist/dom/AttrImpl.java
===================================================================
--- trunk/eXist/src/org/exist/dom/AttrImpl.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/src/org/exist/dom/AttrImpl.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -207,7 +207,7 @@
LOG.warn(uee);
value = new String( data, pos, len - (pos - start));
}
- list.addAttribute(broker.getBrokerPool().getSymbols().getQName(Node.ATTRIBUTE_NODE, namespace, name, prefix), value, attrType);
+ list.addAttribute(broker.getBrokerPool().getSymbols().getQName(Node.ATTRIBUTE_NODE, namespace, name, prefix), value, attrType, dln);
}
public String getName() {
@@ -223,6 +223,16 @@
attributeType = type;
}
+ public static String getAttributeType(int type) {
+ if (type == AttrImpl.ID)
+ return "ID";
+ if (type == AttrImpl.IDREF)
+ return "IDREF";
+ if (type == AttrImpl.IDREFS)
+ return "IDREFS";
+ return "CDATA";
+ }
+
public String getValue() {
return value.toString();
}
Modified: trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java
===================================================================
--- trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -23,6 +23,8 @@
import org.w3c.dom.Node;
import org.exist.stax.EmbeddedXMLStreamReader;
+import org.exist.stax.ExtendedXMLStreamReader;
+import org.exist.numbering.NodeId;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
@@ -35,7 +37,7 @@
* eXist's in-memory DOM. This class complements {@link org.exist.stax.EmbeddedXMLStreamReader}
* which reads persistent documents.
*/
-public class InMemoryXMLStreamReader implements XMLStreamReader {
+public class InMemoryXMLStreamReader implements ExtendedXMLStreamReader {
protected DocumentImpl doc;
protected int currentNode;
@@ -51,7 +53,7 @@
}
public Object getProperty(String name) throws IllegalArgumentException {
- if (name.equals(EmbeddedXMLStreamReader.PROPERTY_NODE_ID)) {
+ if (name.equals(PROPERTY_NODE_ID)) {
if (currentNode < 0 || currentNode >= doc.size)
return null;
doc.expand();
@@ -66,8 +68,13 @@
}
if (currentNode > -1) {
int next = -1;
- if (state == XMLStreamReader.START_ELEMENT)
+ if (state == XMLStreamReader.START_ELEMENT) {
next = doc.getFirstChildFor(currentNode);
+ if (next < 0) { // no child nodes
+ state = XMLStreamReader.END_ELEMENT;
+ return state;
+ }
+ }
if (next < 0) {
next = doc.next[currentNode];
if (next < currentNode) {
@@ -180,6 +187,16 @@
return getAttributeQName(index).getPrefix();
}
+ public NodeId getAttributeId(int index) {
+ if (state != START_ELEMENT)
+ throw new IllegalStateException("Cursor is not at an element");
+ if (index > getAttributeCount())
+ throw new ArrayIndexOutOfBoundsException("bad attribute index");
+ doc.expand();
+ int attr = doc.alpha[currentNode];
+ return doc.attrNodeId[attr + index];
+ }
+
public String getAttributeType(int index) {
if (state != START_ELEMENT)
throw new IllegalStateException("Cursor is not at an element");
Modified: trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java
===================================================================
--- trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -51,12 +51,10 @@
* a few selected node properties are requested. Node properties are extracted on demand. For example, the QName of
* an element will not be read unless {@link #getText()} is called.
*/
-public class EmbeddedXMLStreamReader implements XMLStreamReader {
+public class EmbeddedXMLStreamReader implements ExtendedXMLStreamReader {
private static final Logger LOG = Logger.getLogger(EmbeddedXMLStreamReader.class);
- public final static String PROPERTY_NODE_ID = "node-id";
-
private RawNodeIterator iterator;
private Value current = null;
@@ -367,13 +365,7 @@
if (i > attributes.getLength())
throw new ArrayIndexOutOfBoundsException("index should be < " + attributes.getLength());
final int type = attributes.getType(i);
- if (type == AttrImpl.ID)
- return "ID";
- if (type == AttrImpl.IDREF)
- return "IDREF";
- if (type == AttrImpl.IDREFS)
- return "IDREFS";
- return "CDATA";
+ return AttrImpl.getAttributeType(type);
}
public String getAttributeValue(int i) {
@@ -385,6 +377,15 @@
return attributes.getValue(i);
}
+ public NodeId getAttributeId(int i) {
+ if (state != START_ELEMENT)
+ throw new IllegalStateException("Cursor is not at an element");
+ readAttributes();
+ if (i > attributes.getLength())
+ throw new ArrayIndexOutOfBoundsException("index should be < " + attributes.getLength());
+ return attributes.getNodeId(i);
+ }
+
public boolean isAttributeSpecified(int i) {
return false;
}
Added: trunk/eXist/src/org/exist/stax/ExtendedXMLStreamReader.java
===================================================================
--- trunk/eXist/src/org/exist/stax/ExtendedXMLStreamReader.java (rev 0)
+++ trunk/eXist/src/org/exist/stax/ExtendedXMLStreamReader.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -0,0 +1,37 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-07 The eXist Project
+ * http://exist-db.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id$
+ */
+package org.exist.stax;
+
+import org.exist.numbering.NodeId;
+
+import javax.xml.stream.XMLStreamReader;
+
+public interface ExtendedXMLStreamReader extends XMLStreamReader {
+
+ public final static String PROPERTY_NODE_ID = "node-id";
+
+ public org.exist.dom.QName getAttributeQName(int i);
+
+ public org.exist.dom.QName getQName();
+
+ public NodeId getAttributeId(int i);
+}
Modified: trunk/eXist/src/org/exist/util/serializer/AttrList.java
===================================================================
--- trunk/eXist/src/org/exist/util/serializer/AttrList.java 2008-12-30 10:43:12 UTC (rev 8439)
+++ trunk/eXist/src/org/exist/util/serializer/AttrList.java 2008-12-30 14:26:04 UTC (rev 8440)
@@ -23,6 +23,7 @@
import org.exist.dom.AttrImpl;
import org.exist.dom.QName;
+import org.exist.numbering.NodeId;
/**
* Represents a list of attributes. Each attribute is defined by
@@ -34,6 +35,7 @@
*/
public class AttrList {
+ protected NodeId nodeIds[] = new NodeId[4];
protected QName names[] = new QName[4];
protected String values[] = new String[4];
protected int type[] = new int[4];
@@ -51,7 +53,12 @@
}
public void addAttribute(QName name, String value, int attrType) {
+ addAttribute(name, value, attrType, null);
+ }
+
+ public void addAttribute(QName name, String value, int attrType, NodeId nodeId) {
ensureCapacity();
+ nodeIds[size] = nodeId;
names[size] = name;
values[size] = value;
type[size] = attrType;
@@ -65,7 +72,11 @@
public QName getQName(int pos) {
return names[pos];
}
-
+
+ public NodeId getNodeId(int pos) {
+ return nodeIds[pos];
+ }
+
public String getValue(int pos) {
return values[pos];
}
@@ -86,6 +97,9 @@
if(size == names.length) {
// resize
final int newSize = names.length * 3 / 2;
+ NodeId tnodeIds[] = new NodeId[newSize];
+ System.arraycopy(nodeIds, 0, tnodeIds, 0, nodeIds.length);
+
QName tnames[] = new QName[newSize];
System.arraycopy(names, 0, tnames, 0, names.length);
@@ -95,6 +109,7 @@
int ttype[] = new int[newSize];
System.arraycopy(type, 0, ttype, 0, type.length);
+ nodeIds = tnodeIds;
names = tnames;
values = tvalues;
type = ttype;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-30 10:43:19
|
Revision: 8439
http://exist.svn.sourceforge.net/exist/?rev=8439&view=rev
Author: deliriumsky
Date: 2008-12-30 10:43:12 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
fix so the TCK runs - eXist db must be running at http://localhost:8080/exist/rest/db
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java
branches/allad/jsr-225/test/jsr225/remote.properties
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java 2008-12-30 01:40:26 UTC (rev 8438)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java 2008-12-30 10:43:12 UTC (rev 8439)
@@ -50,7 +50,7 @@
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpGet;
import org.apache.log4j.Logger;
import org.exist.xqj.Constants;
import org.exist.xqj.EXistXQDataFactoryImpl;
@@ -132,14 +132,14 @@
private void checkResourceAvailable() throws XQException
{
- HttpHead head = new HttpHead(remoteURL);
+ HttpGet get = new HttpGet(remoteURL); //TODO understand why HEAD isnt supported here probably in RESTServer?
try
{
//TODO replace head with get and check that the response looks like this -
//<rest:response xmlns:rest="" rel="nofollow">http://exist-db.org/rest">
//<rest:http method="GET" url="http://localhost:8080/exist/rest/db/mydoc.xml" status="200"/>
- HttpResponse response = httpClient.execute(head);
+ HttpResponse response = httpClient.execute(get);
if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
throw new XQException("Could not connect to the remote resource, response code: " + response.getStatusLine().getStatusCode() + " reason: " + response.getStatusLine().getReasonPhrase());
Modified: branches/allad/jsr-225/test/jsr225/remote.properties
===================================================================
--- branches/allad/jsr-225/test/jsr225/remote.properties 2008-12-30 01:40:26 UTC (rev 8438)
+++ branches/allad/jsr-225/test/jsr225/remote.properties 2008-12-30 10:43:12 UTC (rev 8439)
@@ -2,7 +2,7 @@
MaxConnections=20
ServerType=REMOTE
ServerName=localhost
-CollectionPath=/exist/db
+CollectionPath=/exist/rest/db
ServerPort=8080
Username=guest
Password=guest
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <pka...@us...> - 2008-12-30 02:22:10
|
Revision: 8438
http://exist.svn.sourceforge.net/exist/?rev=8438&view=rev
Author: pkaminsk2
Date: 2008-12-30 01:40:26 +0000 (Tue, 30 Dec 2008)
Log Message:
-----------
Fluent: Changed node ID tracking mechanism: instead of listening for change events, trust that only defragmentation can change IDs and use the staleness marking mechanism to prevent defragmentation of documents that have outstanding references to/into them. This means that ItemLists now eagerly instantiate wrappers for their contents, which could impact performance a bit but not much as it does not force nodes to be pulled in. Since staleness is now accurate, you can't pass stale resources to queries any more (this is most likely to affect ItemLists where some nodes have been deleted). Also fixed bugs in query analysis, database conf.xml to collection.xconf conversion, and sped up DatabaseTestCase by not requiring a database shutdown/startup between every test.
Modified Paths:
--------------
trunk/eXist/extensions/fluent/src/org/exist/fluent/Database.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/DatabaseTestCase.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/Folder.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/ItemList.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/Node.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/QueryService.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/Transaction.java
trunk/eXist/extensions/fluent/src/org/exist/fluent/XMLDocument.java
trunk/eXist/extensions/fluent/test/src/org/exist/fluent/ItemListTest.java
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/Database.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/Database.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/Database.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -88,28 +88,26 @@
// If the config is already *exactly* how we want it, no need to reload and reindex.
try {
- if (db.getFolder(CollectionConfigurationManager.CONFIG_COLLECTION + Database.ROOT_PREFIX).documents()
- .get(CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE)
- .contentsAsString().equals(configXml.toString())) return;
+ Node currentConfig =
+ db.getFolder(CollectionConfigurationManager.CONFIG_COLLECTION + Database.ROOT_PREFIX).documents()
+ .get(CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE).xml().root();
+ if (currentConfig.query().presub().single("deep-equal(., $1)", configXml.toString()).booleanValue()) return;
} catch (DatabaseException e) {
// fall through
}
// Now force reload and reindex so it'll pick up the new settings.
- DBBroker broker = null;
- Transaction tx = requireTransaction();
+ Transaction tx = db.requireTransactionWithBroker();
try {
- broker = db.acquireBroker();
- pool.getConfigurationManager().addConfiguration(tx.tx, broker, broker.getCollection(XmldbURI.ROOT_COLLECTION_URI), configXml.toString());
+ pool.getConfigurationManager().addConfiguration(tx.tx, tx.broker, tx.broker.getCollection(XmldbURI.ROOT_COLLECTION_URI), configXml.toString());
tx.commit();
- broker.reindexCollection(XmldbURI.ROOT_COLLECTION_URI);
+ tx.broker.reindexCollection(XmldbURI.ROOT_COLLECTION_URI);
} catch (PermissionDeniedException e) {
throw new DatabaseException(e);
} catch (CollectionConfigurationException e) {
throw new DatabaseException(e);
} finally {
tx.abortIfIncomplete();
- db.releaseBroker(broker);
}
}
@@ -435,6 +433,24 @@
};
}
+ /**
+ * Return a transaction for use with database operations. If a transaction is already in progress
+ * then join it, otherwise begin a new one. If a transaction is joined, calling <code>commit</code>
+ * or <code>abort</code> on the returned instance will have no effect; only the outermost
+ * transaction object can do this.
+ *
+ * @return a transaction object
+ */
+ static Transaction requireTransaction() {
+ Transaction t = localTransaction.get();
+ return t == null ? new Transaction(txManager, null) : new Transaction(t, null);
+ }
+
+ Transaction requireTransactionWithBroker() {
+ Transaction t = localTransaction.get();
+ return t == null ? new Transaction(txManager, this) : new Transaction(t, this);
+ }
+
void checkSame(Resource o) {
// allow other resource to be a NULL, as those are safe and database-neutral
if (!(o.database() == null || o.database().user == this.user)) throw new IllegalArgumentException("cannot combine objects from two database instances in one operation");
@@ -480,57 +496,6 @@
};
- /**
- * Return a transaction for use with database operations. If a transaction is already in progress
- * then join it, otherwise begin a new one. If a transaction is joined, calling <code>commit</code>
- * or <code>abort</code> on the returned instance will have no effect; only the outermost
- * transaction object can do this.
- *
- * @return a transaction object
- */
- static Transaction requireTransaction() {
- Transaction t = localTransaction.get();
- return t == null ? new Transaction(txManager) : new Transaction(t.tx);
- }
-
- private static final WeakMultiValueHashMap<Long, NodeProxy> nodes = new WeakMultiValueHashMap<Long, NodeProxy>();
- private static final WeakMultiValueHashMap<String, NodeProxy> docsInUse = new WeakMultiValueHashMap<String, NodeProxy>();
- private static final long ADDRESS_MASK = 0xFFFFFFFF0000FFFFL;
-
- private static final NodeIndexListener indexChangeListener = new NodeIndexListener() {
- @SuppressWarnings("hiding")
- private final Logger LOG = Logger.getLogger("org.exist.fluent.Database.indexChangeListener");
-
- public void nodeChanged(StoredNode node) {
- int numUpdated = 0;
- synchronized(nodes) {
- for (NodeProxy target : nodes.get(node.getInternalAddress() & ADDRESS_MASK)) {
- target.setNodeId(node.getNodeId());
- numUpdated++;
- }
- }
- if (LOG.isDebugEnabled()) System.out.println("change nodeid at " + StorageAddress.toString(node.getInternalAddress()) + " to " + node.getNodeId() + "; updated " + numUpdated);
- }
- };
-
- static void trackNode(NodeProxy proxy) {
- if (proxy.getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE) return; // no need to track document nodes as they don't change gids
- if (proxy.getInternalAddress() == -1) {
- StoredNode node = (StoredNode) proxy.getNode();
- if (node == null) {
- LOG.error("can't load node for proxy, doc=" + proxy.getDocument().getURI().lastSegment() + ", nodeid=" + proxy.getNodeId());
- return;
- }
- proxy.setInternalAddress(node.getInternalAddress());
- assert proxy.getInternalAddress() != -1;
- }
- proxy.getDocument().getMetadata().setIndexListener(indexChangeListener);
- // this may cause duplicates in the list; try to avoid them by design,
- // or it might become a performance hit
- nodes.put(proxy.getInternalAddress() & ADDRESS_MASK, proxy);
- docsInUse.put(normalizePath(proxy.getDocument().getURI().getCollectionPath()), proxy);
- }
-
static void queueDefrag(DocumentImpl doc) {
defragmenter.queue(doc);
}
@@ -590,24 +555,30 @@
try {
DBBroker broker = pool.get(SecurityManager.SYSTEM_USER);
try {
- Integer fragmentationLimit = broker.getBrokerPool().getConfiguration().getInteger(DBBroker.PROPERTY_XUPDATE_FRAGMENTATION_FACTOR);
- if (fragmentationLimit == null) fragmentationLimit = Integer.valueOf(0);
+ Integer fragmentationLimitObject = broker.getBrokerPool().getConfiguration().getInteger(DBBroker.PROPERTY_XUPDATE_FRAGMENTATION_FACTOR);
+ int fragmentationLimit = fragmentationLimitObject == null ? 0 : fragmentationLimitObject;
for (Iterator<DocumentImpl> it = docsToDefragCopy.iterator(); it.hasNext(); ) {
DocumentImpl doc = it.next();
if (doc.getMetadata().getSplitCount() <= fragmentationLimit) {
it.remove();
- } else if (!docsInUse.containsKey(normalizePath(doc.getURI().getCollectionPath()))) {
- LOG.debug("defragmenting " + normalizePath(doc.getURI().getCollectionPath()));
- count++;
- Transaction tx = Database.requireTransaction();
- try {
- // It would be nicer to just try the lock here, and keep going if we can't get it, but oh well.
- tx.lockWrite(doc);
- broker.defragXMLResource(tx.tx, doc);
- tx.commit();
- it.remove();
+ } else {
+ // Must hold write lock on doc before checking stale map to avoid race condition
+ if (doc.getUpdateLock().attempt(Lock.WRITE_LOCK)) try {
+ String docPath = normalizePath(doc.getURI().getCollectionPath());
+ if (!staleMap.containsKey(docPath)) {
+ LOG.debug("defragmenting " + docPath);
+ count++;
+ Transaction tx = Database.requireTransaction();
+ try {
+ broker.defragXMLResource(tx.tx, doc);
+ tx.commit();
+ it.remove();
+ } finally {
+ tx.abortIfIncomplete();
+ }
+ }
} finally {
- tx.abortIfIncomplete();
+ doc.getUpdateLock().release(Lock.WRITE_LOCK);
}
}
}
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/DatabaseTestCase.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/DatabaseTestCase.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/DatabaseTestCase.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -2,8 +2,10 @@
import java.io.File;
import java.lang.annotation.*;
+import java.util.Iterator;
import org.exist.collections.Collection;
+import org.exist.dom.*;
import org.exist.security.SecurityManager;
import org.exist.storage.DBBroker;
import org.exist.xmldb.XmldbURI;
@@ -47,28 +49,36 @@
Database.configureRootCollection(configFile); // config file gets erased by wipeDatabase()
}
- @After public void shutdownDatabase() throws Exception {
+ @AfterClass public static void shutdownDatabase() throws Exception {
if (Database.isStarted()) {
- // TODO: a bug in eXist's removeCollection(root) means that we need to shut down immediately
- // after wiping every time, otherwise the database gets corrupted. When this is fixed, this
- // method can become a static @AfterClass method for increased performance.
wipeDatabase();
Database.shutdown();
db = null;
}
}
+ @SuppressWarnings("unchecked")
private static void wipeDatabase() throws Exception {
- DBBroker broker = null;
- Transaction tx = Database.requireTransaction();
+ Transaction tx = db.requireTransactionWithBroker();
try {
- broker = db.acquireBroker();
- Collection root = broker.getCollection(XmldbURI.ROOT_COLLECTION_URI);
- broker.removeCollection(tx.tx, root);
+ Collection root = tx.broker.getCollection(XmldbURI.ROOT_COLLECTION_URI);
+ for (Iterator<XmldbURI> it = root.collectionIterator(); it.hasNext(); ) {
+ XmldbURI childName = it.next();
+ if (!childName.getCollectionPath().equals(DBBroker.SYSTEM_COLLECTION_NAME)) {
+ tx.broker.removeCollection(tx.tx, tx.broker.getCollection(root.getURI().append(childName)));
+ }
+ }
+ for (Iterator<DocumentImpl> it = root.iterator(tx.broker); it.hasNext(); ) {
+ DocumentImpl doc = it.next();
+ if (doc instanceof BinaryDocument) {
+ root.removeBinaryResource(tx.tx, tx.broker, doc);
+ } else {
+ root.removeXMLResource(tx.tx, tx.broker, doc.getFileURI());
+ }
+ }
tx.commit();
} finally {
tx.abortIfIncomplete();
- db.releaseBroker(broker);
}
}
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/Folder.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/Folder.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/Folder.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -269,6 +269,7 @@
}
@Override Sequence convertToSequence() {
+ staleMarker.check();
return getDocsSequence(false);
}
@@ -994,6 +995,7 @@
}
@Override Sequence convertToSequence() {
+ staleMarker.check();
return getDocsSequence(true);
}
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/ItemList.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/ItemList.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/ItemList.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -2,7 +2,6 @@
import java.util.*;
-import org.exist.dom.NodeProxy;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.*;
@@ -31,24 +30,12 @@
* @return a string value iterator
*/
public Iterator<String> iterator() {
- try {
- return new Iterator<String>() {
- private final SequenceIterator delegate = seq.iterate();
- public boolean hasNext() {
- return delegate.hasNext();
- }
- public String next() {
- try {
- return delegate.nextItem().getStringValue();
- } catch (XPathException e) {
- throw new DatabaseException(e);
- }
- }
- public void remove() {throw new UnsupportedOperationException();}
- };
- } catch (XPathException e) {
- throw new DatabaseException("failed to construct iterator over sequence", e);
- }
+ return new Iterator<String>() {
+ private final Iterator<Item> delegate = ItemList.this.iterator();
+ public boolean hasNext() { return delegate.hasNext();}
+ public String next() {return delegate.next().value();}
+ public void remove() {throw new UnsupportedOperationException();}
+ };
}
private ItemList itemList() {
@@ -70,16 +57,8 @@
*/
public List<String> asList() {
return new AbstractList<String>() {
- @Override public String get(int index) {
- try {
- return seq.itemAt(index).getStringValue();
- } catch (XPathException e) {
- throw new DatabaseException(e);
- }
- }
- @Override public int size() {
- return seq.getItemCount();
- }
+ @Override public String get(int index) {return items.get(index).value();}
+ @Override public int size() {return items.size();}
};
}
@@ -89,7 +68,7 @@
* @return an array of effective string values
*/
public String[] toArray() {
- return toArray(new String[size()]);
+ return asList().toArray(new String[size()]);
}
/**
@@ -101,21 +80,10 @@
* @return an array of effective string values
*/
public String[] toArray(String[] a) {
- if (a == null && size() == 0) return null;
- if (a == null || a.length < size()) a = new String[size()];
- for (int i = 0; i < size(); i++) {
- try {
- a[i] = seq.itemAt(i).getStringValue();
- } catch (XPathException e) {
- throw new DatabaseException(e);
- }
- }
- if (a.length > size()) a[size()] = null;
- return a;
+ return asList().toArray(a);
}
- @Override
- public String toString() {
+ @Override public String toString() {
return ItemList.this.toString();
}
}
@@ -133,20 +101,18 @@
* @return an iterator over the list of nodes
*/
public Iterator<Node> iterator() {
- try {
- return new Iterator<Node>() {
- private final SequenceIterator delegate = seq.iterate();
- public boolean hasNext() {
- return delegate.hasNext();
+ return new Iterator<Node>() {
+ private final Iterator<Item> delegate = ItemList.this.iterator();
+ public boolean hasNext() {return delegate.hasNext();}
+ public Node next() {
+ try {
+ return (Node) delegate.next();
+ } catch (ClassCastException e) {
+ throw new DatabaseException("item is not a node");
}
- public Node next() {
- return new Node(delegate.nextItem(), namespaceBindings.extend(), db);
- }
- public void remove() {throw new UnsupportedOperationException();}
- };
- } catch (XPathException e) {
- throw new DatabaseException("failed to construct iterator over sequence", e);
- }
+ }
+ public void remove() {throw new UnsupportedOperationException();}
+ };
}
/**
@@ -186,10 +152,14 @@
public List<Node> asList() {
return new AbstractList<Node>() {
@Override public Node get(int index) {
- return new Node(seq.itemAt(index), namespaceBindings.extend(), db);
+ try {
+ return (Node) items.get(index);
+ } catch (ClassCastException e) {
+ throw new DatabaseException("item is not a node");
+ }
}
@Override public int size() {
- return seq.getItemCount();
+ return items.size();
}
};
}
@@ -200,7 +170,7 @@
* @return an array of nodes
*/
public Node[] toArray() {
- return toArray(new Node[size()]);
+ return asList().toArray(new Node[size()]);
}
/**
@@ -212,48 +182,50 @@
* @return an array of nodes
*/
public Node[] toArray(Node[] a) {
- if (a.length < size()) a = new Node[size()];
- for (int i = 0; i < size(); i++) {
- a[i] = new Node(seq.itemAt(i), namespaceBindings.extend(), db);
- }
- if (a.length > size()) a[size()] = null;
- return a;
+ return asList().toArray(a);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
- for (Node node : this) {
- buf.append(node).append('\n');
- }
+ for (Node node : this) buf.append(node).append('\n');
return buf.toString();
}
}
private final Sequence seq;
+ private final List<Item> items;
private ValuesFacet values;
private NodesFacet nodes;
private ItemList() {
super(null, null);
- this.seq = null;
+ this.seq = Sequence.EMPTY_SEQUENCE;
+ this.items = Collections.emptyList();
}
ItemList(Sequence seq, NamespaceMap namespaceBindings, Database db) {
super(namespaceBindings, db);
this.seq = seq;
+ List<Item> modifiableItems = new ArrayList<Item>(seq.getItemCount());
try {
- for (SequenceIterator it = seq.unorderedIterator(); it.hasNext(); ) {
- org.exist.xquery.value.Item item = it.nextItem();
- if (item instanceof NodeProxy) Database.trackNode((NodeProxy) item);
+ for (SequenceIterator it = seq.iterate(); it.hasNext(); ) {
+ org.exist.xquery.value.Item existItem = it.nextItem();
+ if (existItem instanceof NodeValue) {
+ modifiableItems.add(new Node((NodeValue) existItem, namespaceBindings.extend(), db));
+ } else {
+ modifiableItems.add(new Item(existItem, namespaceBindings.extend(), db));
+ }
}
} catch (XPathException xpe) {
throw new DatabaseException(xpe);
}
+ this.items = Collections.unmodifiableList(modifiableItems);
}
@Override Sequence convertToSequence() {
+ for (Item item : items) if (item instanceof Node) ((Node) item).staleMarker.check();
return seq;
}
@@ -263,7 +235,7 @@
* @return the number of elements in this item list
*/
public int size() {
- return seq.getItemCount();
+ return items.size();
}
/**
@@ -272,13 +244,8 @@
* @return <code>true</code> if this item list has no elements
*/
public boolean isEmpty() {
- return seq.isEmpty();
+ return items.isEmpty();
}
-
- Item wrap(org.exist.xquery.value.Item x) {
- if (x instanceof NodeValue) return new Node(x, namespaceBindings.extend(), db);
- return new Item(x, namespaceBindings.extend(), db);
- }
/**
* Return the item at the given index in this result. Indexing starts at 0.
@@ -288,8 +255,7 @@
* @throws IndexOutOfBoundsException if the index is out of bounds
*/
public Item get(int index) {
- if (index < 0 || index >= size()) throw new IndexOutOfBoundsException("index " + index + " out of bounds (upper bound at " + size() + ")");
- return wrap(seq.itemAt(index));
+ return items.get(index);
}
/**
@@ -299,7 +265,7 @@
public void deleteAllNodes() {
Transaction tx = Database.requireTransaction();
try {
- for (Item item : this) if (item instanceof Node) ((Node) item).delete();
+ for (Item item : items) if (item instanceof Node) ((Node) item).delete();
tx.commit();
} finally {
tx.abortIfIncomplete();
@@ -308,10 +274,7 @@
@Override public boolean equals(Object o) {
if (!(o instanceof ItemList)) return false;
- ItemList that = (ItemList) o;
- if (this.size() != that.size()) return false;
- for (int i=0; i<size(); i++) if (!this.get(i).equals(that.get(i))) return false;
- return true;
+ return items.equals(((ItemList) o).items);
}
/**
@@ -320,7 +283,7 @@
*/
@Override public int hashCode() {
int hashCode = 1;
- for (Item item : this) hashCode = hashCode * 31 + item.hashCode();
+ for (Item item : items) hashCode = hashCode * 31 + item.hashCode();
return hashCode;
}
@@ -330,20 +293,7 @@
* @return an iterator over this item list
*/
public Iterator<Item> iterator() {
- try {
- return new Iterator<Item>() {
- private final SequenceIterator delegate = seq.iterate();
- public boolean hasNext() {
- return delegate.hasNext();
- }
- public Item next() {
- return wrap(delegate.nextItem());
- }
- public void remove() {throw new UnsupportedOperationException();}
- };
- } catch (XPathException e) {
- throw new DatabaseException("failed to construct iterator over sequence", e);
- }
+ return items.iterator();
}
/**
@@ -352,14 +302,7 @@
* @return a list view
*/
public List<Item> asList() {
- return new AbstractList<Item>() {
- @Override public Item get(int index) {
- return wrap(seq.itemAt(index));
- }
- @Override public int size() {
- return seq.getItemCount();
- }
- };
+ return items;
}
/**
@@ -368,7 +311,7 @@
* @return an array of items
*/
public Item[] toArray() {
- return toArray(new Item[size()]);
+ return items.toArray(new Item[size()]);
}
/**
@@ -380,12 +323,7 @@
* @return an array of items
*/
public Item[] toArray(Item[] a) {
- if (a.length < size()) a = new Item[size()];
- for (int i = 0; i < size(); i++) {
- a[i] = wrap(seq.itemAt(i));
- }
- if (a.length > size()) a[size()] = null;
- return a;
+ return items.toArray(a);
}
@Override
@@ -393,7 +331,7 @@
StringBuilder buf = new StringBuilder();
buf.append("(");
boolean first = true;
- for (Item item : this) {
+ for (Item item : items) {
if (first) first = false; else buf.append(", ");
buf.append(item);
}
@@ -426,8 +364,6 @@
static final ItemList NULL = new ItemList() {
@Override public QueryService query() {return QueryService.NULL;}
- @Override public int size() {return 0;}
- @Override public Iterator<Item> iterator() {return Database.emptyIterator();}
@Override public ValuesFacet values() {return new ValuesFacet() {
@Override public Iterator<String> iterator() {return Database.emptyIterator();}
// toArray/0 and toArray/1 take care of themselves thanks to size()
@@ -436,9 +372,6 @@
@Override public Iterator<Node> iterator() {return Database.emptyIterator();}
// toArray/0 and toArray/1 take care of themselves thanks to size()
};}
- @Override Sequence convertToSequence() {
- return Sequence.EMPTY_SEQUENCE;
- }
};
}
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/Node.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/Node.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/Node.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -9,7 +9,6 @@
import org.exist.collections.triggers.*;
import org.exist.collections.triggers.Trigger;
import org.exist.dom.*;
-import org.exist.storage.DBBroker;
import org.exist.storage.io.VariableByteOutputStream;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.*;
@@ -24,13 +23,12 @@
public class Node extends Item {
private XMLDocument document;
- private final StaleMarker staleMarker = new StaleMarker();
+ final StaleMarker staleMarker = new StaleMarker();
private Node() {}
- Node(org.exist.xquery.value.Item item, NamespaceMap namespaceBindings, Database db) {
+ Node(org.exist.xquery.value.NodeValue item, NamespaceMap namespaceBindings, Database db) {
super(item, namespaceBindings, db);
- if (!(item instanceof NodeValue)) throw new IllegalArgumentException("item is not a node");
if (item instanceof NodeProxy) {
NodeProxy proxy = (NodeProxy) item;
String docPath = proxy.getDocument().getURI().getCollectionPath();
@@ -40,12 +38,17 @@
}
}
+ @Override Sequence convertToSequence() {
+ staleMarker.check();
+ return super.convertToSequence();
+ }
+
public boolean extant() {
return !staleMarker.stale();
}
org.w3c.dom.Node getDOMNode() {
- staleMarker.check();
+ staleMarker.check();
try {
org.w3c.dom.Node domNode = ((NodeValue) item).getNode();
if (domNode == null) throw new DatabaseException("unable to load node data");
@@ -190,23 +193,16 @@
final StoredNode node = (StoredNode) getDOMNode();
return new ElementBuilder<Node>(namespaceBindings, true, new ElementBuilder.CompletedCallback<Node>() {
public Node completed(org.w3c.dom.Node[] nodes) {
- Transaction tx = Database.requireTransaction();
+ Transaction tx = db.requireTransactionWithBroker();
try {
tx.lockWrite(node.getDocument());
DocumentTrigger trigger = fireTriggerBefore(tx);
- StoredNode result = null;
- if (nodes.length == 1) {
- result = (StoredNode) node.appendChild(nodes[0]);
- } else {
- node.appendChildren(tx.tx, toNodeList(nodes), 0);
- }
- ((DocumentImpl) node.getOwnerDocument()).getMetadata().setLastModified(System.currentTimeMillis());
- defrag();
- fireTriggerAfter(tx, trigger);
+ node.appendChildren(tx.tx, toNodeList(nodes), 0);
+ StoredNode result = (StoredNode) node.getLastChild();
+ touchDefragAndFireTriggerAfter(tx, trigger);
tx.commit();
if (result == null) return null;
NodeProxy proxy = new NodeProxy((DocumentImpl) result.getOwnerDocument(), result.getNodeId(), result.getNodeType(), result.getInternalAddress());
- Database.trackNode(proxy);
return new Node(proxy, namespaceBindings.extend(), db);
} catch (DOMException e) {
throw new DatabaseException(e);
@@ -245,12 +241,12 @@
} else if (parent == null) {
throw new DatabaseException("cannot delete node with no parent");
} else {
- Transaction tx = Database.requireTransaction();
+ Transaction tx = db.requireTransactionWithBroker();
try {
if (parent instanceof StoredNode) tx.lockWrite(((StoredNode) parent).getDocument());
DocumentTrigger trigger = fireTriggerBefore(tx);
parent.removeChild(tx.tx, child);
- fireTriggerAfter(tx, trigger);
+ touchDefragAndFireTriggerAfter(tx, trigger);
tx.commit();
} catch (DOMException e) {
throw new DatabaseException(e);
@@ -300,15 +296,13 @@
return new ElementBuilder<Object>(namespaceBindings, false, new ElementBuilder.CompletedCallback<Object>() {
public Object completed(org.w3c.dom.Node[] nodes) {
assert nodes.length == 1;
- Transaction tx = Database.requireTransaction();
+ Transaction tx = db.requireTransactionWithBroker();
try {
DocumentImpl doc = (DocumentImpl) oldNode.getOwnerDocument();
tx.lockWrite(doc);
DocumentTrigger trigger = fireTriggerBefore(tx);
((NodeImpl) oldNode.getParentNode()).replaceChild(tx.tx, nodes[0], oldNode);
- doc.getMetadata().setLastModified(System.currentTimeMillis());
- defrag();
- fireTriggerAfter(tx, trigger);
+ touchDefragAndFireTriggerAfter(tx, trigger);
tx.commit();
// no point in returning the old node; we'd rather return the newly inserted one,
// but it's not easily available
@@ -342,15 +336,13 @@
final ElementImpl elem = (ElementImpl) getDOMNode();
return new AttributeBuilder(elem, namespaceBindings, new AttributeBuilder.CompletedCallback() {
public void completed(NodeList removeList, NodeList addList) {
- Transaction tx = Database.requireTransaction();
+ Transaction tx = db.requireTransactionWithBroker();
try {
DocumentImpl doc = (DocumentImpl) elem.getOwnerDocument();
tx.lockWrite(doc);
DocumentTrigger trigger = fireTriggerBefore(tx);
elem.removeAppendAttributes(tx.tx, removeList, addList);
- doc.getMetadata().setLastModified(System.currentTimeMillis());
- defrag();
- fireTriggerAfter(tx, trigger);
+ touchDefragAndFireTriggerAfter(tx, trigger);
tx.commit();
} catch (TriggerException e) {
throw new DatabaseException("append aborted by listener", e);
@@ -371,37 +363,27 @@
private DocumentTrigger fireTriggerBefore(Transaction tx) throws TriggerException {
if (!(item instanceof NodeProxy)) return null;
DocumentImpl docimpl = ((NodeProxy) item).getDocument();
- DBBroker broker = null;
try {
- broker = db.acquireBroker();
- CollectionConfiguration config = docimpl.getCollection().getConfiguration(broker);
+ CollectionConfiguration config = docimpl.getCollection().getConfiguration(tx.broker);
if (config == null) return null;
- DocumentTrigger trigger = (DocumentTrigger) config.newTrigger(Trigger.UPDATE_DOCUMENT_EVENT, broker, docimpl.getCollection());
+ DocumentTrigger trigger = (DocumentTrigger) config.newTrigger(Trigger.UPDATE_DOCUMENT_EVENT, tx.broker, docimpl.getCollection());
if (trigger == null) return null;
- trigger.prepare(Trigger.UPDATE_DOCUMENT_EVENT, broker, tx.tx, docimpl.getURI(), docimpl);
+ trigger.prepare(Trigger.UPDATE_DOCUMENT_EVENT, tx.broker, tx.tx, docimpl.getURI(), docimpl);
return trigger;
} catch (CollectionConfigurationException e) {
throw new DatabaseException(e);
- } finally {
- db.releaseBroker(broker);
}
}
- private void fireTriggerAfter(Transaction tx, DocumentTrigger trigger) {
+ private void touchDefragAndFireTriggerAfter(Transaction tx, DocumentTrigger trigger) {
+ DocumentImpl doc = ((NodeProxy) item).getDocument();
+ doc.getMetadata().setLastModified(System.currentTimeMillis());
+ tx.broker.storeXMLResource(tx.tx, doc);
+ if (item instanceof NodeProxy) Database.queueDefrag(((NodeProxy) item).getDocument());
if (trigger == null) return;
- DBBroker broker = null;
- try {
- broker = db.acquireBroker();
- DocumentImpl docimpl = ((NodeProxy) item).getDocument();
- trigger.finish(Trigger.UPDATE_DOCUMENT_EVENT, broker, tx.tx, docimpl.getURI(), docimpl);
- } finally {
- db.releaseBroker(broker);
- }
+ DocumentImpl docimpl = ((NodeProxy) item).getDocument();
+ trigger.finish(Trigger.UPDATE_DOCUMENT_EVENT, tx.broker, tx.tx, docimpl.getURI(), docimpl);
}
-
- private void defrag() {
- if (item instanceof NodeProxy) Database.queueDefrag(((NodeProxy) item).getDocument());
- }
static NodeList toNodeList(final org.w3c.dom.Node[] nodes) {
return new NodeList() {
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/QueryService.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/QueryService.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/QueryService.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -281,12 +281,12 @@
XQueryContext context;
if (compiledQuery == null) {
context = xquery.newContext(AccessContext.INTERNAL_PREFIX_LOOKUP);
- buildXQueryStaticContext(context);
+ buildXQueryStaticContext(context, true);
} else {
context = compiledQuery.getContext();
// static context already set
}
- buildXQueryDynamicContext(context, params, docsToLock);
+ buildXQueryDynamicContext(context, params, docsToLock, true);
t2 = System.currentTimeMillis();
if (compiledQuery == null) {
compiledQuery = xquery.compile(context, source);
@@ -338,25 +338,27 @@
return new StringSourceWithMapKey(query, combinedMap);
}
- private void buildXQueryDynamicContext(XQueryContext context, Object[] params, MutableDocumentSet docsToLock) throws XPathException {
+ private void buildXQueryDynamicContext(XQueryContext context, Object[] params, MutableDocumentSet docsToLock, boolean bindVariables) throws XPathException {
context.setBackwardsCompatibility(false);
context.setStaticallyKnownDocuments(docs);
context.setBaseURI(baseUri == null ? new AnyURIValue("/db") : baseUri);
- for (Map.Entry<QName, Object> entry : bindings.entrySet()) {
- context.declareVariable(
- new org.exist.dom.QName(entry.getKey().getLocalPart(), entry.getKey().getNamespaceURI(), entry.getKey().getPrefix()),
- convertValue(entry.getValue()));
- }
- if (params != null) for (int i = 0; i < params.length; i++) {
- Object convertedValue = convertValue(params[i]);
- if (docsToLock != null && convertedValue instanceof Sequence) {
- docsToLock.addAll(((Sequence) convertedValue).getDocumentSet());
+ if (bindVariables) {
+ for (Map.Entry<QName, Object> entry : bindings.entrySet()) {
+ context.declareVariable(
+ new org.exist.dom.QName(entry.getKey().getLocalPart(), entry.getKey().getNamespaceURI(), entry.getKey().getPrefix()),
+ convertValue(entry.getValue()));
}
- context.declareVariable("_"+(i+1), convertedValue);
+ if (params != null) for (int i = 0; i < params.length; i++) {
+ Object convertedValue = convertValue(params[i]);
+ if (docsToLock != null && convertedValue instanceof Sequence) {
+ docsToLock.addAll(((Sequence) convertedValue).getDocumentSet());
+ }
+ context.declareVariable("_"+(i+1), convertedValue);
+ }
}
}
- private void buildXQueryStaticContext(XQueryContext context) throws XPathException {
+ private void buildXQueryStaticContext(XQueryContext context, boolean importModules) throws XPathException {
context.declareNamespaces(namespaceBindings.getCombinedMap());
for (Map.Entry<String, Document> entry : moduleMap.entrySet()) {
context.importModule(entry.getKey(), null, "xmldb:exist:///db" + entry.getValue().path());
@@ -403,7 +405,7 @@
StringBuffer buf = new StringBuffer();
Matcher matcher = PRE_SUB_PATTERN.matcher(query);
while(matcher.find()) {
- matcher.appendReplacement(buf, (String) params[Integer.parseInt(matcher.group(1))-1]);
+ matcher.appendReplacement(buf, ((String) params[Integer.parseInt(matcher.group(1))-1]).replace("\\", "\\\\").replace("$", "\\$"));
}
matcher.appendTail(buf);
return buf.toString();
@@ -495,8 +497,6 @@
public QueryAnalysis analyze(String query, Object... params) {
if (presub) query = presub(query, params);
- final Set<QName> requiredVariables = new TreeSet<QName>();
- final Set<QName> requiredFunctions = new TreeSet<QName>();
long t1 = System.currentTimeMillis(), t2 = 0, t3 = 0;
DBBroker broker = null;
try {
@@ -507,22 +507,20 @@
final XQueryPool pool = xquery.getXQueryPool();
CompiledXQuery compiledQuery = pool.borrowCompiledXQuery(broker, source);
try {
- XQueryContext context;
+ AnalysisXQueryContext context;
if (compiledQuery == null) {
- context = createAnalysisContext(broker, requiredVariables, requiredFunctions);
- buildXQueryStaticContext(context);
- } else {
- context = compiledQuery.getContext();
- // static context already set
- }
- buildXQueryDynamicContext(context, params, null);
- t2 = System.currentTimeMillis();
- if (compiledQuery == null) {
+ context = new AnalysisXQueryContext(broker, AccessContext.INTERNAL_PREFIX_LOOKUP);
+ buildXQueryStaticContext(context, false);
+ buildXQueryDynamicContext(context, params, null, false);
+ t2 = System.currentTimeMillis();
compiledQuery = xquery.compile(context, source);
t3 = System.currentTimeMillis();
+ } else {
+ context = (AnalysisXQueryContext) compiledQuery.getContext();
+ t2 = System.currentTimeMillis();
}
return new QueryAnalysis(
- compiledQuery, Collections.unmodifiableSet(requiredVariables), Collections.unmodifiableSet(requiredFunctions));
+ compiledQuery, Collections.unmodifiableSet(context.requiredVariables), Collections.unmodifiableSet(context.requiredFunctions));
} finally {
if (compiledQuery != null) pool.returnCompiledXQuery(source, compiledQuery);
}
@@ -536,29 +534,35 @@
STATS.update(query, t1, t2, t3, 0, System.currentTimeMillis());
}
}
-
- private XQueryContext createAnalysisContext(DBBroker broker, final Set<QName> requiredVariables, final Set<QName> requiredFunctions) {
- return new XQueryContext(broker, AccessContext.INTERNAL_PREFIX_LOOKUP) {
- @Override public Variable resolveVariable(org.exist.dom.QName qname) throws XPathException {
- Variable var = super.resolveVariable(qname);
- if (var == null) {
- requiredVariables.add(new QName(qname.getNamespaceURI(), qname.getLocalName(), qname.getPrefix()));
- var = new Variable(qname);
- }
- return var;
+
+ private static final class AnalysisXQueryContext extends XQueryContext {
+ final Set<QName> requiredFunctions = new TreeSet<QName>();
+ final Set<QName> requiredVariables = new TreeSet<QName>();
+
+ private AnalysisXQueryContext(DBBroker broker, AccessContext accessCtx) {
+ super(broker, accessCtx);
+ }
+
+ @Override public Variable resolveVariable(org.exist.dom.QName qname) throws XPathException {
+ Variable var = super.resolveVariable(qname);
+ if (var == null) {
+ requiredVariables.add(new QName(qname.getNamespaceURI(), qname.getLocalName(), qname.getPrefix()));
+ var = new Variable(qname);
}
- @Override public UserDefinedFunction resolveFunction(org.exist.dom.QName qname, int argCount) throws XPathException {
- UserDefinedFunction func = super.resolveFunction(qname, argCount);
- if (func == null) {
- requiredFunctions.add(new QName(qname.getNamespaceURI(), qname.getLocalName(), qname.getPrefix()));
- func = new UserDefinedFunction(this, new FunctionSignature(qname, null, new SequenceType(Type.ITEM, org.exist.xquery.Cardinality.ZERO_OR_MORE), true));
- func.setFunctionBody(new SequenceConstructor(this));
- }
- return func;
+ return var;
+ }
+
+ @Override public UserDefinedFunction resolveFunction(org.exist.dom.QName qname, int argCount) throws XPathException {
+ UserDefinedFunction func = super.resolveFunction(qname, argCount);
+ if (func == null) {
+ requiredFunctions.add(new QName(qname.getNamespaceURI(), qname.getLocalName(), qname.getPrefix()));
+ func = new UserDefinedFunction(this, new FunctionSignature(qname, null, new SequenceType(Type.ITEM, org.exist.xquery.Cardinality.ZERO_OR_MORE), true));
+ func.setFunctionBody(new SequenceConstructor(this));
}
- };
+ return func;
+ }
}
-
+
/**
* An access point for running various analyses on a query.
*/
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/Transaction.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/Transaction.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/Transaction.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -1,6 +1,7 @@
package org.exist.fluent;
import org.exist.dom.DocumentImpl;
+import org.exist.storage.DBBroker;
import org.exist.storage.lock.Lock;
import org.exist.storage.txn.*;
import org.exist.util.LockException;
@@ -17,6 +18,8 @@
class Transaction {
private final TransactionManager txManager;
final Txn tx;
+ final DBBroker broker;
+ private final Database db;
private boolean complete;
/**
@@ -24,9 +27,11 @@
*
* @param txManager the manager to use
*/
- Transaction(TransactionManager txManager) {
+ Transaction(TransactionManager txManager, Database db) {
this.txManager = txManager;
this.tx = txManager.beginTransaction();
+ this.db = db;
+ this.broker = db == null ? null : db.acquireBroker();
complete = false;
}
@@ -35,25 +40,32 @@
*
* @param tx the transaction to join
*/
- Transaction(Txn tx) {
+ Transaction(Transaction tx, Database db) {
this.txManager = null;
- this.tx = tx;
+ this.tx = tx.tx;
+ this.db = db;
+ this.broker = db == null ? null : db.acquireBroker();
complete = true;
}
void commit() {
if (complete) return;
- if (tx != null && txManager != null) try {
- txManager.commit(tx);
- complete = true;
- } catch (TransactionException e) {
- throw new DatabaseException(e);
+ try {
+ if (tx != null && txManager != null) try {
+ txManager.commit(tx);
+ complete = true;
+ } catch (TransactionException e) {
+ throw new DatabaseException(e);
+ }
+ } finally {
+ if (broker != null) db.releaseBroker(broker);
}
}
void abortIfIncomplete() {
if (complete) return;
if (tx != null && txManager != null) txManager.abort(tx);
+ if (broker != null) db.releaseBroker(broker);
complete = true;
}
Modified: trunk/eXist/extensions/fluent/src/org/exist/fluent/XMLDocument.java
===================================================================
--- trunk/eXist/extensions/fluent/src/org/exist/fluent/XMLDocument.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/src/org/exist/fluent/XMLDocument.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -32,6 +32,7 @@
}
@Override Sequence convertToSequence() {
+ staleMarker.check();
return proxy;
}
Modified: trunk/eXist/extensions/fluent/test/src/org/exist/fluent/ItemListTest.java
===================================================================
--- trunk/eXist/extensions/fluent/test/src/org/exist/fluent/ItemListTest.java 2008-12-29 22:38:43 UTC (rev 8437)
+++ trunk/eXist/extensions/fluent/test/src/org/exist/fluent/ItemListTest.java 2008-12-30 01:40:26 UTC (rev 8438)
@@ -56,9 +56,17 @@
assertEquals(2, doc.query().all("$_1//c", new Object[] { res }).size());
}
- @Test public void deleteAllNodes() {
+ @Test public void deleteAllNodes1() {
XMLDocument doc = db.createFolder("/top").documents().load(Name.generate(), Source.xml(
"<foo><bar><bar/></bar></foo>"));
doc.query().all("//bar").deleteAllNodes();
+ assertEquals("<foo/>", doc.contentsAsString());
}
+
+ @Test public void deleteAllNodes2() {
+ XMLDocument doc = db.createFolder("/top").documents().load(Name.generate(), Source.xml(
+ "<bar><bar><bar/></bar></bar>"));
+ doc.query().all("//bar").deleteAllNodes();
+ assertEquals(0, db.getFolder("/top").documents().size());
+ }
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <pka...@us...> - 2008-12-29 22:38:47
|
Revision: 8437
http://exist.svn.sourceforge.net/exist/?rev=8437&view=rev
Author: pkaminsk2
Date: 2008-12-29 22:38:43 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Fixed stack overflow bug introduced by module caching change.
Modified Paths:
--------------
trunk/eXist/src/org/exist/xquery/ModuleContext.java
Modified: trunk/eXist/src/org/exist/xquery/ModuleContext.java
===================================================================
--- trunk/eXist/src/org/exist/xquery/ModuleContext.java 2008-12-29 21:40:15 UTC (rev 8436)
+++ trunk/eXist/src/org/exist/xquery/ModuleContext.java 2008-12-29 22:38:43 UTC (rev 8437)
@@ -94,6 +94,9 @@
*/
public Module getModule(String namespaceURI) {
Module module = super.getModule(namespaceURI);
+ // TODO: I don't think modules should be able to access their parent context's modules,
+ // since that breaks lexical scoping. However, it seems that some eXist modules rely on
+ // this so let's leave it for now. (pkaminsk2)
if(module == null)
module = parentContext.getModule(namespaceURI);
return module;
@@ -119,13 +122,6 @@
return module;
}
- /* (non-Javadoc)
- * @see org.exist.xquery.XQueryContext#getModules()
- */
- public Iterator getModules() {
- return parentContext.getModules();
- }
-
/* (non-Javadoc)
* @see org.exist.xquery.XQueryContext#getWatchDog()
*/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <pka...@us...> - 2008-12-29 22:22:20
|
Revision: 8436
http://exist.svn.sourceforge.net/exist/?rev=8436&view=rev
Author: pkaminsk2
Date: 2008-12-29 21:40:15 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Re-checking-in overwritten change.
Modified Paths:
--------------
trunk/eXist/src/org/exist/storage/NativeBroker.java
Modified: trunk/eXist/src/org/exist/storage/NativeBroker.java
===================================================================
--- trunk/eXist/src/org/exist/storage/NativeBroker.java 2008-12-29 21:26:17 UTC (rev 8435)
+++ trunk/eXist/src/org/exist/storage/NativeBroker.java 2008-12-29 21:40:15 UTC (rev 8436)
@@ -73,8 +73,8 @@
import org.exist.util.LockException;
import org.exist.util.ReadOnlyException;
import org.exist.xmldb.XmldbURI;
-import org.exist.xquery.TerminatedException;
-import org.exist.xquery.value.Type;
+import org.exist.xquery.*;
+import org.exist.xquery.value.*;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Node;
@@ -2025,14 +2025,18 @@
InputStream is = getBinaryResource((BinaryDocument) doc);
destination.addBinaryResource(transaction, this, newName, is, doc.getMetadata().getMimeType(),-1);
} else {
- //TODO : put a lock on newDoc ?
DocumentImpl newDoc = new DocumentImpl(pool, destination, newName);
newDoc.copyOf(doc);
newDoc.setDocId(getNextResourceId(transaction, destination));
- newDoc.setPermissions(doc.getPermissions());
- copyXMLResource(transaction, doc, newDoc);
- destination.addDocument(transaction, this, newDoc);
- storeXMLResource(transaction, newDoc);
+ newDoc.setPermissions(doc.getPermissions());
+ newDoc.getUpdateLock().acquire(Lock.WRITE_LOCK);
+ try {
+ copyXMLResource(transaction, doc, newDoc);
+ destination.addDocument(transaction, this, newDoc);
+ storeXMLResource(transaction, newDoc);
+ } finally {
+ newDoc.getUpdateLock().release(Lock.WRITE_LOCK);
+ }
}
// saveCollection(destination);
} catch (EXistException e) {
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <pka...@us...> - 2008-12-29 21:26:20
|
Revision: 8435
http://exist.svn.sourceforge.net/exist/?rev=8435&view=rev
Author: pkaminsk2
Date: 2008-12-29 21:26:17 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Implemented MultiReadReentrantLock.attempt().
Modified Paths:
--------------
trunk/eXist/src/org/exist/storage/lock/MultiReadReentrantLock.java
Modified: trunk/eXist/src/org/exist/storage/lock/MultiReadReentrantLock.java
===================================================================
--- trunk/eXist/src/org/exist/storage/lock/MultiReadReentrantLock.java 2008-12-29 20:55:43 UTC (rev 8434)
+++ trunk/eXist/src/org/exist/storage/lock/MultiReadReentrantLock.java 2008-12-29 21:26:17 UTC (rev 8435)
@@ -109,9 +109,9 @@
}
switch (mode) {
case Lock.WRITE_LOCK:
- return writeLock();
+ return writeLock(true);
default:
- return readLock();
+ return readLock(true);
}
}
@@ -119,15 +119,25 @@
* @see org.exist.util.Lock#attempt(int)
*/
public boolean attempt(int mode) {
- throw new RuntimeException("Not implemented");
+ try {
+ switch (mode) {
+ case Lock.WRITE_LOCK:
+ return writeLock(false);
+ default:
+ return readLock(false);
+ }
+ } catch (LockException e) {
+ return false;
+ }
}
/**
* Issue a read lock if there is no outstanding write lock or threads
* waiting to get a write lock. Caller of this method must be careful to
* avoid synchronizing the calling code so as to avoid deadlock.
+ * @param waitIfNecessary whether to wait if the lock is not available right away
*/
- private synchronized boolean readLock() throws LockException {
+ private synchronized boolean readLock(boolean waitIfNecessary) throws LockException {
final Thread thisThread = Thread.currentThread();
if (writeLockedThread == thisThread) {
// add acquired lock to the current list of read locks
@@ -138,6 +148,7 @@
deadlockCheck();
waitingForReadLock++;
if (writeLockedThread != null) {
+ if (!waitIfNecessary) return false;
WaitingThread waiter = new WaitingThread(thisThread, this, this, Lock.READ_LOCK);
DeadlockDetection.addResourceWaiter(thisThread, waiter);
while (writeLockedThread != null) {
@@ -159,8 +170,9 @@
* Issue a write lock if there are no outstanding read or write locks.
* Caller of this method must be careful to avoid synchronizing the calling
* code so as to avoid deadlock.
+ * @param waitIfNecessary whether to wait if the lock is not available right away
*/
- private boolean writeLock() throws LockException {
+ private boolean writeLock(boolean waitIfNecessary) throws LockException {
Thread thisThread = Thread.currentThread();
WaitingThread waiter;
synchronized (this) {
@@ -178,6 +190,7 @@
return true;
}
+ if (!waitIfNecessary) return false;
// if (writeLockedThread == thisThread) {
// LOG.debug("nested write lock: " + outstandingWriteLocks);
// }
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <del...@us...> - 2008-12-29 20:55:53
|
Revision: 8434
http://exist.svn.sourceforge.net/exist/?rev=8434&view=rev
Author: deliriumsky
Date: 2008-12-29 20:55:43 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
Mainly refactoring and testing of XQRemoteConnection
Modified Paths:
--------------
branches/allad/jsr-225/src/org/exist/xqj/Constants.java
branches/allad/jsr-225/src/org/exist/xqj/EXistXQDataSource.java
branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java
branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java
branches/allad/jsr-225/src/org/exist/xqj/XQConnectionEventHandler.java
branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java
branches/allad/jsr-225/test/src/org/exist/xqj/AllXQJTests.java
branches/allad/jsr-225/test/src/org/exist/xqj/EXistXQDataSourceTest.java
Added Paths:
-----------
branches/allad/jsr-225/lib/core/httpclient-4.0-beta2.jar
branches/allad/jsr-225/lib/core/httpcore-4.0-beta3.jar
branches/allad/jsr-225/lib/core/httpmime-4.0-beta2.jar
branches/allad/jsr-225/test/src/org/exist/xqj/remote/XQRemoteConnectionTest.java
Added: branches/allad/jsr-225/lib/core/httpclient-4.0-beta2.jar
===================================================================
(Binary files differ)
Property changes on: branches/allad/jsr-225/lib/core/httpclient-4.0-beta2.jar
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: branches/allad/jsr-225/lib/core/httpcore-4.0-beta3.jar
===================================================================
(Binary files differ)
Property changes on: branches/allad/jsr-225/lib/core/httpcore-4.0-beta3.jar
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Added: branches/allad/jsr-225/lib/core/httpmime-4.0-beta2.jar
===================================================================
(Binary files differ)
Property changes on: branches/allad/jsr-225/lib/core/httpmime-4.0-beta2.jar
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Modified: branches/allad/jsr-225/src/org/exist/xqj/Constants.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/Constants.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/src/org/exist/xqj/Constants.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -63,6 +63,10 @@
public final static String DEFAULT_COLLECTION_PATH = "/db";
- public final static int DEFAULT_LOGIN_TIMEOUT = 0;
+ public final static int DEFAULT_LOGIN_TIMEOUT = 60; //seconds
public final static int DEFAULT_MAX_CONNECTIONS = 100;
+
+ /* constant values */
+ public final static String PATH_SEPARATOR = "/";
+ public final static String XQJ_UNDERLYING_PROTOCOL = "http";
}
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQDataSource.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQDataSource.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQDataSource.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -32,6 +32,9 @@
import javax.xml.xquery.XQDataSource;
import javax.xml.xquery.XQException;
+import org.apache.commons.httpclient.params.HttpConnectionParams;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
import org.exist.xqj.local.XQLocalConnection;
import org.exist.xqj.remote.XQRemoteConnection;
@@ -55,7 +58,9 @@
private PrintWriter logWriter = null;
private Properties properties = new Properties();
private SafeCount nConnections = new SafeCount(); //keeps a count of active connections
+ private HttpClient httpClient = new DefaultHttpClient();
+
//thread safe count
private class SafeCount
{
@@ -128,6 +133,8 @@
properties.put(Constants.PROP_SERVER_TYPE, Constants.DEFAULT_SERVER_TYPE);
properties.put(Constants.PROP_SERVER_NAME, Constants.DEFAULT_SERVER_NAME);
properties.put(Constants.PROP_SERVER_PORT, Integer.toString(Constants.DEFAULT_SERVER_PORT));
+
+ httpClient.getParams().setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT, Constants.DEFAULT_LOGIN_TIMEOUT * 1000);
}
/* (non-Javadoc)
@@ -165,7 +172,7 @@
{
if(getServerType().equals(Constants.SERVER_TYPE_REMOTE))
{
- con = new XQRemoteConnection(getServerName(), getServerPort(), getCollectionPath(), username, passwd, this);
+ con = new XQRemoteConnection(httpClient, getServerName(), getServerPort(), getCollectionPath(), username, passwd, this);
}
else
{
@@ -471,13 +478,24 @@
/**
* Sets the collection path for the connection
+ *
+ * @param collectionPath The collection path for the connection
+ *
+ * @throws XQException if the collection path is invalidly formatted
*/
public void setCollectionPath(String collectionPath) throws XQException
{
+ if(collectionPath != null && !collectionPath.startsWith(Constants.PATH_SEPARATOR))
+ throw new XQException("Collection path must start with a '" + Constants.PATH_SEPARATOR + "'");
+
setProperty(Constants.PROP_COLLECTION_PATH, collectionPath);
}
-
+ /**
+ * Calls the closeConnection on the handler and then cleans up our knowledge of the connection
+ *
+ * @param handler The handler for the connection
+ */
public void closeConnection(XQConnectionEventHandler handler) throws XQException
{
try
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQItemType.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -22,19 +22,17 @@
*/
package org.exist.xqj;
-import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.namespace.QName;
import javax.xml.xquery.XQException;
+import javax.xml.xquery.XQItemType;
import javax.xml.xquery.XQSequenceType;
-import javax.xml.xquery.XQItemType;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.NodeValue;
import org.exist.xquery.value.Type;
-import org.w3c.dom.Node;
/**
* An implementation class for the XQJ interface XQItemType
@@ -42,7 +40,7 @@
* @author Cherif YAYA <ch...@gm...>
*
*/
-public class EXistXQItemType implements javax.xml.xquery.XQItemType
+public class EXistXQItemType implements XQItemType, Cloneable
{
private int itemKind;
private int baseType;
@@ -347,4 +345,24 @@
return null;
}
+ public Object clone()
+ {
+ EXistXQItemType newItemType = new EXistXQItemType();
+
+ newItemType.itemKind = itemKind;
+ newItemType.baseType = baseType;
+ newItemType.nodeName = new QName(nodeName.getNamespaceURI(), nodeName.getLocalPart(), nodeName.getPrefix());
+ newItemType.typeName = new QName(typeName.getNamespaceURI(), typeName.getLocalPart(), typeName.getPrefix());
+
+ try
+ {
+ newItemType.typeSchemaURI = new URI(typeSchemaURI.toString());
+ }
+ catch(URISyntaxException use)
+ {
+ //should not happen
+ }
+
+ return newItemType;
+ }
}
Modified: branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/src/org/exist/xqj/EXistXQStaticContext.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -34,7 +34,7 @@
*
* @author Cherif YAYA
*/
-public class EXistXQStaticContext implements XQStaticContext {
+public class EXistXQStaticContext implements XQStaticContext, Cloneable {
//default values recommended by the XQJ specs
private int scrollability = XQConstants.SCROLLTYPE_FORWARD_ONLY;
@@ -343,4 +343,35 @@
public void setScrollability(int scrollability) throws XQException {
this.scrollability = scrollability;
}
+
+ public Object clone() throws CloneNotSupportedException
+ {
+ EXistXQStaticContext newContext = new EXistXQStaticContext();
+ newContext.scrollability = scrollability;
+ newContext.holdability = holdability;
+
+ Hashtable newContextNamespaces = new Hashtable();
+ newContextNamespaces.putAll(namespaces);
+ newContext.namespaces = newContextNamespaces;
+
+ newContext.baseURI = baseURI;
+ newContext.bindingMode = bindingMode;
+ newContext.constructionMode = constructionMode;
+ newContext.orderingMode = orderingMode;
+ newContext.queryTimeout = queryTimeout;
+ newContext.defaultCollation = defaultCollation;
+ newContext.defaultElementTypeNamespace = defaultElementTypeNamespace;
+ newContext.defaultFunctionNamespace = defaultFunctionNamespace;
+
+ if(ctxtItemType != null)
+ newContext.ctxtItemType = (EXistXQItemType)((EXistXQItemType)ctxtItemType).clone();
+
+ newContext.copyNamespacesModeInherit = copyNamespacesModeInherit;
+ newContext.copyNamespacesModePreserve = copyNamespacesModePreserve;
+ newContext.boundarySpacePolicy = boundarySpacePolicy;
+ newContext.defaultOrderForEmptySequence = defaultOrderForEmptySequence;
+ newContext.langType = langType;
+
+ return newContext;
+ }
}
Modified: branches/allad/jsr-225/src/org/exist/xqj/XQConnectionEventHandler.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/XQConnectionEventHandler.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/src/org/exist/xqj/XQConnectionEventHandler.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -3,7 +3,7 @@
import javax.xml.xquery.XQException;
/**
- * @author Adam Retter <ada...@ex...>
+ * @author Adam Retter <ad...@ex...>
*/
public interface XQConnectionEventHandler
{
Modified: branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java
===================================================================
--- branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/src/org/exist/xqj/remote/XQRemoteConnection.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -22,20 +22,16 @@
*/
package org.exist.xqj.remote;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.IOException;
import java.io.Reader;
import java.net.URI;
-
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.xquery.XQConnection;
@@ -50,29 +46,19 @@
import javax.xml.xquery.XQSequenceType;
import javax.xml.xquery.XQStaticContext;
-import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpHead;
import org.apache.log4j.Logger;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-
-import org.exist.memtree.SAXAdapter;
import org.exist.xqj.Constants;
import org.exist.xqj.EXistXQDataFactoryImpl;
import org.exist.xqj.EXistXQMetadata;
import org.exist.xqj.EXistXQStaticContext;
import org.exist.xqj.XQConnectionEventHandler;
+import org.w3c.dom.Node;
+import org.xml.sax.XMLReader;
/**
* The XQRemoteConnection models a connection to a remote eXist database. From
@@ -81,158 +67,215 @@
* Before closing, the connection object frees all his resources.
*
* @author Cherif YAYA (allad)
+ * @author Adam Retter <ad...@ex...>
*/
public class XQRemoteConnection implements XQConnection, XQConnectionEventHandler
{
private final static Logger LOG = Logger.getLogger(XQRemoteConnection.class);
- private XQConnectionEventHandler conEventHandler = null;
-
+ private HttpClient httpClient = null;
private String serverName = null;
private int serverPort = -1;
private String collectionPath = null;
private String username = null;
private String password = null;
+ private XQConnectionEventHandler conEventHandler = null;
+
+ private String remoteURL = null; //Remote URL to use
+ private boolean connectionClosed = false; //is this connection closed?
+ private boolean autoCommit = true; //JSR-225/XQJ spec requires true by default which is good as thats all eXist will support at present
+ private XQStaticContext staticContext = new EXistXQStaticContext();
private XQDataFactory dataFactory = new EXistXQDataFactoryImpl(this);
- private XQStaticContext staticContext = new EXistXQStaticContext();
-
- private boolean connectionClosed = false;
- //Remote URL to use
- private String remoteURL = null;
-
- private boolean autoCommit = true;
-
//expressions
private List expressions = new ArrayList();
- //constructors have package visibility so that they can only be created from
- //EXistXQDatasource
- public XQRemoteConnection(String server, int port, String collection, String username, String password, XQConnectionEventHandler conEventHandler) throws XQException
+ public XQRemoteConnection(HttpClient httpClient, String serverName, int serverPort, String collectionPath, String username, String password, XQConnectionEventHandler conEventHandler) throws XQException
{
- this.conEventHandler = conEventHandler;
+ if(httpClient == null)
+ throw new XQException("A HTTPClient is required for a remote XQJ connection");
- if(server == null)
- throw new IllegalArgumentException("The server name can't be null"); // TODO why?
+ if(serverName == null)
+ throw new XQException("A server name is required for a remote XQJ connection");
- serverName = server;
- serverPort = port;
- if(serverPort < 0)
- serverPort = Constants.DEFAULT_SERVER_PORT;
+ if(collectionPath == null)
+ throw new XQException("A collection path is required for a remote XQJ connection");
- collectionPath = collection;
- if(!collectionPath.startsWith("/")) // TODO NPE
- collectionPath = "/" + collectionPath;
+ if(!collectionPath.startsWith(Constants.PATH_SEPARATOR))
+ throw new XQException("Collection path must start with a '" + Constants.PATH_SEPARATOR + "'");
+ if(username == null)
+ throw new XQException("A username is required for a remote XQJ connection");
+
+ if(password == null)
+ throw new XQException("A password is required for a remote XQJ connection");
+
+ if(conEventHandler == null)
+ throw new XQException("A connection event handler is required for a remote XQJ connection");
+
+ this.httpClient = httpClient;
+ this.serverName = serverName;
+ this.serverPort = serverPort;
+ this.collectionPath = collectionPath;
this.username = username;
this.password = password;
+ this.conEventHandler = conEventHandler;
// form remote URL
- String url = "http://"+serverName+":"+serverPort;
- //url += "/exist/rest/";
- String tmp = "/"+collectionPath.substring(1);
- url += tmp;
-
- remoteURL = url;
+ this.remoteURL = Constants.XQJ_UNDERLYING_PROTOCOL + "://" + serverName + ":" + serverPort + collectionPath;
- //check wether the remote host is accessible or not
- reachResource(url,0);
+ //check whether the remote host and collection is accessible or not
+ checkResourceAvailable();
}
- public static void reachResource(String url, int timeout) throws XQException{
- HttpClient client = new HttpClient();
- //timeout 0 means no timeout
- if(timeout != 0)
- client.setConnectionTimeout(timeout);
-
- // Create a method instance.
- HeadMethod method = new HeadMethod(url);
-
- // Provide custom retry handler is necessary
- method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
- new DefaultHttpMethodRetryHandler(3, false));
-
- try {
- // Execute the method.
- int statusCode = client.executeMethod(method);
-
- if (statusCode != HttpStatus.SC_OK) {
-
- // Create a method instance.
- GetMethod gmethod = new GetMethod(url);
-
- // Provide custom retry handler is necessary
- gmethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
- new DefaultHttpMethodRetryHandler(3, false));
-
- client.executeMethod(gmethod);
-
- try {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
- InputSource src = new InputSource(gmethod.getResponseBodyAsStream());
- SAXParser parser = factory.newSAXParser();
- XMLReader reader = parser.getXMLReader();
- SAXAdapter adapter = new SAXAdapter();
- reader.setContentHandler(adapter);
- reader.parse(src);
-
- Document doc = adapter.getDocument();
-
- //check whether there is an error
- //when there is an error the response looks like
- /*
- * <rest:response xmlns:rest="" rel="nofollow">http://exist-db.org/rest">
- * <rest:http method="GET" url="http://localhost:8080/exist/rest/db/mydoc.xml" status="200"/>
- * <rest:error>{ message }</rest:error>
- * </rest:response>
- */
-
- //navigate the dom to the error node
- Node n1 = doc.getDocumentElement();
- NodeList c = n1.getChildNodes();
- Node e = c.item(1);
-
- if(e != null ) { //an error occured
-
- String msg = e.getFirstChild().getNodeValue();
- throw new XQException("Connection error : "+msg);
- }
- }catch (SAXException sxe) {
- // Error generated during parsing
- Exception x = sxe;
- if (sxe.getException() != null)
- x = sxe.getException();
- LOG.error(x.getMessage(),x);
-
- } catch (ParserConfigurationException pce) {
- // Parser with specified options can't be built
- LOG.error(pce.getMessage(),pce);
-
- } catch (IOException ioe) {
- // I/O error
- LOG.error(ioe.getMessage(),ioe);
- }
- finally {
- gmethod.releaseConnection();
- }
-
- throw new XQException("Connection error : HTTP error "+statusCode);
- }
- } catch (HttpException e) {
- LOG.error("Fatal protocol violation: " + e.getMessage());
- throw new XQException(e.toString());
- } catch (java.io.IOException e) {
- LOG.error("Fatal transport error: " + e.getMessage());
- throw new XQException(e.toString());
- } finally {
- // Release the connection.
- method.releaseConnection();
- }
+ private void checkResourceAvailable() throws XQException
+ {
+ HttpHead head = new HttpHead(remoteURL);
+ try
+ {
+ //TODO replace head with get and check that the response looks like this -
+ //<rest:response xmlns:rest="" rel="nofollow">http://exist-db.org/rest">
+ //<rest:http method="GET" url="http://localhost:8080/exist/rest/db/mydoc.xml" status="200"/>
+
+ HttpResponse response = httpClient.execute(head);
+
+ if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
+ throw new XQException("Could not connect to the remote resource, response code: " + response.getStatusLine().getStatusCode() + " reason: " + response.getStatusLine().getReasonPhrase());
+ }
+ catch (ClientProtocolException cpe)
+ {
+ throw new XQException(cpe.getMessage());
+ }
+ catch(IOException ioe)
+ {
+ throw new XQException(ioe.getMessage());
+ }
}
+ /* (non-javadoc)
+ * @see javax.xml.xquery.XQConnection#close()
+ */
+ public void close() throws XQException
+ {
+ conEventHandler.closeConnection(this);
+ }
+
+ /* (non-javadoc)
+ * @see javax.xml.xquery.XQConnection#setAutoCommit(boolean)
+ */
+ public void setAutoCommit(boolean autoCommit) throws XQException
+ {
+ throwIfClosed();
+
+ if(!autoCommit)
+ throw new XQException("eXist's XQJ only supports auto-commit at present");
+
+ this.autoCommit = autoCommit;
+ }
+
+ /* (non-javadoc)
+ * @see javax.xml.xquery.XQConnection#getAutoCommit()
+ */
+ public boolean getAutoCommit() throws XQException
+ {
+ throwIfClosed();
+
+ return autoCommit;
+ }
+
+ /* (non-javadoc)
+ * @see javax.xml.xquery.XQConnection#commit()
+ */
+ public void commit() throws XQException
+ {
+ throwIfClosed();
+
+ if(autoCommit)
+ throw new XQException("Cannot commit. Currently operating in auto-commit mode");
+ }
+
+ /* (non-javadoc)
+ * @see javax.xml.xquery.XQConnection#createExpression()
+ */
+ public XQExpression createExpression() throws XQException
+ {
+ return createExpression(this.staticContext);
+ }
+
+ /* (non-javadoc)
+ * @see javax.xml.xquery.XQConnection#createExpression(javax.xml.xquery.XQStaticContext)
+ */
+ public XQExpression createExpression(XQStaticContext properties) throws XQException
+ {
+ throwIfClosed();
+
+ if(properties == null)
+ throw new XQException("The static context may not be null");
+
+ EXistXQStaticContext newContext = null;
+ try
+ {
+ newContext = (EXistXQStaticContext)((EXistXQStaticContext)properties).clone();
+ }
+ catch(CloneNotSupportedException cnse)
+ {
+ throw new XQException("Could not copy the provided static context: " + cnse.getMessage());
+ }
+
+ XQRemoteExpression expr = new XQRemoteExpression(this, newContext);
+ expressions.add(expr);
+
+ return expr;
+ }
+
+ private void throwIfClosed() throws XQException
+ {
+ if(connectionClosed)
+ throw new XQException("Cannot process operation on a closed connection.");
+ }
+
+ public void closeConnection(XQConnectionEventHandler handler) throws XQException
+ {
+ if(connectionClosed)
+ return;
+
+ //try and close each expression, if an exception occurs continue with the next
+ //we can only throw one exception, so if there is one or more only catch the first one and then thow it at the end
+ XQExpression expr = null;
+ XQException xqException = null;
+ try
+ {
+ for(Iterator itExpr = expressions.iterator(); itExpr.hasNext(); expr = (XQExpression)itExpr.next())
+ {
+ if(!expr.isClosed())
+ {
+ try
+ {
+ expr.close();
+ }
+ catch(XQException xqe)
+ {
+ if(xqException == null)
+ xqException = xqe;
+ }
+ }
+ }
+
+ if(xqException != null)
+ throw xqException;
+ }
+ finally
+ {
+ connectionClosed = true;
+ }
+ }
+
+
+
+ //TODO ADAM HAS CODE REVIEWED UPTO HERE
+
public String getServerName() {
return serverName;
}
@@ -262,36 +305,6 @@
throw new XQException("The connection is no longer valid.");
}
- public void close() throws XQException
- {
- conEventHandler.closeConnection(this);
- }
-
- public void closeConnection(XQConnectionEventHandler handler) throws XQException
- {
- if(connectionClosed)
- return;
-
- for(Iterator i = expressions.iterator(); i.hasNext();)
- {
- XQExpression e = (XQExpression)i.next();
- if(!e.isClosed())
- e.close();
- }
-
- connectionClosed = true;
- }
-
- public void commit() throws XQException {
- // TODO Auto-generated method stub
- }
-
- public XQExpression createExpression() throws XQException {
- XQRemoteExpression expr = new XQRemoteExpression(this,this.staticContext);
- expressions.add(expr);
- return expr;
- }
-
public XQMetaData getMetaData() throws XQException {
return new EXistXQMetadata(this,username);
}
@@ -379,16 +392,6 @@
return dataFactory.createSequenceType(item, occurrence);
}
- public XQExpression createExpression(XQStaticContext props) throws XQException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public boolean getAutoCommit() throws XQException {
- isConnectionClosed();
- return this.autoCommit;
- }
-
public XQStaticContext getStaticContext() throws XQException {
return staticContext;
}
@@ -419,10 +422,7 @@
return expr;
}
- public void setAutoCommit(boolean autoCommit) throws XQException {
- isConnectionClosed();
- this.autoCommit = autoCommit;
- }
+
public void setStaticContext(XQStaticContext properties) throws XQException {
isConnectionClosed();
Modified: branches/allad/jsr-225/test/src/org/exist/xqj/AllXQJTests.java
===================================================================
--- branches/allad/jsr-225/test/src/org/exist/xqj/AllXQJTests.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/test/src/org/exist/xqj/AllXQJTests.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -21,6 +21,7 @@
*/
package org.exist.xqj;
+import org.exist.xqj.remote.XQRemoteConnectionTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -33,7 +34,8 @@
XqjDynamicContextTest.class,
XqjURITest.class,
XQDataSourceTest.class,
- EXistXQDataSourceTest.class
+ EXistXQDataSourceTest.class,
+ XQRemoteConnectionTest.class
})
public class AllXQJTests {
Modified: branches/allad/jsr-225/test/src/org/exist/xqj/EXistXQDataSourceTest.java
===================================================================
--- branches/allad/jsr-225/test/src/org/exist/xqj/EXistXQDataSourceTest.java 2008-12-29 19:13:52 UTC (rev 8433)
+++ branches/allad/jsr-225/test/src/org/exist/xqj/EXistXQDataSourceTest.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -343,6 +343,27 @@
}
@Test
+ public void setCollectionPath_invalid() throws XQException
+ {
+ EXistXQDataSource ds = new EXistXQDataSource();
+
+ assertEquals(Constants.DEFAULT_COLLECTION_PATH, ds.getCollectionPath());
+
+ boolean caughtException = false;
+ try
+ {
+ ds.setCollectionPath("db/1/b/"); //missing leading slash
+ }
+ catch(XQException xqe)
+ {
+ caughtException = true;
+ }
+ assertTrue(caughtException);
+
+ assertEquals(Constants.DEFAULT_COLLECTION_PATH, ds.getCollectionPath());
+ }
+
+ @Test
public void closeConnection() throws XQException
{
final EXistXQDataSource ds = new EXistXQDataSource();
@@ -360,6 +381,6 @@
//check the connection count was decremented
assertEquals(-1, ds.getConnectionCount());
-
}
+
}
Added: branches/allad/jsr-225/test/src/org/exist/xqj/remote/XQRemoteConnectionTest.java
===================================================================
--- branches/allad/jsr-225/test/src/org/exist/xqj/remote/XQRemoteConnectionTest.java (rev 0)
+++ branches/allad/jsr-225/test/src/org/exist/xqj/remote/XQRemoteConnectionTest.java 2008-12-29 20:55:43 UTC (rev 8434)
@@ -0,0 +1,384 @@
+package org.exist.xqj.remote;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.xml.xquery.XQException;
+import javax.xml.xquery.XQExpression;
+import javax.xml.xquery.XQStaticContext;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.exist.xqj.Constants;
+import org.exist.xqj.XQConnectionEventHandler;
+import org.hamcrest.Description;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.api.Action;
+import org.jmock.api.Invocation;
+import org.junit.Test;
+
+/**
+ * @author Adam Retter <ad...@ex...>
+ */
+public class XQRemoteConnectionTest
+{
+ @Test(expected=XQException.class)
+ public void constructor_nullHttpClient() throws XQException
+ {
+ Mockery mockery = new Mockery();
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ new XQRemoteConnection(null, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, Constants.DEFAULT_USERNAME, Constants.DEFAULT_PASSWORD, handler);
+ }
+
+ @Test(expected=XQException.class)
+ public void constructor_nullServerName() throws XQException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ new XQRemoteConnection(httpClient, null, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, Constants.DEFAULT_USERNAME, Constants.DEFAULT_PASSWORD, handler);
+ }
+
+ @Test(expected=XQException.class)
+ public void constructor_nullCollectionPath() throws XQException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ new XQRemoteConnection(httpClient, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, null, Constants.DEFAULT_USERNAME, Constants.DEFAULT_PASSWORD, handler);
+ }
+
+ @Test(expected=XQException.class)
+ public void constructor_nullUsername() throws XQException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ new XQRemoteConnection(httpClient, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, null, Constants.DEFAULT_PASSWORD, handler);
+ }
+
+ @Test(expected=XQException.class)
+ public void constructor_nullPassword() throws XQException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ new XQRemoteConnection(httpClient, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, Constants.DEFAULT_USERNAME, null, handler);
+ }
+
+ @Test(expected=XQException.class)
+ public void constructor_nullConnectionEventHandler() throws XQException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+
+ new XQRemoteConnection(httpClient, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, Constants.DEFAULT_USERNAME, Constants.DEFAULT_PASSWORD, null);
+ }
+
+ @Test
+ public void constructor_ServerAvailable() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ assertFalse(con.isClosed());
+
+ //TODO check properties were set
+ }
+
+ @Test(expected=XQException.class)
+ public void constructor_ServerUnavailable() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final HttpResponse httpResponse = mockery.mock(HttpResponse.class);
+ final StatusLine statusLine = mockery.mock(StatusLine.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+
+ mockery.checking(new Expectations(){{
+ one(httpClient).execute(with(any(HttpUriRequest.class))); will(returnValue(httpResponse));
+ exactly(3).of(httpResponse).getStatusLine(); will(returnValue(statusLine));
+ exactly(2).of(statusLine).getStatusCode(); will(returnValue(HttpStatus.SC_BAD_REQUEST));
+ one(statusLine).getReasonPhrase(); will(returnValue("Bad Request"));
+ }});
+
+ new XQRemoteConnection(httpClient, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, Constants.DEFAULT_USERNAME, Constants.DEFAULT_PASSWORD, handler);
+ }
+
+ private XQRemoteConnection getConstructor_mockAvailableServer(Mockery mockery, HttpClient httpClient, XQConnectionEventHandler handler) throws IOException, XQException
+ {
+ final HttpClient fHttpClient = httpClient;
+ final HttpResponse httpResponse = mockery.mock(HttpResponse.class);
+ final StatusLine statusLine = mockery.mock(StatusLine.class);
+
+ mockery.checking(new Expectations(){{
+ one(fHttpClient).execute(with(aNonNull(HttpUriRequest.class))); will(returnValue(httpResponse));
+ one(httpResponse).getStatusLine(); will(returnValue(statusLine));
+ one(statusLine).getStatusCode(); will(returnValue(HttpStatus.SC_OK));
+ }});
+
+ return new XQRemoteConnection(httpClient, Constants.DEFAULT_SERVER_NAME, Constants.DEFAULT_SERVER_PORT, Constants.DEFAULT_COLLECTION_PATH, Constants.DEFAULT_USERNAME, Constants.DEFAULT_PASSWORD, handler);
+ }
+
+ @Test
+ public void close() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ prepareMockCloseConnection(mockery, handler, con);
+
+ assertFalse(con.isClosed());
+
+ con.close();
+
+ assertTrue(con.isClosed());
+ }
+
+ @Test
+ public void getAndsetAutoCommit_true() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ assertTrue(con.getAutoCommit()); //spec requires true for default
+
+ con.setAutoCommit(true);
+
+ assertTrue(con.getAutoCommit());
+ }
+
+ @Test
+ public void getAndsetAutoCommit_false() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ assertTrue(con.getAutoCommit());
+
+ boolean caughtException = false;
+ try
+ {
+ con.setAutoCommit(false);
+ }
+ catch(XQException xqe)
+ {
+ caughtException = true;
+ }
+ assertTrue(caughtException);
+
+ assertTrue(con.getAutoCommit());
+ }
+
+ @Test(expected=XQException.class)
+ public void setAutoCommit_when_ConnectionClosed() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ assertTrue(con.getAutoCommit());
+
+ prepareMockCloseConnection(mockery, handler, con);
+
+ assertFalse(con.isClosed());
+
+ con.close();
+
+ assertTrue(con.isClosed());
+
+ con.setAutoCommit(true);
+ }
+
+ @Test(expected=XQException.class)
+ public void getAutoCommit_when_ConnectionClosed() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ assertTrue(con.getAutoCommit());
+
+ prepareMockCloseConnection(mockery, handler, con);
+
+ assertFalse(con.isClosed());
+
+ con.close();
+
+ assertTrue(con.isClosed());
+
+ con.getAutoCommit();
+ }
+
+ @Test(expected=XQException.class)
+ public void commit() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ con.commit();
+ }
+
+ @Test(expected=XQException.class)
+ public void commit_when_ConnectionClosed() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ prepareMockCloseConnection(mockery, handler, con);
+
+ assertFalse(con.isClosed());
+
+ con.close();
+
+ assertTrue(con.isClosed());
+
+ con.commit();
+ }
+
+ @Test
+ public void createExpression() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ XQExpression expr = con.createExpression();
+ assertNotNull(expr);
+ }
+
+ @Test(expected=XQException.class)
+ public void createExpression_when_ConnectionClosed() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ prepareMockCloseConnection(mockery, handler, con);
+
+ assertFalse(con.isClosed());
+
+ con.close();
+
+ assertTrue(con.isClosed());
+
+ con.createExpression();
+
+ //TODO: test that the static context of the XQRemoteConnection is copied to the XQRemoteExpression
+ }
+
+ @Test
+ public void createExpressionWithStaticContext() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ final XQStaticContext staticContext = mockery.mock(XQStaticContext.class);
+
+ XQExpression expr = con.createExpression(staticContext);
+
+ assertNotNull(expr);
+
+ //TODO: test that staticContext is copied to the XQRemoteExpression
+ }
+
+ @Test(expected=XQException.class)
+ public void createExpressionWithStaticContext_null() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ XQExpression expr = con.createExpression(null);
+ }
+
+ @Test(expected=XQException.class)
+ public void createExpressionWithStaticContext_with_ConnectionClosed() throws XQException, IOException
+ {
+ Mockery mockery = new Mockery();
+ final HttpClient httpClient = mockery.mock(HttpClient.class);
+ final XQConnectionEventHandler handler = mockery.mock(XQConnectionEventHandler.class);
+ final XQRemoteConnection con = getConstructor_mockAvailableServer(mockery, httpClient, handler);
+
+ final XQStaticContext staticContext = mockery.mock(XQStaticContext.class);
+
+ prepareMockCloseConnection(mockery, handler, con);
+
+ assertFalse(con.isClosed());
+
+ con.close();
+
+ assertTrue(con.isClosed());
+
+ con.createExpression(staticContext);
+ }
+
+ /**
+ * Mocks a closed connection
+ * makes ready for calling close()
+ */
+ private void prepareMockCloseConnection(Mockery mockery, final XQConnectionEventHandler handler, final XQRemoteConnection con) throws XQException
+ {
+ mockery.checking(new Expectations(){{
+ one(handler).closeConnection(con); will(closeConnectionAction(handler)); //closeConnectionAction will ensure that the connection is closed
+ }});
+ }
+
+ private static Action closeConnectionAction(XQConnectionEventHandler handler)
+ {
+ return new CloseConnectionAction(handler);
+ }
+
+ private static class CloseConnectionAction implements Action
+ {
+ private XQConnectionEventHandler handler = null;
+
+ public CloseConnectionAction(XQConnectionEventHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public void describeTo(Description description)
+ {
+ description.appendText("calls closeConnection on an XQConnectionEventHandler");
+ }
+
+ public Object invoke(Invocation invocation) throws Throwable
+ {
+ ((XQConnectionEventHandler)invocation.getParameter(0)).closeConnection(handler);
+ return null;
+ }
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <wol...@us...> - 2008-12-29 19:13:55
|
Revision: 8433
http://exist.svn.sourceforge.net/exist/?rev=8433&view=rev
Author: wolfgang_m
Date: 2008-12-29 19:13:52 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
[ignore] fix broken build.
Modified Paths:
--------------
trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
Modified: trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java 2008-12-29 19:05:25 UTC (rev 8432)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java 2008-12-29 19:13:52 UTC (rev 8433)
@@ -102,7 +102,7 @@
return simplified;
}
- protected String diff2XML(List changes, Properties properties) throws IOException {
+ protected String diff2XML(List changes, Properties properties) throws DiffException {
changes = simplify(changes);
try {
StringWriter writer = new StringWriter();
@@ -123,7 +123,7 @@
sax.endDocument();
return writer.toString();
} catch (SAXException e) {
- throw new IOException("error while serializing diff: " + e.getMessage(), e);
+ throw new DiffException("error while serializing diff: " + e.getMessage(), e);
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <wol...@us...> - 2008-12-29 19:05:33
|
Revision: 8432
http://exist.svn.sourceforge.net/exist/?rev=8432&view=rev
Author: wolfgang_m
Date: 2008-12-29 19:05:25 +0000 (Mon, 29 Dec 2008)
Log Message:
-----------
[feature] new versioning extension: automatically saves a diff for all document updates and keeps track of revisions. Patch utility can restore arbitrary revisions of a given document. This is work in progress, some features are not implemented or properly tested. In particular, removing documents or collections is not correctly handled yet.
Modified Paths:
--------------
trunk/eXist/build/scripts/build-impl.xml
trunk/eXist/extensions/modules/build.xml
trunk/eXist/src/org/exist/dom/DocumentMetadata.java
trunk/eXist/src/org/exist/stax/EmbeddedXMLStreamReader.java
trunk/eXist/src/org/exist/storage/DBBroker.java
trunk/eXist/src/org/exist/storage/NativeBroker.java
Added Paths:
-----------
trunk/eXist/extensions/build.properties
trunk/eXist/extensions/versioning/
trunk/eXist/extensions/versioning/build.xml
trunk/eXist/extensions/versioning/src/
trunk/eXist/extensions/versioning/src/bmsi/
trunk/eXist/extensions/versioning/src/bmsi/util/
trunk/eXist/extensions/versioning/src/bmsi/util/Diff.java
trunk/eXist/extensions/versioning/src/org/
trunk/eXist/extensions/versioning/src/org/exist/
trunk/eXist/extensions/versioning/src/org/exist/versioning/
trunk/eXist/extensions/versioning/src/org/exist/versioning/DiffException.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningHelper.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningTrigger.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/XMLDiff.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/
trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/PatchFunction.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/VersioningModule.java
trunk/eXist/extensions/versioning/src/org/exist/versioning/xquery/versioning.xqm
trunk/eXist/extensions/versioning/test/
trunk/eXist/extensions/versioning/test/test.xml
trunk/eXist/extensions/versioning/test/test.xq
trunk/eXist/src/org/exist/memtree/InMemoryXMLStreamReader.java
Removed Paths:
-------------
trunk/eXist/extensions/modules/build.properties
Modified: trunk/eXist/build/scripts/build-impl.xml
===================================================================
--- trunk/eXist/build/scripts/build-impl.xml 2008-12-29 18:58:54 UTC (rev 8431)
+++ trunk/eXist/build/scripts/build-impl.xml 2008-12-29 19:05:25 UTC (rev 8432)
@@ -365,7 +365,7 @@
<!-- Build all -->
<!-- ================================================================== -->
<target name="all"
- depends="jar,wrapper,extension-modules,extension-indexes,extension-fluent,test-compile"
+ depends="jar,wrapper,extension-modules,extension-indexes,extension-versioning,extension-fluent,test-compile"
description="Build all">
<antcall target="sign"/>
</target>
@@ -488,6 +488,7 @@
<ant antfile="build.xml" dir="extensions/modules" target="clean"/>
<ant antfile="build.xml" dir="extensions/indexes" target="clean"/>
<ant antfile="build.xml" dir="extensions/fluent" target="clean"/>
+ <ant antfile="build.xml" dir="extensions/versioning" target="clean"/>
<antcall target="extensions-xslt"/>
</target>
@@ -533,6 +534,10 @@
<ant antfile="build.xml" dir="extensions/indexes" inheritall="false"/>
</target>
+ <target name="extension-versioning" depends="prepare-extensions,jar">
+ <ant antfile="build.xml" dir="extensions/versioning" inheritall="false"/>
+ </target>
+
<target name="extension-fluent" depends="jar">
<ant antfile="build.xml" dir="extensions/fluent" inheritall="false"/>
</target>
Added: trunk/eXist/extensions/build.properties
===================================================================
--- trunk/eXist/extensions/build.properties (rev 0)
+++ trunk/eXist/extensions/build.properties 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,42 @@
+###########################################################
+# This file specifies which extension features and XQuery modules should be compiled.
+# To include a feature or module, set its property to 'true'.
+#
+# Don't directly modify this file. Instead, copy it to local.build.properties and
+# edit that.
+#
+# $Id: build.properties 8362 2008-12-04 01:28:36Z chaeron $
+##########################################################
+
+#Versioning extensions for eXist
+include.feature.versioning = true
+
+# XSL FO transformations (Uses Apache FOP)
+include.module.xslfo = false
+
+## URLs to use to get Apache FOP and Avalon jar dependencies
+
+include.module.xslfo.url = http://apache.cs.uu.nl/dist/xmlgraphics/fop/binaries/fop-0.95-bin.zip
+include.module.xslfo.avalon.api.url = http://www.apache.org/dist/excalibur/excalibur-framework/binaries/avalon-framework-api-4.3.zip
+include.module.xslfo.avalon.impl.url = http://www.apache.org/dist/excalibur/excalibur-framework/binaries/avalon-framework-impl-4.3.zip
+
+# HTTP client module
+include.module.httpclient = true
+
+# Utility module to compare XML fragments; based on xmlunit
+include.module.xmldiff = true
+
+# Generate thumbnails etc.
+include.module.image = true
+
+# Send emails from XQuery
+include.module.mail = true
+
+# Example: implements a simple query language which is translated into XQuery
+include.module.simpleql = false
+
+# Provides functions to query a subversion repository
+include.module.svn = false'
+
+# Provides functions to query a JNDI Directory
+include.module.jndi = false
Deleted: trunk/eXist/extensions/modules/build.properties
===================================================================
--- trunk/eXist/extensions/modules/build.properties 2008-12-29 18:58:54 UTC (rev 8431)
+++ trunk/eXist/extensions/modules/build.properties 2008-12-29 19:05:25 UTC (rev 8432)
@@ -1,39 +0,0 @@
-###########################################################
-# This file specifies which XQuery extension modules should be compiled and
-# added to exist-modules.jar. To include a module, set its property to 'true'
-#
-# Don't directly modify this file. Instead, copy it to local.build.properties and
-# edit that.
-#
-# $Id$
-##########################################################
-
-# XSL FO transformations (Uses Apache FOP)
-include.module.xslfo = false
-
-## URLs to use to get Apache FOP and Avalon jar dependencies
-
-include.module.xslfo.url = http://apache.cs.uu.nl/dist/xmlgraphics/fop/binaries/fop-0.95-bin.zip
-include.module.xslfo.avalon.api.url = http://www.apache.org/dist/excalibur/excalibur-framework/binaries/avalon-framework-api-4.3.zip
-include.module.xslfo.avalon.impl.url = http://www.apache.org/dist/excalibur/excalibur-framework/binaries/avalon-framework-impl-4.3.zip
-
-# HTTP client module
-include.module.httpclient = true
-
-# Utility module to compare XML fragments; based on xmlunit
-include.module.xmldiff = true
-
-# Generate thumbnails etc.
-include.module.image = true
-
-# Send emails from XQuery
-include.module.mail = true
-
-# Example: implements a simple query language which is translated into XQuery
-include.module.simpleql = false
-
-# Provides functions to query a subversion repository
-include.module.svn = false
-
-# Provides functions to query a JNDI Directory
-include.module.jndi = false
Modified: trunk/eXist/extensions/modules/build.xml
===================================================================
--- trunk/eXist/extensions/modules/build.xml 2008-12-29 18:58:54 UTC (rev 8431)
+++ trunk/eXist/extensions/modules/build.xml 2008-12-29 19:05:25 UTC (rev 8432)
@@ -8,8 +8,8 @@
<property file="${top.dir}/build.properties"/>
- <property file="local.build.properties"/>
- <property file="build.properties"/>
+ <property file="../local.build.properties"/>
+ <property file="../build.properties"/>
<condition property="include.module.simpleql.config">
<istrue value="${include.module.simpleql}"/>
Added: trunk/eXist/extensions/versioning/build.xml
===================================================================
--- trunk/eXist/extensions/versioning/build.xml (rev 0)
+++ trunk/eXist/extensions/versioning/build.xml 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,77 @@
+<project basedir="." default="jar" name="versioning">
+
+ <property name="src" value="./src"/>
+ <property name="classes" value="./classes"/>
+ <property name="top.dir" value="../.."/>
+
+ <property name="build.compiler" value="modern"/>
+
+ <property file="${top.dir}/build.properties"/>
+
+ <property file="../local.build.properties"/>
+ <property file="../build.properties"/>
+
+ <condition property="include.feature.versioning.config">
+ <istrue value="${include.feature.versioning}"/>
+ </condition>
+
+ <path id="classpath.core">
+ <fileset dir="${top.dir}/${lib.core}">
+ <include name="*.jar"/>
+ </fileset>
+ <fileset dir="${top.dir}/${lib.optional}">
+ <include name="*.jar"/>
+ </fileset>
+ <fileset dir="${top.dir}/${lib.endorsed}">
+ <include name="*.jar"/>
+ </fileset>
+ <fileset dir="${top.dir}/${lib.user}">
+ <include name="*.jar"/>
+ </fileset>
+ <fileset dir="${top.dir}/tools/ant/lib">
+ <include name="*.jar"/>
+ </fileset>
+ <pathelement path="${top.dir}/exist.jar"/>
+ <pathelement path="${top.dir}/exist-optional.jar"/>
+ <pathelement path="${top.dir}/start.jar"/>
+ <pathelement path="${java.class.path}"/>
+ </path>
+
+ <target name="prepare">
+ <mkdir dir="${classes}"/>
+ </target>
+
+ <target name="compile" depends="prepare" if="include.feature.versioning.config">
+ <echo message="----------------------------------"/>
+ <echo message="Compiling versioning extensions"/>
+ <echo message="----------------------------------"/>
+ <javac debug="${build.debug}" deprecation="${build.deprecation}"
+ destdir="${classes}" encoding="UTF-8"
+ optimize="${build.optimize}" srcdir="${src}"
+ source="1.5">
+ <!-- jmv target="1.4" -->
+ <classpath>
+ <path refid="classpath.core"/>
+ </classpath>
+ </javac>
+ <copy todir="${classes}/org/exist/versioning/xquery"
+ file="${src}/org/exist/versioning/xquery/versioning.xqm"/>
+ </target>
+
+ <target name="jar" depends="compile" if="include.feature.versioning.config">
+ <echo message="Creating exist-versioning.jar ..."/>
+ <jar basedir="${classes}" jarfile="${top.dir}/${lib.extensions}/exist-versioning.jar">
+ <manifest>
+ <attribute name="Project-Name" value="${project.name}"/>
+ <attribute name="Project-Version" value="${project.version}"/>
+ <attribute name="Project-Build" value="${DSTAMP}"/>
+ <attribute name="SVN-Revision" value="${svn.revision}"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="clean" if="include.feature.versioning.config">
+ <delete dir="${classes}"/>
+ <delete file="${top.dir}/${lib.extensions}/exist-versioning.jar" failonerror="false"/>
+ </target>
+</project>
Added: trunk/eXist/extensions/versioning/src/bmsi/util/Diff.java
===================================================================
--- trunk/eXist/extensions/versioning/src/bmsi/util/Diff.java (rev 0)
+++ trunk/eXist/extensions/versioning/src/bmsi/util/Diff.java 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,890 @@
+/*
+ * $Log: Diff.java,v $
+ * Revision 1.6 2003/03/06 22:51:32 stuart
+ * Convert to CVS
+ *
+ * Revision 1.5 2002/07/19 19:14:40 stuart
+ * fix reverseScript, make change ctor public, update docs
+ *
+ * Revision 1.4 2002/04/09 17:53:39 stuart
+ * More flexible interface for diff() function.
+ *
+ * Revision 1.3 2000/03/03 21:58:03 stuart
+ * move discard_confusing_lines and shift_boundaries to class file_data
+ *
+ * Revision 1.2 2000/03/02 16:37:38 stuart
+ * Add GPL and copyright
+ *
+ */
+package bmsi.util;
+
+import java.util.Hashtable;
+
+/** A class to compare vectors of objects. The result of comparison
+ is a list of <code>change</code> objects which form an
+ edit script. The objects compared are traditionally lines
+ of text from two files. Comparison options such as "ignore
+ whitespace" are implemented by modifying the <code>equals</code>
+ and <code>hashcode</code> methods for the objects compared.
+<p>
+ The basic algorithm is described in: </br>
+ "An O(ND) Difference Algorithm and its Variations", Eugene Myers,
+ Algorithmica Vol. 1 No. 2, 1986, p 251.
+<p>
+ This class outputs different results from GNU diff 1.15 on some
+ inputs. Our results are actually better (smaller change list, smaller
+ total size of changes), but it would be nice to know why. Perhaps
+ there is a memory overwrite bug in GNU diff 1.15.
+
+ @author Stuart D. Gathman, translated from GNU diff 1.15
+ Copyright (C) 2000 Business Management Systems, Inc.
+<p>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+<p>
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+<p>
+ You should have received a copy of the <a href=COPYING.txt>
+ GNU General Public License</a>
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+public class Diff {
+
+ /** Prepare to find differences between two arrays. Each element of
+ the arrays is translated to an "equivalence number" based on
+ the result of <code>equals</code>. The original Object arrays
+ are no longer needed for computing the differences. They will
+ be needed again later to print the results of the comparison as
+ an edit script, if desired.
+ */
+ public Diff(Object[] a,Object[] b) {
+ Hashtable h = new Hashtable(a.length + b.length);
+ filevec[0] = new file_data(a,h);
+ filevec[1] = new file_data(b,h);
+ }
+
+ /** 1 more than the maximum equivalence value used for this or its
+ sibling file. */
+ private int equiv_max = 1;
+
+ /** When set to true, the comparison uses a heuristic to speed it up.
+ With this heuristic, for files with a constant small density
+ of changes, the algorithm is linear in the file size. */
+ public boolean heuristic = false;
+
+ /** When set to true, the algorithm returns a guarranteed minimal
+ set of changes. This makes things slower, sometimes much slower. */
+ public boolean no_discards = false;
+
+ private int[] xvec, yvec; /* Vectors being compared. */
+ private int[] fdiag; /* Vector, indexed by diagonal, containing
+ the X coordinate of the point furthest
+ along the given diagonal in the forward
+ search of the edit matrix. */
+ private int[] bdiag; /* Vector, indexed by diagonal, containing
+ the X coordinate of the point furthest
+ along the given diagonal in the backward
+ search of the edit matrix. */
+ private int fdiagoff, bdiagoff;
+ private final file_data[] filevec = new file_data[2];
+ private int cost;
+
+ /** Find the midpoint of the shortest edit script for a specified
+ portion of the two files.
+
+ We scan from the beginnings of the files, and simultaneously from the ends,
+ doing a breadth-first search through the space of edit-sequence.
+ When the two searches meet, we have found the midpoint of the shortest
+ edit sequence.
+
+ The value returned is the number of the diagonal on which the midpoint lies.
+ The diagonal number equals the number of inserted lines minus the number
+ of deleted lines (counting only lines before the midpoint).
+ The edit cost is stored into COST; this is the total number of
+ lines inserted or deleted (counting only lines before the midpoint).
+
+ This function assumes that the first lines of the specified portions
+ of the two files do not match, and likewise that the last lines do not
+ match. The caller must trim matching lines from the beginning and end
+ of the portions it is going to specify.
+
+ Note that if we return the "wrong" diagonal value, or if
+ the value of bdiag at that diagonal is "wrong",
+ the worst this can do is cause suboptimal diff output.
+ It cannot cause incorrect diff output. */
+
+ private int diag (int xoff, int xlim, int yoff, int ylim) {
+ final int[] fd = fdiag; // Give the compiler a chance.
+ final int[] bd = bdiag; // Additional help for the compiler.
+ final int[] xv = xvec; // Still more help for the compiler.
+ final int[] yv = yvec; // And more and more . . .
+ final int dmin = xoff - ylim; // Minimum valid diagonal.
+ final int dmax = xlim - yoff; // Maximum valid diagonal.
+ final int fmid = xoff - yoff; // Center diagonal of top-down search.
+ final int bmid = xlim - ylim; // Center diagonal of bottom-up search.
+ int fmin = fmid, fmax = fmid; // Limits of top-down search.
+ int bmin = bmid, bmax = bmid; // Limits of bottom-up search.
+ /* True if southeast corner is on an odd
+ diagonal with respect to the northwest. */
+ final boolean odd = (fmid - bmid & 1) != 0;
+
+ fd[fdiagoff + fmid] = xoff;
+ bd[bdiagoff + bmid] = xlim;
+
+ for (int c = 1;; ++c)
+ {
+ int d; /* Active diagonal. */
+ boolean big_snake = false;
+
+ /* Extend the top-down search by an edit step in each diagonal. */
+ if (fmin > dmin)
+ fd[fdiagoff + --fmin - 1] = -1;
+ else
+ ++fmin;
+ if (fmax < dmax)
+ fd[fdiagoff + ++fmax + 1] = -1;
+ else
+ --fmax;
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int x, y, oldx, tlo = fd[fdiagoff + d - 1], thi = fd[fdiagoff + d + 1];
+
+ if (tlo >= thi)
+ x = tlo + 1;
+ else
+ x = thi;
+ oldx = x;
+ y = x - d;
+ while (x < xlim && y < ylim && xv[x] == yv[y]) {
+ ++x; ++y;
+ }
+ if (x - oldx > 20)
+ big_snake = true;
+ fd[fdiagoff + d] = x;
+ if (odd && bmin <= d && d <= bmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
+ {
+ cost = 2 * c - 1;
+ return d;
+ }
+ }
+
+ /* Similar extend the bottom-up search. */
+ if (bmin > dmin)
+ bd[bdiagoff + --bmin - 1] = Integer.MAX_VALUE;
+ else
+ ++bmin;
+ if (bmax < dmax)
+ bd[bdiagoff + ++bmax + 1] = Integer.MAX_VALUE;
+ else
+ --bmax;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int x, y, oldx, tlo = bd[bdiagoff + d - 1], thi = bd[bdiagoff + d + 1];
+
+ if (tlo < thi)
+ x = tlo;
+ else
+ x = thi - 1;
+ oldx = x;
+ y = x - d;
+ while (x > xoff && y > yoff && xv[x - 1] == yv[y - 1]) {
+ --x; --y;
+ }
+ if (oldx - x > 20)
+ big_snake = true;
+ bd[bdiagoff + d] = x;
+ if (!odd && fmin <= d && d <= fmax && bd[bdiagoff + d] <= fd[fdiagoff + d])
+ {
+ cost = 2 * c;
+ return d;
+ }
+ }
+
+ /* Heuristic: check occasionally for a diagonal that has made
+ lots of progress compared with the edit distance.
+ If we have any such, find the one that has made the most
+ progress and return it as if it had succeeded.
+
+ With this heuristic, for files with a constant small density
+ of changes, the algorithm is linear in the file size. */
+
+ if (c > 200 && big_snake && heuristic)
+ {
+ int best = 0;
+ int bestpos = -1;
+
+ for (d = fmax; d >= fmin; d -= 2)
+ {
+ int dd = d - fmid;
+ if ((fd[fdiagoff + d] - xoff)*2 - dd > 12 * (c + (dd > 0 ? dd : -dd)))
+ {
+ if (fd[fdiagoff + d] * 2 - dd > best
+ && fd[fdiagoff + d] - xoff > 20
+ && fd[fdiagoff + d] - d - yoff > 20)
+ {
+ int k;
+ int x = fd[fdiagoff + d];
+
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ for (k = 1; k <= 20; k++)
+ if (xvec[x - k] != yvec[x - d - k])
+ break;
+
+ if (k == 21)
+ {
+ best = fd[fdiagoff + d] * 2 - dd;
+ bestpos = d;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ cost = 2 * c - 1;
+ return bestpos;
+ }
+
+ best = 0;
+ for (d = bmax; d >= bmin; d -= 2)
+ {
+ int dd = d - bmid;
+ if ((xlim - bd[bdiagoff + d])*2 + dd > 12 * (c + (dd > 0 ? dd : -dd)))
+ {
+ if ((xlim - bd[bdiagoff + d]) * 2 + dd > best
+ && xlim - bd[bdiagoff + d] > 20
+ && ylim - (bd[bdiagoff + d] - d) > 20)
+ {
+ /* We have a good enough best diagonal;
+ now insist that it end with a significant snake. */
+ int k;
+ int x = bd[bdiagoff + d];
+
+ for (k = 0; k < 20; k++)
+ if (xvec[x + k] != yvec[x - d + k])
+ break;
+ if (k == 20)
+ {
+ best = (xlim - bd[bdiagoff + d]) * 2 + dd;
+ bestpos = d;
+ }
+ }
+ }
+ }
+ if (best > 0)
+ {
+ cost = 2 * c - 1;
+ return bestpos;
+ }
+ }
+ }
+ }
+
+ /** Compare in detail contiguous subsequences of the two files
+ which are known, as a whole, to match each other.
+
+ The results are recorded in the vectors filevec[N].changed_flag, by
+ storing a 1 in the element for each line that is an insertion or deletion.
+
+ The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
+
+ Note that XLIM, YLIM are exclusive bounds.
+ All line numbers are origin-0 and discarded lines are not counted. */
+
+ private void compareseq (int xoff, int xlim, int yoff, int ylim) {
+ /* Slide down the bottom initial diagonal. */
+ while (xoff < xlim && yoff < ylim && xvec[xoff] == yvec[yoff]) {
+ ++xoff; ++yoff;
+ }
+ /* Slide up the top initial diagonal. */
+ while (xlim > xoff && ylim > yoff && xvec[xlim - 1] == yvec[ylim - 1]) {
+ --xlim; --ylim;
+ }
+
+ /* Handle simple cases. */
+ if (xoff == xlim)
+ while (yoff < ylim)
+ filevec[1].changed_flag[1+filevec[1].realindexes[yoff++]] = true;
+ else if (yoff == ylim)
+ while (xoff < xlim)
+ filevec[0].changed_flag[1+filevec[0].realindexes[xoff++]] = true;
+ else
+ {
+ /* Find a point of correspondence in the middle of the files. */
+
+ int d = diag (xoff, xlim, yoff, ylim);
+ int c = cost;
+ int f = fdiag[fdiagoff + d];
+ int b = bdiag[bdiagoff + d];
+
+ if (c == 1)
+ {
+ /* This should be impossible, because it implies that
+ one of the two subsequences is empty,
+ and that case was handled above without calling `diag'.
+ Let's verify that this is true. */
+ throw new IllegalArgumentException("Empty subsequence");
+ }
+ else
+ {
+ /* Use that point to split this problem into two subproblems. */
+ compareseq (xoff, b, yoff, b - d);
+ /* This used to use f instead of b,
+ but that is incorrect!
+ It is not necessarily the case that diagonal d
+ has a snake from b to f. */
+ compareseq (b, xlim, b - d, ylim);
+ }
+ }
+ }
+
+ /** Discard lines from one file that have no matches in the other file.
+ */
+
+ private void discard_confusing_lines() {
+ filevec[0].discard_confusing_lines(filevec[1]);
+ filevec[1].discard_confusing_lines(filevec[0]);
+ }
+
+ private boolean inhibit = false;
+
+ /** Adjust inserts/deletes of blank lines to join changes
+ as much as possible.
+ */
+
+ private void shift_boundaries() {
+ if (inhibit)
+ return;
+ filevec[0].shift_boundaries(filevec[1]);
+ filevec[1].shift_boundaries(filevec[0]);
+ }
+
+ public interface ScriptBuilder {
+ /** Scan the tables of which lines are inserted and deleted,
+ producing an edit script.
+ @param changed0 true for lines in first file which do not match 2nd
+ @param len0 number of lines in first file
+ @param changed1 true for lines in 2nd file which do not match 1st
+ @param len1 number of lines in 2nd file
+ @return a linked list of changes - or null
+ */
+ public change build_script(
+ boolean[] changed0,int len0,
+ boolean[] changed1,int len1
+ );
+ }
+
+ /** Scan the tables of which lines are inserted and deleted,
+ producing an edit script in reverse order. */
+
+ static class ReverseScript implements ScriptBuilder {
+ public change build_script(
+ final boolean[] changed0,int len0,
+ final boolean[] changed1,int len1)
+ {
+ change script = null;
+ int i0 = 0, i1 = 0;
+ while (i0 < len0 || i1 < len1) {
+ if (changed0[1+i0] || changed1[1+i1]) {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[1+i0]) ++i0;
+ while (changed1[1+i1]) ++i1;
+
+ /* Record this change. */
+ script = new change(line0, line1, i0 - line0, i1 - line1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0++; i1++;
+ }
+
+ return script;
+ }
+ }
+
+ static class ForwardScript implements ScriptBuilder {
+ /** Scan the tables of which lines are inserted and deleted,
+ producing an edit script in forward order. */
+ public change build_script(
+ final boolean[] changed0,int len0,
+ final boolean[] changed1,int len1)
+ {
+ change script = null;
+ int i0 = len0, i1 = len1;
+
+ while (i0 >= 0 || i1 >= 0)
+ {
+ if (changed0[i0] || changed1[i1])
+ {
+ int line0 = i0, line1 = i1;
+
+ /* Find # lines changed here in each file. */
+ while (changed0[i0]) --i0;
+ while (changed1[i1]) --i1;
+
+ /* Record this change. */
+ script = new change(i0, i1, line0 - i0, line1 - i1, script);
+ }
+
+ /* We have reached lines in the two files that match each other. */
+ i0--; i1--;
+ }
+
+ return script;
+ }
+ }
+
+ /** Standard ScriptBuilders. */
+ public final static ScriptBuilder
+ forwardScript = new ForwardScript(),
+ reverseScript = new ReverseScript();
+
+ /* Report the differences of two files. DEPTH is the current directory
+ depth. */
+ public final change diff_2(final boolean reverse) {
+ return diff(reverse ? reverseScript : forwardScript);
+ }
+
+ /** Get the results of comparison as an edit script. The script
+ is described by a list of changes. The standard ScriptBuilder
+ implementations provide for forward and reverse edit scripts.
+ Alternate implementations could, for instance, list common elements
+ instead of differences.
+ @param bld an object to build the script from change flags
+ @return the head of a list of changes
+ */
+ public change diff(final ScriptBuilder bld) {
+
+ /* Some lines are obviously insertions or deletions
+ because they don't match anything. Detect them now,
+ and avoid even thinking about them in the main comparison algorithm. */
+
+ discard_confusing_lines ();
+
+ /* Now do the main comparison algorithm, considering just the
+ undiscarded lines. */
+
+ xvec = filevec[0].undiscarded;
+ yvec = filevec[1].undiscarded;
+
+ int diags =
+ filevec[0].nondiscarded_lines + filevec[1].nondiscarded_lines + 3;
+ fdiag = new int[diags];
+ fdiagoff = filevec[1].nondiscarded_lines + 1;
+ bdiag = new int[diags];
+ bdiagoff = filevec[1].nondiscarded_lines + 1;
+
+ compareseq (0, filevec[0].nondiscarded_lines,
+ 0, filevec[1].nondiscarded_lines);
+ fdiag = null;
+ bdiag = null;
+
+ /* Modify the results slightly to make them prettier
+ in cases where that can validly be done. */
+
+ shift_boundaries ();
+
+ /* Get the results of comparison in the form of a chain
+ of `struct change's -- an edit script. */
+ return bld.build_script(
+ filevec[0].changed_flag,
+ filevec[0].buffered_lines,
+ filevec[1].changed_flag,
+ filevec[1].buffered_lines
+ );
+
+ }
+
+ /** The result of comparison is an "edit script": a chain of change objects.
+ Each change represents one place where some lines are deleted
+ and some are inserted.
+
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+
+ public static class change {
+ /** Previous or next edit command. */
+ public change link;
+ /** # lines of file 1 changed here. */
+ public final int inserted;
+ /** # lines of file 0 changed here. */
+ public final int deleted;
+ /** Line number of 1st deleted line. */
+ public final int line0;
+ /** Line number of 1st inserted line. */
+ public final int line1;
+
+ /** Cons an additional entry onto the front of an edit script OLD.
+ LINE0 and LINE1 are the first affected lines in the two files (origin 0).
+ DELETED is the number of lines deleted here from file 0.
+ INSERTED is the number of lines inserted here in file 1.
+
+ If DELETED is 0 then LINE0 is the number of the line before
+ which the insertion was done; vice versa for INSERTED and LINE1. */
+ public change(int line0, int line1, int deleted, int inserted, change old) {
+ this.line0 = line0;
+ this.line1 = line1;
+ this.inserted = inserted;
+ this.deleted = deleted;
+ this.link = old;
+ //System.err.println(line0+","+line1+","+inserted+","+deleted);
+ }
+ }
+
+ /** Data on one input file being compared.
+ */
+
+ class file_data {
+
+ /** Allocate changed array for the results of comparison. */
+ void clear() {
+ /* Allocate a flag for each line of each file, saying whether that line
+ is an insertion or deletion.
+ Allocate an extra element, always zero, at each end of each vector.
+ */
+ changed_flag = new boolean[buffered_lines + 2];
+ }
+
+ /** Return equiv_count[I] as the number of lines in this file
+ that fall in equivalence class I.
+ @return the array of equivalence class counts.
+ */
+ int[] equivCount() {
+ int[] equiv_count = new int[equiv_max];
+ for (int i = 0; i < buffered_lines; ++i)
+ ++equiv_count[equivs[i]];
+ return equiv_count;
+ }
+
+ /** Discard lines that have no matches in another file.
+
+ A line which is discarded will not be considered by the actual
+ comparison algorithm; it will be as if that line were not in the file.
+ The file's `realindexes' table maps virtual line numbers
+ (which don't count the discarded lines) into real line numbers;
+ this is how the actual comparison algorithm produces results
+ that are comprehensible when the discarded lines are counted.
+<p>
+ When we discard a line, we also mark it as a deletion or insertion
+ so that it will be printed in the output.
+ @param f the other file
+ */
+ void discard_confusing_lines(file_data f) {
+ clear();
+ /* Set up table of which lines are going to be discarded. */
+ final byte[] discarded = discardable(f.equivCount());
+
+ /* Don't really discard the provisional lines except when they occur
+ in a run of discardables, with nonprovisionals at the beginning
+ and end. */
+ filterDiscards(discarded);
+
+ /* Actually discard the lines. */
+ discard(discarded);
+ }
+
+ /** Mark to be discarded each line that matches no line of another file.
+ If a line matches many lines, mark it as provisionally discardable.
+ @see equivCount()
+ @param counts The count of each equivalence number for the other file.
+ @return 0=nondiscardable, 1=discardable or 2=provisionally discardable
+ for each line
+ */
+
+ private byte[] discardable(final int[] counts) {
+ final int end = buffered_lines;
+ final byte[] discards = new byte[end];
+ final int[] equivs = this.equivs;
+ int many = 5;
+ int tem = end / 64;
+
+ /* Multiply MANY by approximate square root of number of lines.
+ That is the threshold for provisionally discardable lines. */
+ while ((tem = tem >> 2) > 0)
+ many *= 2;
+
+ for (int i = 0; i < end; i++)
+ {
+ int nmatch;
+ if (equivs[i] == 0)
+ continue;
+ nmatch = counts[equivs[i]];
+ if (nmatch == 0)
+ discards[i] = 1;
+ else if (nmatch > many)
+ discards[i] = 2;
+ }
+ return discards;
+ }
+
+ /** Don't really discard the provisional lines except when they occur
+ in a run of discardables, with nonprovisionals at the beginning
+ and end. */
+
+ private void filterDiscards(final byte[] discards) {
+ final int end = buffered_lines;
+
+ for (int i = 0; i < end; i++)
+ {
+ /* Cancel provisional discards not in middle of run of discards. */
+ if (discards[i] == 2)
+ discards[i] = 0;
+ else if (discards[i] != 0)
+ {
+ /* We have found a nonprovisional discard. */
+ int j;
+ int length;
+ int provisional = 0;
+
+ /* Find end of this run of discardable lines.
+ Count how many are provisionally discardable. */
+ for (j = i; j < end; j++)
+ {
+ if (discards[j] == 0)
+ break;
+ if (discards[j] == 2)
+ ++provisional;
+ }
+
+ /* Cancel provisional discards at end, and shrink the run. */
+ while (j > i && discards[j - 1] == 2) {
+ discards[--j] = 0; --provisional;
+ }
+
+ /* Now we have the length of a run of discardable lines
+ whose first and last are not provisional. */
+ length = j - i;
+
+ /* If 1/4 of the lines in the run are provisional,
+ cancel discarding of all provisional lines in the run. */
+ if (provisional * 4 > length)
+ {
+ while (j > i)
+ if (discards[--j] == 2)
+ discards[j] = 0;
+ }
+ else
+ {
+ int consec;
+ int minimum = 1;
+ int tem = length / 4;
+
+ /* MINIMUM is approximate square root of LENGTH/4.
+ A subrun of two or more provisionals can stand
+ when LENGTH is at least 16.
+ A subrun of 4 or more can stand when LENGTH >= 64. */
+ while ((tem = tem >> 2) > 0)
+ minimum *= 2;
+ minimum++;
+
+ /* Cancel any subrun of MINIMUM or more provisionals
+ within the larger run. */
+ for (j = 0, consec = 0; j < length; j++)
+ if (discards[i + j] != 2)
+ consec = 0;
+ else if (minimum == ++consec)
+ /* Back up to start of subrun, to cancel it all. */
+ j -= consec;
+ else if (minimum < consec)
+ discards[i + j] = 0;
+
+ /* Scan from beginning of run
+ until we find 3 or more nonprovisionals in a row
+ or until the first nonprovisional at least 8 lines in.
+ Until that point, cancel any provisionals. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i + j] == 1)
+ break;
+ if (discards[i + j] == 2) {
+ consec = 0; discards[i + j] = 0;
+ }
+ else if (discards[i + j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+
+ /* I advances to the last line of the run. */
+ i += length - 1;
+
+ /* Same thing, from end. */
+ for (j = 0, consec = 0; j < length; j++)
+ {
+ if (j >= 8 && discards[i - j] == 1)
+ break;
+ if (discards[i - j] == 2) {
+ consec = 0; discards[i - j] = 0;
+ }
+ else if (discards[i - j] == 0)
+ consec = 0;
+ else
+ consec++;
+ if (consec == 3)
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /** Actually discard the lines.
+ @param discards flags lines to be discarded
+ */
+ private void discard(final byte[] discards) {
+ final int end = buffered_lines;
+ int j = 0;
+ for (int i = 0; i < end; ++i)
+ if (no_discards || discards[i] == 0)
+ {
+ undiscarded[j] = equivs[i];
+ realindexes[j++] = i;
+ }
+ else
+ changed_flag[1+i] = true;
+ nondiscarded_lines = j;
+ }
+
+ file_data(Object[] data,Hashtable h) {
+ buffered_lines = data.length;
+
+ equivs = new int[buffered_lines];
+ undiscarded = new int[buffered_lines];
+ realindexes = new int[buffered_lines];
+
+ for (int i = 0; i < data.length; ++i) {
+ Integer ir = (Integer)h.get(data[i]);
+ if (ir == null)
+ h.put(data[i],new Integer(equivs[i] = equiv_max++));
+ else
+ equivs[i] = ir.intValue();
+ }
+ }
+
+ /** Adjust inserts/deletes of blank lines to join changes
+ as much as possible.
+
+ We do something when a run of changed lines include a blank
+ line at one end and have an excluded blank line at the other.
+ We are free to choose which blank line is included.
+ `compareseq' always chooses the one at the beginning,
+ but usually it is cleaner to consider the following blank line
+ to be the "change". The only exception is if the preceding blank line
+ would join this change to other changes.
+ @param f the file being compared against
+ */
+
+ void shift_boundaries(file_data f) {
+ final boolean[] changed = changed_flag;
+ final boolean[] other_changed = f.changed_flag;
+ int i = 0;
+ int j = 0;
+ int i_end = buffered_lines;
+ int preceding = -1;
+ int other_preceding = -1;
+
+ for (;;)
+ {
+ int start, end, other_start;
+
+ /* Scan forwards to find beginning of another run of changes.
+ Also keep track of the corresponding point in the other file. */
+
+ while (i < i_end && !changed[1+i])
+ {
+ while (other_changed[1+j++])
+ /* Non-corresponding lines in the other file
+ will count as the preceding batch of changes. */
+ other_preceding = j;
+ i++;
+ }
+
+ if (i == i_end)
+ break;
+
+ start = i;
+ other_start = j;
+
+ for (;;)
+ {
+ /* Now find the end of this run of changes. */
+
+ while (i < i_end && changed[1+i]) i++;
+ end = i;
+
+ /* If the first changed line matches the following unchanged one,
+ and this run does not follow right after a previous run,
+ and there are no lines deleted from the other file here,
+ then classify the first changed line as unchanged
+ and the following line as changed in its place. */
+
+ /* You might ask, how could this run follow right after another?
+ Only because the previous run was shifted here. */
+
+ if (end != i_end
+ && equivs[start] == equivs[end]
+ && !other_changed[1+j]
+ && end != i_end
+ && !((preceding >= 0 && start == preceding)
+ || (other_preceding >= 0
+ && other_start == other_preceding)))
+ {
+ changed[1+end++] = true;
+ changed[1+start++] = false;
+ ++i;
+ /* Since one line-that-matches is now before this run
+ instead of after, we must advance in the other file
+ to keep in synch. */
+ ++j;
+ }
+ else
+ break;
+ }
+
+ preceding = i;
+ other_preceding = j;
+ }
+ }
+
+ /** Number of elements (lines) in this file. */
+ final int buffered_lines;
+
+ /** Vector, indexed by line number, containing an equivalence code for
+ each line. It is this vector that is actually compared with that
+ of another file to generate differences. */
+ private final int[] equivs;
+
+ /** Vector, like the previous one except that
+ the elements for discarded lines have been squeezed out. */
+ final int[] undiscarded;
+
+ /** Vector mapping virtual line numbers (not counting discarded lines)
+ to real ones (counting those lines). Both are origin-0. */
+ final int[] realindexes;
+
+ /** Total number of nondiscarded lines. */
+ int nondiscarded_lines;
+
+ /** Array, indexed by real origin-1 line number,
+ containing true for a line that is an insertion or a deletion.
+ The results of comparison are stored here. */
+ boolean[] changed_flag;
+
+ }
+}
Added: trunk/eXist/extensions/versioning/src/org/exist/versioning/DiffException.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/DiffException.java (rev 0)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/DiffException.java 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,33 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-07 The eXist Project
+ * http://exist-db.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id$
+ */
+package org.exist.versioning;
+
+public class DiffException extends Exception {
+
+ public DiffException(String message) {
+ super(message);
+ }
+
+ public DiffException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
Added: trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java (rev 0)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/Difference.java 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,122 @@
+package org.exist.versioning;
+
+import org.exist.dom.NewArrayNodeSet;
+import org.exist.dom.NodeProxy;
+import org.exist.dom.NodeSet;
+import org.exist.numbering.NodeId;
+import org.exist.storage.DBBroker;
+import org.exist.util.serializer.SAXSerializer;
+import org.exist.util.serializer.SerializerPool;
+import org.exist.xquery.XPathException;
+import org.exist.xquery.value.SequenceIterator;
+import org.exist.Namespaces;
+import org.xml.sax.SAXException;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributesImpl;
+
+import java.io.StringWriter;
+import java.util.Iterator;
+
+public abstract class Difference {
+
+ public final static int INSERT = 0;
+ public final static int DELETE = 1;
+ public final static int APPEND = 2;
+
+ protected int type;
+ protected NodeProxy refChild;
+
+ public Difference(int type, NodeProxy reference) {
+ this.type = type;
+ this.refChild = reference;
+ }
+
+ public abstract void serialize(DBBroker broker, ContentHandler handler);
+
+
+ public static class Insert extends Difference {
+
+ protected NodeSet nodes = new NewArrayNodeSet(1, 8);
+
+ public Insert(NodeProxy reference) {
+ super(INSERT, reference);
+ }
+
+ public Insert(int type, NodeProxy reference) {
+ super(type, reference);
+ }
+
+ protected void addNode(NodeProxy node) {
+ if (nodes.parentWithChild(node.getDocument(), node.getNodeId(), false, true) == null)
+ nodes.add(node);
+ }
+
+ protected void addNodes(NodeSet set) {
+ nodes.addAll(set);
+ }
+
+ protected void setNodes(NodeSet nodes) {
+ this.nodes = nodes;
+ }
+
+ public void serialize(DBBroker broker, ContentHandler handler) {
+ try {
+ AttributesImpl attribs = new AttributesImpl();
+ attribs.addAttribute("", "ref", "ref", "CDATA", refChild.getNodeId().toString());
+ handler.startElement(XMLDiff.NAMESPACE, "insert", XMLDiff.PREFIX + ":insert", attribs);
+ for (SequenceIterator i = nodes.iterate(); i.hasNext(); ) {
+ NodeProxy proxy = (NodeProxy) i.nextItem();
+ proxy.toSAX(broker, handler, null);
+ }
+ handler.endElement(XMLDiff.NAMESPACE, "insert", XMLDiff.PREFIX + ":insert");
+ } catch (XPathException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ } catch (SAXException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+ }
+
+ public final static class Append extends Insert {
+
+ public Append(NodeProxy reference) {
+ super(APPEND, reference);
+ }
+
+ public void serialize(DBBroker broker, ContentHandler handler) {
+ try {
+ AttributesImpl attribs = new AttributesImpl();
+ attribs.addAttribute("", "ref", "ref", "CDATA", refChild.getNodeId().toString());
+ handler.startElement(XMLDiff.NAMESPACE, "append", XMLDiff.PREFIX + ":append", attribs);
+ for (SequenceIterator i = nodes.iterate(); i.hasNext(); ) {
+ NodeProxy proxy = (NodeProxy) i.nextItem();
+ proxy.toSAX(broker, handler, null);
+ }
+ handler.endElement(XMLDiff.NAMESPACE, "append", XMLDiff.PREFIX + ":append");
+ } catch (XPathException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ } catch (SAXException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+ }
+
+ public final static class Delete extends Difference {
+
+ public Delete(NodeProxy reference) {
+ super(DELETE, reference);
+ }
+
+ public void serialize(DBBroker broker, ContentHandler handler) {
+ try {
+ AttributesImpl attribs = new AttributesImpl();
+ attribs.addAttribute("", "ref", "ref", "CDATA", refChild.getNodeId().toString());
+ handler.startElement(XMLDiff.NAMESPACE, "delete", XMLDiff.PREFIX + ":delete", attribs);
+ handler.endElement(XMLDiff.NAMESPACE, "delete", XMLDiff.PREFIX + ":delete");
+ } catch (SAXException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ }
+ }
+ }
+}
\ No newline at end of file
Added: trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java (rev 0)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/Patch.java 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,202 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-07 The eXist Project
+ * http://exist-db.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id$
+ */
+package org.exist.versioning;
+
+import org.exist.dom.AttrImpl;
+import org.exist.dom.DocumentImpl;
+import org.exist.dom.ElementImpl;
+import org.exist.dom.QName;
+import org.exist.dom.StoredNode;
+import org.exist.numbering.NodeId;
+import org.exist.stax.EmbeddedXMLStreamReader;
+import org.exist.storage.DBBroker;
+import org.exist.util.serializer.AttrList;
+import org.exist.util.serializer.Receiver;
+import org.exist.xquery.XPathException;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Patch a given source document by applying a diff in eXist's diff format.
+ */
+public class Patch {
+
+ private DBBroker broker;
+ private Set deletedNodes = null;
+ private Map insertedNodes = null;
+ private Map appendedNodes = null;
+
+ /**
+ * Create a new Patch instance using the specified broker and diff document.
+ *
+ * @param broker the DBBroker to use
+ * @param diff the diff document to apply
+ *
+ * @throws XPathException
+ */
+ public Patch(DBBroker broker, DocumentImpl diff) throws XPathException {
+ this.broker = broker;
+ parseDiff(broker, diff);
+ }
+
+ /**
+ * Apply the diff to the given source data stream passed as an XMLStreamReader. Write
+ * output to the specified receiver.
+ *
+ * @throws DiffException
+ */
+ public void patch(XMLStreamReader reader, Receiver receiver) throws DiffException {
+ try {
+ NodeId skip = null;
+ while (reader.hasNext()) {
+ int status = reader.next();
+ NodeId nodeId = (NodeId) reader.getProperty(EmbeddedXMLStreamReader.PROPERTY_NODE_ID);
+ if (status != XMLStreamReader.END_ELEMENT) {
+ ElementImpl insertedNode = (ElementImpl) insertedNodes.get(nodeId);
+ if (insertedNode != null) {
+ insertNode(insertedNode, receiver);
+ }
+ } else {
+ ElementImpl appendedNode = (ElementImpl) appendedNodes.get(nodeId);
+ if (appendedNode != null) {
+ insertNode(appendedNode, receiver);
+ }
+ }
+ if (status == XMLStreamReader.END_ELEMENT && skip != null && nodeId.equals(skip))
+ skip = null;
+ else if (deletedNodes.contains(nodeId)) {
+ if (status == XMLStreamReader.START_ELEMENT)
+ skip = nodeId;
+ } else if (skip == null)
+ copyNode(reader, receiver, status);
+ }
+ } catch (XMLStreamException e) {
+ throw new DiffException("Caught exception while reading source document for patch: " +
+ e.getMessage(), e);
+ } catch (IOException e) {
+ throw new DiffException("Caught exception while patching document: " + e.getMessage(), e);
+ } catch (SAXException e) {
+ throw new DiffException("Caught exception while serializing patch output: " + e.getMessage(), e);
+ }
+ }
+
+ private void insertNode(Element insertedNode, Receiver receiver) throws XMLStreamException, IOException, SAXException {
+ StoredNode child = (StoredNode) insertedNode.getFirstChild();
+ while (child != null) {
+ XMLStreamReader reader = broker.newXMLStreamReader(child, false);
+ while (reader.hasNext()) {
+ int status = reader.next();
+ copyNode(reader, receiver, status);
+ }
+ child = (StoredNode) child.getNextSibling();
+ }
+ }
+
+ private void copyNode(XMLStreamReader reader, Receiver receiver, int status) throws SAXException {
+ switch (status) {
+ case XMLStreamReader.START_ELEMENT:
+ AttrList attrs = new AttrList();
+ for (int i = 0; i < reader.getAttributeCount(); i++) {
+ QName attrQn = new QName(reader.getAttributeLocalName(i), reader.getAttributeNamespace(i),
+ reader.getAttributePrefix(i));
+ attrs.addAttribute(
+ attrQn,
+ reader.getAttributeValue(i),
+ getAttributeType(reader.getAttributeType(i))
+ );
+ }
+ receiver.startElement(new QName(reader.getLocalName(), reader.getNamespaceURI(), reader.getPrefix()),
+ attrs);
+ break;
+ case XMLStreamReader.END_ELEMENT:
+ receiver.endElement(new QName(reader.getLocalName(), reader.getNamespaceURI(), reader.getPrefix()));
+ break;
+ case XMLStreamReader.CHARACTERS:
+ receiver.characters(reader.getText());
+ break;
+ case XMLStreamReader.CDATA:
+ char[] cdata = reader.getTextCharacters();
+ receiver.cdataSection(cdata, 0, cdata.length);
+ break;
+ case XMLStreamReader.PROCESSING_INSTRUCTION:
+ receiver.processingInstruction(reader.getPITarget(), reader.getPIData());
+ break;
+ case XMLStreamReader.COMMENT:
+ char[] ch = reader.getTextCharacters();
+ receiver.comment(ch, 0, ch.length);
+ break;
+ }
+ }
+
+ private void parseDiff(DBBroker broker, DocumentImpl doc) throws XPathException {
+ deletedNodes = new TreeSet();
+ insertedNodes = new TreeMap();
+ appendedNodes = new TreeMap();
+
+ Element root = doc.getDocumentElement();
+ Node child = root.getFirstChild();
+ while (child != null) {
+ if (child.getNodeType() == Node.ELEMENT_NODE &&
+ child.getNamespaceURI().equals(XMLDiff.NAMESPACE)) {
+ if (child.getLocalName().equals("delete")) {
+ NodeId id = parseRef(broker, child);
+ deletedNodes.add(id);
+ } else if (child.getLocalName().equals("insert")) {
+ NodeId id = parseRef(broker, child);
+ insertedNodes.put(id, child);
+ } else if (child.getLocalName().equals("append")) {
+ NodeId id = parseRef(broker, child);
+ appendedNodes.put(id, child);
+ }
+ }
+ child = child.getNextSibling();
+ }
+ }
+
+ private NodeId parseRef(DBBroker broker, Node child) {
+ String idval = ((Element)child).getAttribute("ref");
+ NodeId id = broker.getBrokerPool().getNodeFactory().createFromString(idval);
+ return id;
+ }
+
+ private int getAttributeType(String attributeType) {
+ if ("ID".equals(attributeType))
+ return AttrImpl.ID;
+ else if ("IDREF".equals(attributeType))
+ return AttrImpl.IDREF;
+ else if ("IDREFS".equals(attributeType))
+ return AttrImpl.IDREFS;
+ else
+ return AttrImpl.CDATA;
+ }
+}
Added: trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningHelper.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningHelper.java (rev 0)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningHelper.java 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,58 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-07 The eXist Project
+ * http://exist-db.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id$
+ */
+package org.exist.versioning;
+
+import org.exist.collections.Collection;
+import org.exist.dom.DocumentImpl;
+import org.exist.xmldb.XmldbURI;
+import org.exist.storage.DBBroker;
+import org.exist.storage.lock.Lock;
+import org.exist.util.LockException;
+
+import java.util.Iterator;
+
+public class VersioningHelper {
+
+ public static DocumentImpl getBaseRevision(DBBroker broker, XmldbURI docPath) throws LockException {
+ String docName = docPath.lastSegment().toString();
+ XmldbURI collectionPath = docPath.removeLastSegment();
+ XmldbURI path = VersioningTrigger.VERSIONS_COLLECTION.append(collectionPath);
+ Collection vCollection = broker.openCollection(path, Lock.READ_LOCK);
+ try {
+ for (Iterator i = vCollection.iterator(broker); i.hasNext(); ) {
+ DocumentImpl doc = (DocumentImpl) i.next();
+ String fname = doc.getFileURI().toString();
+ int p = fname.lastIndexOf('.');
+ if (p > -1) {
+ String name = fname.substring(0, p);
+ if (name.equals(docName)) {
+ doc.getUpdateLock().acquire(Lock.READ_LOCK);
+ return doc;
+ }
+ }
+ }
+ } finally {
+ vCollection.release(Lock.READ_LOCK);
+ }
+ return null;
+ }
+}
Added: trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningTrigger.java
===================================================================
--- trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningTrigger.java (rev 0)
+++ trunk/eXist/extensions/versioning/src/org/exist/versioning/VersioningTrigger.java 2008-12-29 19:05:25 UTC (rev 8432)
@@ -0,0 +1,214 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-07 The eXist Project
+ * http://exist-db.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id$
+ */
+package org.exist.versioning;
+
+import org.exist.collections.triggers.FilteringTrigger;
+import org.exist.collections.triggers.TriggerException;
+import org.exist.collections.Collection;
+import org.exist.collections.IndexInfo;
+import org.exist.storage.DBBroker;
+import org.exist.storage.BrokerPool;
+import org.exist.storage.lock.Lock;
+import org.exist.storage.txn.Txn;
+import org.exist.xmldb.XmldbURI;
+import org.exist.dom.DocumentImpl;
+import org.exist.security.*;
+import org.exist.util.LockException;
+import org.exist.util.Configuration;
+...
[truncated message content] |