| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title xmlns:d="http://docbook.org/ns/docbook">Chapter 12. Customizing Cayenne Runtime</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 4.0 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 4.0"><link rel="home" href="index.html" title="Cayenne Guide"><link rel="up" href="cayenne-guide-part2.html" title="Part II. Cayenne Framework"><link rel="prev" href="performance-tuning.html" title="Chapter 11. Performance Tuning"><link rel="next" href="cayenne-guide-part3.html" title="Part III. Cayenne Framework - Remote Object Persistence"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript"> |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-7036673-1']); |
| _gaq.push(['_trackPageview']); |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| </script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.4.0 (4.0.M5)</th><th align="center">Chapter 12. Customizing Cayenne Runtime</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="performance-tuning.html">Prev</a> </td><th width="60%" align="center"><a accesskey="u" href="cayenne-guide-part2.html">Part II. Cayenne Framework</a></th><td width="20%" align="right"> <a accesskey="n" href="cayenne-guide-part3.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="customizing-cayenne-runtime"></a>Chapter 12. Customizing Cayenne Runtime</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="section"><a href="customizing-cayenne-runtime.html#depdendency-injection-container">Dependency Injection Container</a></span></dt><dt><span class="section"><a href="customizing-cayenne-runtime.html#ways-to-customize-runtime"> Customization Strategies</a></span></dt><dt><span class="section"><a href="customizing-cayenne-runtime.html#extendedtypes">Extended Types</a></span></dt><dt><span class="section"><a href="customizing-cayenne-runtime.html#noteworthy-runtime-components">Noteworthy Built-in Services</a></span></dt></dl></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="depdendency-injection-container"></a>Dependency Injection Container</h2></div></div></div><p>Cayenne runtime is built around a small powerful dependency injection (DI) container. Just |
| like other popular DI technologies, such as Spring or Guice, Cayenne DI container |
| manages sets of interdependent objects and allows users to configure them. These |
| objects are regular Java objects. We are calling them "services" in this document to |
| distinguish from all other objects that are not configured in the container and are not |
| managed. DI container is responsible for service instantiation, injecting correct |
| dependencies, maintaining service instances scope, and dispatching scope events to |
| services. </p><p>The services are configured in special Java classes called "modules". Each module |
| defines binding of service interfaces to implementation instances, implementation types |
| or providers of implementation instances. There are no XML configuration files, and all |
| the bindings are type-safe. The container supports injection into instance variables and |
| constructor parameters based on the <code class="code">@Inject</code> annotation. This mechanism is |
| very close to Google Guice.</p><p>The discussion later in this chapter demonstrates a standalone DI container. But keep in |
| mind that Cayenne already has a built-in Injector, and a set of default modules. A |
| Cayenne user would normally only use the API below to write custom extension modules |
| that will be loaded in that existing container when creating ServerRuntime. See |
| "Starting and Stopping ServerRuntime" chapter for an example of passing an extension |
| module to Cayenne.</p><p>Cayenne DI probably has ~80% of the features expected in a DI container and has no |
| dependency on the rest of Cayenne, so in theory can be used as an application-wide DI |
| engine. But it's primary purpose is still to serve Cayenne. Hence there are no plans to |
| expand it beyond Cayenne needs. It is an ideal "embedded" DI that does not interfere |
| with Spring, Guice or any other such framework present elsewhere in the |
| application.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="di-bindings-api"></a>DI Bindings API</h3></div></div></div><p>To have a working DI container, we need three things: service interfaces and |
| classes, a module that describes service bindings, a container that loads the |
| module, and resolves the depedencies. Let's start with service interfaces and |
| classes:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">interface</span> Service1 { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> String getString(); |
| }</pre><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">interface</span> Service2 { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> getInt(); |
| }</pre><p>A service implementation using instance variable |
| injection:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Service1Impl <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> Service1 { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Inject</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">private</span> Service2 service2; |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> String getString() { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">return</span> service2.getInt() + <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"_Service1Impl"</span>; |
| } |
| }</pre><p>Same |
| thing, but using constructor |
| injection:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Service1Impl <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> Service1 { |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">private</span> Service2 service2; |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> Service1Impl(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Inject</span> Service2 service2) { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">this</span>.service2 = service2; |
| } |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> String getString() { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">return</span> service2.getInt() + <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"_Service1Impl"</span>; |
| } |
| } |
| </pre><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Service2Impl <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> Service2 { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">private</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> i; |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> getInt() { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">return</span> i++; |
| } |
| }</pre><p>Now let's create a module implementing |
| <code class="code">org.apache.cayenne.tutorial.di.Module</code> interface that will contain |
| DI configuration. A module binds service objects to keys that are reference. Binder |
| provided by container implements fluent API to connect the key to implementation, |
| and to configure various binding options (the options, such as scope, are |
| demonstrated later in this chapter). The simplest form of a key is a Java Class |
| object representing service interface. Here is a module that binds Service1 and |
| Service2 to corresponding default implementations:</p><p> |
| </p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> Module1 <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> Module { |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> configure(Binder binder) { |
| binder.bind(Service1.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).to(Service1Impl.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| binder.bind(Service2.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).to(Service2Impl.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| } |
| }</pre><p> |
| </p><p>Once we have at least one module, we can create a DI container. |
| <code class="code">org.apache.cayenne.di.Injector</code> is the container class in |
| Cayenne:</p><pre class="programlisting">Injector injector = DIBootstrap.createInjector(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> Module1());</pre><p>Now that we have created the container, we can obtain services from it and call |
| their |
| methods:</p><pre class="programlisting">Service1 s1 = injector.getInstance(Service1.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">for</span> (<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> i = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>; i < <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">5</span>; i++) { |
| System.out.println(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"S1 String: "</span> + s1.getString()); |
| }</pre><p>This outputs the following lines, demonstrating that s1 was Service1Impl and |
| Service2 injected into it was |
| Service2Impl:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>_Service1Impl |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">1</span>_Service1Impl |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">2</span>_Service1Impl |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">3</span>_Service1Impl |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">4</span>_Service1Impl</pre><p>There are more flavors of bindings: |
| </p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// binding to instance - allowing user to create and configure instance</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// inside the module class</span> |
| binder.bind(Service2.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).toInstance(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> Service2Impl()); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// binding to provider - delegating instance creation to a special</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// provider class</span> |
| binder.bind(Service1.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).toProvider(Service1Provider.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// binding to provider instance</span> |
| binder.bind(Service1.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).toProviderInstance(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> Service1Provider()); |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// multiple bindings of the same type using Key</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// injection can reference the key name in annotation:</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// @Inject("i1")</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// private Service2 service2;</span> |
| binder.bind(Key.get(Service2.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"i1"</span>)).to(Service2Impl.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>); |
| binder.bind(Key.get(Service2.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"i2"</span>)).to(Service2Impl.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);</pre><p>Another types of confiuguration that can be bound in the container are lists and |
| maps. They will be discussed in the following chapters. </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="managing-services-lifecycle"></a>Service Lifecycle</h3></div></div></div><p>An important feature of the Cayenne DI container is instance <span class="italic">scope</span>. The default scope (implicitly used in all examples above) is |
| "singleton", meaning that a binding would result in creation of only one service |
| instance, that will be repeatedly returned from |
| <code class="code">Injector.getInstance(..)</code>, as well as injected into classes that |
| declare it as a dependency. </p><p>Singleton scope dispatches a "BeforeScopeEnd" event to interested services. This |
| event occurs before the scope is shutdown, i.e. when |
| <code class="code">Injector.shutdown()</code> is called. Note that the built-in Cayenne |
| injector is shutdown behind the scenes when <code class="code">ServerRuntime.shutdown()</code> |
| is invoked. Services may register as listeners for this event by annotating a |
| no-argument method with <code class="code">@BeforeScopeEnd</code> annotation. Such method should |
| be implemented if a service needs to clean up some resources, stop threads, |
| etc.</p><p>Another useful scope is "no scope", meaning that every time a container is asked to provide |
| a service instance for a given key, a new instance will be created and |
| returned:</p><pre class="programlisting">binder.bind(Service2.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).to(Service2Impl.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).withoutScope();</pre><p>Users |
| can also create their own scopes, e.g. a web application request scope or a session |
| scope. Most often than not custom scopes can be created as instances of |
| <code class="code">org.apache.cayenne.di.spi.DefaultScope</code> with startup and shutdown |
| managed by the application (e.g. singleton scope is a DefaultScope managed by the |
| Injector) . </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="overriding-services"></a>Overriding Services</h3></div></div></div><p>Cayenne DI allows to override services already definied in the current module, or |
| more commonly - some other module in the the same container. Actually there's no |
| special API to override a service, you'd just bind the service key again with a new |
| implementation or provider. The last binding for a key takes precedence. This means |
| that the order of modules is important when configuring a container. The built-in |
| Cayenne injector ensures that Cayenne standard modules are loaded first, followed by |
| optional user extension modules. This way the application can override the standard |
| services in Cayenne.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="ways-to-customize-runtime"></a> Customization Strategies</h2></div></div></div><p>The previous section discussed how Cayenne DI works in general terms. Since Cayenne users |
| will mostly be dealing with an existing Injector provided by ServerRuntime, it is |
| important to understand how to build custom extensions to a preconfigured container. As |
| shown in "Starting and Stopping ServerRuntime" chapter, custom extensions are done by |
| writing an aplication DI module (or multiple modules) that configures service overrides. |
| This section shows all the configuration possibilities in detail, including changing |
| properties of the existing services, contributing services to standard service lists and |
| maps, and overriding service implementations. All the code examples later in this |
| section are assumed to be placed in an application module "configure" method:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> MyExtensionsModule <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> Module { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> configure(Binder binder) { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// customizations go here...</span> |
| } |
| }</pre><pre class="programlisting">Module extensions = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> MyExtensionsModule(); |
| ServerRuntime runtime = ServerRuntime.builder() |
| .addConfig(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"com/example/cayenne-mydomain.xml"</span>) |
| .addModule(extensions) |
| .build();</pre><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="changing-properties-of-existing-services"></a>Changing Properties of Existing Services</h3></div></div></div><p>Many built-in Cayenne services change their behavior based on a value of some |
| environment property. A user may change Cayenne behavior without even knowing which |
| services are responsible for it, but setting a specific value of a known property. |
| Supported property names are listed in "Appendix A".</p><p>There are two ways to set service properties. The most obvious one is to pass it |
| to the JVM with -D flag on startup. |
| E.g.</p><pre class="screen"><code class="prompt">$</code> java -Dcayenne.server.contexts_sync_strategy=false ...</pre><p>A second one is to contribute a property to |
| <code class="code">org.apache.cayenne.configuration.DefaultRuntimeProperties.properties |
| </code>map (see the next section on how to do that). This map contains the default |
| property values and can accept application-specific values, overrding the defaults. </p><p>Note that if a property value is a name of a Java class, when this Java class is |
| instantiated by Cayenne, the container performs injection of instance variables. So |
| even the dynamically specified Java classes can use @Inject annotation to get a hold |
| of other Cayenne services.</p><p>If the same property is specified both in the command line and in the properties |
| map, the command-line value takes precedence. The map value will be ignored. This |
| way Cayenne runtime can be reconfigured during deployment.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="contributing-to-service-lists-maps"></a>Contributing to Service Collections</h3></div></div></div><p>Cayenne can be extended by adding custom objects to named maps or lists bound in |
| DI. We are calling these lists/maps "service collections". A service collection |
| allows things like appending a custom strategy to a list of built-in strategies. |
| E.g. an application that needs to install a custom DbAdapter for some database type |
| may contribute an instance of custom DbAdapterDetector to a |
| <code class="code">org.apache.cayenne.configuration.server.DefaultDbAdapterFactory.detectors</code> |
| list:</p><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> MyDbAdapterDetector <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> DbAdapterDetector { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> DbAdapter createAdapter(DatabaseMetaData md) <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">throws</span> SQLException { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// check if we support this database and retun custom adapter</span> |
| ... |
| } |
| }</pre><pre class="programlisting"><span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// since build-in list for this key is a singleton, repeated</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// calls to 'bindList' will return the same instance </span> |
| binder.bindList(DefaultDbAdapterFactory.DETECTORS_LIST) |
| .add(MyDbAdapterDetector.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);</pre><p>Maps are customized using a similar "<code class="code">bindMap</code>" method.</p><p>The names of built-in collections are listed in "Appendix B".</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="alternative-service-implementations"></a>Alternative Service Implementations</h3></div></div></div><p>As mentioned above, custom modules are loaded by ServerRuntime after the built-in |
| modules. So it is easy to redefine a built-in service in Cayenne by rebinding |
| desired implementations or providers. To do that, first we need to know what those |
| services to redefine are. While we describe some of them in the following sections, |
| the best way to get a full list is to check the source code of the Cayenne version |
| you are using and namely look in |
| <code class="code">org.apache.cayenne.configuration.server.ServerModule</code> - the main |
| built-in module in Cayenne. </p><p>Now an example of overriding <code class="code">QueryCache</code> service. The default |
| implementation of this service is provided by <code class="code">MapQueryCacheProvider</code>. |
| But if we want to use <code class="code">EhCacheQueryCache</code> (a Cayenne wrapper for the |
| EhCache framework), we can define it like |
| this:</p><pre class="programlisting">binder.bind(QueryCache.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>).to(EhCacheQueryCache.<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>);</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="extendedtypes"></a>Extended Types</h2></div></div></div><p>JDBC specification defines a set of "standard" database column types (defined in java.sql.Types class) |
| and a very specific mapping of these types to Java Object Types, such as java.lang.String, |
| java.math.BigDecimal, etc. Sometimes there is a need to use a custom Java type not known to JDBC driver and |
| Cayenne allows to configure it. For this Cayenne needs to know how to instantiate this type from |
| a database "primitive" value, and conversely, how to transform an object of the custom type to |
| a JDBC-compatible object.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="supporting-non-standard-types"></a>Supporting Non-Standard Types</h3></div></div></div><p>For supporting non-standard type you should define it via an interface <code class="code">org.apache.cayenne.access.types.ExtendedType</code>. |
| An implementation must provide <code class="code">ExtendedType.getClassName()</code> method that returns |
| a fully qualified Java class name for the supported custom type, and a number of methods |
| that convert data between JDBC and custom type. |
| The following example demonstrates how to add a custom DoubleArrayType |
| to store java.lang.Double[] as a custom string in a database:</p><pre class="programlisting"> |
| <strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">/** |
| * Defines methods to read Java objects from JDBC ResultSets and write as parameters of |
| * PreparedStatements. |
| */</strong> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span> DoubleArrayType <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">implements</span> ExtendedType { |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">private</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">final</span> String SEPARATOR = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">","</span>; |
| |
| <strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">/** |
| * Returns a full name of Java class that this ExtendedType supports. |
| */</strong> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Override</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> String getClassName() { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">return</span> Double[].<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">class</span>.getCanonicalName(); |
| } |
| |
| <strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">/** |
| * Initializes a single parameter of a PreparedStatement with object value. |
| */</strong> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Override</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> setJdbcObject(PreparedStatement statement, Object value, |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> pos, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> type, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> scale) <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">throws</span> Exception { |
| |
| String str = StringUtils.join((Double[]) value, SEPARATOR); |
| statement.setString(pos, str); |
| } |
| |
| |
| <strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">/** |
| * Reads an object from JDBC ResultSet column, converting it to class returned by |
| * 'getClassName' method. |
| * |
| * @throws Exception if read error occurred, or an object can't be converted to a |
| * target Java class. |
| */</strong> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Override</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> Object materializeObject(ResultSet rs, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> index, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> type) <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">throws</span> Exception { |
| String[] str = rs.getString(index).split(SEPARATOR); |
| Double[] res = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> Double[str.length]; |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">for</span> (<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> i = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>; i < str.length; i++) { |
| res[i] = Double.valueOf(str[i]); |
| } |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">return</span> res; |
| } |
| |
| <strong xmlns="http://www.w3.org/1999/xhtml" class="hl-tag">/** |
| * Reads an object from a stored procedure OUT parameter, converting it to class |
| * returned by 'getClassName' method. |
| * |
| * @throws Exception if read error ocurred, or an object can't be converted to a |
| * target Java class. |
| */</strong> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Override</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> Object materializeObject(CallableStatement rs, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> index, <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> type) <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">throws</span> Exception { |
| String[] str = rs.getString(index).split(SEPARATOR); |
| Double[] res = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> Double[str.length]; |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">for</span> (<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">int</span> i = <span xmlns="http://www.w3.org/1999/xhtml" class="hl-number">0</span>; i < str.length; i++) { |
| res[i] = Double.valueOf(str[i]); |
| } |
| |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">return</span> res; |
| } |
| } |
| </pre><p>For Java7</p><pre class="programlisting"> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// add DoubleArrayType to list of user types</span> |
| ServerRuntime runtime = ServerRuntime.builder() |
| .addConfig(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"cayenne-project.xml"</span>) |
| .addModule(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> Module() { |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-annotation">@Override</span> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">public</span> <span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">void</span> configure(Binder binder) { |
| binder |
| .bindList(Constants.SERVER_USER_TYPES_LIST) |
| .add(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> DoubleArrayType()); |
| } |
| }) |
| .build(); |
| </pre><p>For Java8</p><pre class="programlisting"> |
| <span xmlns="http://www.w3.org/1999/xhtml" class="hl-comment">// add DoubleArrayType to list of user types</span> |
| ServerRuntime runtime = ServerRuntime.builder() |
| .addConfig(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-string">"cayenne-project.xml"</span>) |
| .addModule(binder -> binder.bindList(Constants.SERVER_USER_TYPES_LIST).add(<span xmlns="http://www.w3.org/1999/xhtml" class="hl-keyword">new</span> DoubleArrayType())) |
| .build(); |
| </pre><p>More examples of implementation you can find in |
| <a class="link" href="https://github.com/apache/cayenne/tree/master/cayenne-java8" target="_top">cayenne-java8 module</a> or |
| <a class="link" href="https://github.com/apache/cayenne/tree/master/cayenne-joda" target="_top">cayenne-joda module</a>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="dbadapters-and-extended-types"></a>DbAdapters and Extended Types</h3></div></div></div><p>As shown in the example above, ExtendedTypes are stored by DbAdapter. In fact DbAdapters often install |
| their own extended types to address incompatibilities, incompleteness and differences between |
| JDBC drivers in handling "standard" JDBC types. For instance some drivers support reading large |
| character columns (CLOB) as java.sql.Clob, but some other - as "character stream", etc. |
| Adapters provided with Cayenne override <code class="code">configureExtendedTypes()</code> method to install their own types, |
| possibly substituting Cayenne defaults. Custom DbAdapters can use the same technique.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title"><a name="noteworthy-runtime-components"></a>Noteworthy Built-in Services</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="jdbceventlogger"></a>JdbcEventLogger</h3></div></div></div><p><code class="code">org.apache.cayenne.log.JdbcEventLogger</code> is the service that defines |
| logging API for Cayenne internals. It provides facilities for logging queries, |
| commits, transactions, etc. The default implementation is |
| <code class="code">org.apache.cayenne.log.CommonsJdbcEventLogger</code> that performs logging |
| via commons-logging library. Cayenne library includes another potentially useful |
| logger - <code class="code">org.apache.cayenne.log.FormattedCommonsJdbcEventLogger</code> that |
| produces formatted multiline SQL output that can be easier to read.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="datasourcefactory"></a>DataSourceFactory</h3></div></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="datachannelfilter"></a>DataChannelFilter</h3></div></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="querycache"></a>QueryCache</h3></div></div></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="performance-tuning.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="cayenne-guide-part2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="cayenne-guide-part3.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 11. Performance Tuning </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Part III. Cayenne Framework - Remote Object Persistence </td></tr></table></div></body></html> |