See: Description
Package | Description |
---|---|
com.marklogic.xcc |
XCC Core Public Interfaces.
|
com.marklogic.xcc.examples |
XCC Examples.
|
com.marklogic.xcc.exceptions |
XCC Exceptions.
|
com.marklogic.xcc.jndi |
XCC Java Naming and Directory Interface (JNDI) Support.
|
com.marklogic.xcc.spi |
XCC Service Provider Interface Package.
|
com.marklogic.xcc.types |
XCC Type Definitions.
|
This is XCC, the MarkLogic XML Content Connector API. This interface varies significantly from the original MarkLogic connector solution, XDBC. One of the goals of the new API is to simplify the public interface to make it easier to understand and to use.
The XCC API has been designed so that client code will be easier to write, less error prone and more robust. With those goals in mind, the new public API intentionally doesn't use abstrations like "connection" or "statement". The new model is that of a session, or conversation, between client code and a contentbase.
The session metaphor is not only simpler and more natural, it makes it easier to hide implementation details. It also emphasizes that XCC is not like JDBC. Common JDBC usage patterns, such as pooling connections, are not appropriate with XCC.
The central metaphor used in XCC is the
Session
interface.
A Session
object
is the facade through which client code
performs all interaction with a contentbase.
Session
instances
encapsulate the location of a particular
server, a contentbase on that server and authentication
credentials (user identity) for that contentbase. A
Session
also
holds dynamic state, but it is a lightweight object.
It is OK to create and release
Session
objects
as needed. Do not expend effort to pool and reuse
them, they are not expensive to create.
Session
objects are
created by factory methods on a
ContentSource
instance.
A ContentSource
object statically defines where a
content server (an instance of MarkLogic Server) can be found.
At a minimum, a ContentSource
object identifies a MarkLogic XDBC Server (host and port).
It may also optionally hold default authentication credentials
(user and password) and/or a contentbase (database)
identifier on that server. There are several variations
of the ContentSource.newSession()
factory method which take arguments to provide this
Session
-specific
information or to override the defaults.
Like J2EE DataSource objects, a
ContentSource
instance may
be bound to a JNDI naming service. This allows the
runtime environment (a J2EE container for example) to
supply a pre-initialized
ContentSource
instance.
This allows specification of the connection details at
deployment time. Application
code uses a JNDI lookup key to obtain a
ContentSource
instance. A typical JNDI lookup in a J2EE
container would look like this:
private ContentSource findContentSource() throws ServletException { try { Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup ("java:comp/env"); return (ContentSource) envCtx.lookup("marklogic/ContentSource"); } catch (NamingException e) { throw new ServletException ("ContentSource lookup failed: " + e, e); } }
See ContentSourceBeanFactory
for
more details about integrating with JNDI.
If using JNDI to externalize
ContentSource
configuration
is not appropriate, the helper class
ContentSourceFactory
may be used to instantiate
ContentSource
objects directly.
Several variations of the
ContentSourceFactory.newContentSource(String, int)
method are available:
ContentSource contentSource = ContentSourceFactory.newContentSource ("somehost", 1234);
ContentSource contentSource = ContentSourceFactory.newContentSource ("localhost", 1234, "fred", "secret");
ContentSource contentSource = ContentSourceFactory.newContentSource ("host", 5678, "tony", "hush", "pubsdb");
Of note is the signature which takes a URI argument
(ContentSourceFactory.newContentSource(URI)
).
This factory method accepts a URI of the form:
xdbc://user:password@host:port/contentbase
Which encapsulates all the connection information into a single argument. The URL scheme "xdbc" means the connection will be made to an XDBC server port. The scheme "xcc" may also be used, it's an alias for "xdbc". Additional schemes may be added in the future, but these are the only two currently supported.
Passing a single String argument may be more convenient than passing
four or five discreet values. Note that the factory method takes a
URI
object, not a String
.
URI uri = new URI ("xdbc://joe:secret@devhost:8050/techpubsdb"); ContentSource contentSource = ContentSourceFactory.newContentSource (uri);
Following are some sample code snippets that illustrate typical usage scenarios.
This is an example of using
Session.submitRequest(Request)
to run an XQuery script
and then iterating over the result. There is no longer an
explicit connection object. The
Session
implementation
manages connections automatically as needed.
Also, when a Session
object is closed, any currently open streaming
ResultSequence
objects
created from that Session
will automatically be closed. Any cached
ResultSequence
s no longer
have any relationship to the Session
that created them and will not be affected.
Session session = contentSource.newSession ("mydatabase"); Request request = session.newAdhocQuery ("\"Hello World\""); ResultSequence rs = session.submitRequest (request); while (rs.hasNext()) { ResultItem rsItem = rs.next(); XdmItem item = rsItem.getItem(); if (item instanceof XSString) { String strValue = item.asString(); System.out.println ("String: " + strValue); } if (item instanceof XSDateTime) { XSDateTime dateTime = (XSDateTime) item; Date date = dateTime.asDate(); System.out.println ("DateTime: " + date); } ... // Each ResultItem instance will be a concrete Item class } session.close();
In addition to ad-hoc queries,
Session.submitRequest(Request)
can take a
ModuleInvoke
or
ModuleSpawn
object as the
argument. Rather than literal code to be executed,
these specify the
URI of a server-resident module to be evaluated. In all
other respects they are the same.
Session session = contentSource.newSession ("mydatabase"); Request request = session.newModuleInvoke ("mymodule.xqy"); ResultSequence rs = session.submitRequest (request); while (rs.hasNext()) { ResultItem item = rs.next(); ... (same as previous example) } session.close();
Variables may be bound to Request
objects. When an execution request is issued to the server with
Session.submitRequest(Request)
all the variables currently bound to the
Request
object are sent along
and defined as external variables in the
execution context in the server.
XCC lets you create
XdmNode
s and
XdmSequence
s, as well as
XdmAtomic
values.
However, in the initial XCC release values of this type may
not be bound as external variables because MarkLogic Server
cannot yet accept them. This capability is anticipated
for a future release.
A XdmVariable
object is a named
XdmValue
. XCC defines
interfaces that model the XQuery data types.
See the package
com.marklogic.xcc.types
(click the Description link)
for UML diagrams and details of the type hierarchies.
The following is a (very) verbose example of creating and setting an external variable using a namespace:
Session session = contentSource.newSession ("mydatabase"); Request request = session.newAdhocQuery ( "xquery version \"1.0-ml\";\n" + "declare namespace xyz=\"http://xyz.com/foo/bar\";\n" + "declare variable $xyz:myvar as xs:string external;\n" + "data ($xyz:myvar)"); // create an unnamed xs:string value XdmValue value = ValueFactory.newXSString ("Some string value"); // create a new XName object referencing the above namespace XName xname = new XName ("http://xyz.com/foo/bar", "myvar"); // Create a Variable (name + value) instance XdmVariable myVariable = ValueFactory.newVariable (xname, value); // bind the Variable to the Request request.setVariable (myVariable); // "$xyz:myvar as xs:string" will be defined at query run time ResultSequence rs = session.submitRequest (request);
See the ValueFactory
helper class for more details about creating
XdmVariable
and
XdmValue
instances.
The following is an example of creating and binding a variable in the default namespace.
Session session = contentSource.newSession ("mydatabase"); Request request = session.newAdhocQuery ( "xquery version \"1.0-ml\";\n" + "declare variable $myvar as xs:string external;\n" + "data ($myvar)"); // create an unnamed xs:string value XdmValue value = ValueFactory.newXSString ("Some string value"); // create a new XName object referencing the default namespace XName name = new XName ("myvar"); // create a Variable and bind it to the Request request.setVariable (ValueFactory.newVariable (name, value)); // "$myvar as xs:string" will be defined at query run time ResultSequence rs = session.submitRequest (request);
A conveience method on the Session
object will create and bind a XdmVariable
instance in one call. The following example creates the
same XdmVariable
as above,
binds it to the Request
and
returns the newly created XdmVariable
instance. In this example, the return value is ignored.
Session session = contentSource.newSession ("mydatabase"); Request request = session.newAdhocQuery ( "xquery version \"1.0-ml\";\n" + "declare variable $myvar as xs:string external;\n" + "data ($myvar)"); // create Variable "myvar", bind to Request, ignore return value request.setNewVariable ("myvar", ValueType.XS_STRING, "Some string value"); // "$myvar as xs:string" will be defined at query run time ResultSequence rs = session.submitRequest (request);
The model for inserting content differs in a couple
of significant ways from XDBC.
First of all, you no longer ask for an XDMPDocInsertStream
and push your data into it. You now create
Content
objects
which describe content (a document) to be inserted
and XCC pulls the data from that source.
Secondly, because content uploads can be interrupted
and XCC implements automatic recovery of
uploads, instances of
Content
should be
rewindable. See the
ContentFactory
class
for acceptable sources of content.
This example inserts an XML document from a literal
String
, in the "MyNameSpace" namespace and requests
that no automatic document repair be done. The
ContentCreateOptions
instance is created with a convenience method that
is preset to select XML format.
ContentCreateOptions options = ContentCreateOptions.newXmlInstance(); options.setNamespace ("MyNameSpace"); options.setRepairLevel (DocumentRepairLevel.NONE); Content content = ContentFactory.newContent ("someUri", "<root attr=\"foo\">blah</root>", options); session.insertContent (content);
This example inserts the content of a file in
text format. It uses a
ContentCreateOptions
object to set the namespace and quality.
File file = new File ("/some/file/path"); ContentCreateOptions options = ContentCreateOptions.newTextInstance(); options.setNamespace ("MyNameSpace"); options.setQuality (20); Content content = ContentFactory.newContent ("someUri", file, options); session.insertContent (content);
This example takes a W3C (Document
)
Object Model (DOM)
instance (an object representation of an XML tree) and
inserts it via the
Session
object. No
ContentCreateOptions
object is provided, so defaults are applied. Because,
by definition, the DOM is a well-formed XML tree,
the content format defaults to XML. If another
format (text or binary) is selected by the options,
the serialized String representation of the XML
tree is inserted.
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document dom = builder.parse ("someDocUri"); Content content = ContentFactory.newContent ("someUri", dom, null); session.insertContent (content);
If you're using JDOM,
you can use one of the outputter
classes in the
org.jdom.output
package to convert
the JDOM document to a form that can be handled by
a Session
.
For example, this code translates a JDOM tree
to a W3C DOM and inserts it:
Document dom = new org.jdom.output.DOMOutputter().output (jdomDocument); Content content = ContentFactory.newContent ("someUri", dom, null); session.insertContent (content);
For large JDOM trees, it may be more efficient to serialize them as Strings for insertion.
Multiple documents can be atomically inserted
(all or none are committed as a unit) by passing
an array of Content
objects to
Session.insertContent(Content [])
.
Session session = contentSource.newSession ("mydatabase"); File file = new File ("/some/file/path.xml"); String stringDoc = "<snoop attr=\"bling\">dog</snoop>"; DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document dom = builder.parse ("someDocUri"); Content [] docGroup = { ContentFactory.newContent ("uri1", file, null), ContentFactory.newContent ("uri2", stringDoc, null), ContentFactory.newContent ("uri3", dom, null) }; session.insertContent (docGroup);
Copyright © 2017 MarkLogic Corporation. All Rights Reserved.
Complete online documentation for MarkLogic Server, XQuery and related components may be found at developer.marklogic.com