| |
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| <HTML> |
| <HEAD> |
| <!-- $PAGETITLE --> |
| <TITLE>OpenEJB - Dynamic Datasource</TITLE> |
| <LINK href="http://openejb.apache.org/all.css" rel="stylesheet" type="text/css"> |
| <!--[if IE]><link rel="stylesheet" type="text/css" media="screen, projection" href="openejb.apache.org/ie.css"><![endif]--> |
| |
| <LINK rel="SHORTCUT ICON" href="http://openejb.apache.org/images/favicon.ico"> |
| <META http-equiv="Content-Type" content="text/html;charset=UTF-8"> |
| </HEAD> |
| <BODY> |
| |
| <!-- Delay the loading of the external javascript file needed for labels (as it takes too long to load and visibly holds loading of the page body) --> |
| <!-- To do this without javascript errors over undefined functions, we need to declare stubs here (that are overrided later by the proper implementations) --> |
| <SCRIPT language="JavaScript" type="text/javascript"> |
| function doAddLabel(hideTextfieldAfterAddParam) |
| { |
| // stub |
| } |
| |
| function onAddLabel() |
| { |
| // stub |
| } |
| |
| function showLabelsInput() |
| { |
| // stub |
| } |
| </SCRIPT> |
| |
| <A name="top"></A> |
| <TABLE class="frameTable" cellpadding="0" cellspacing="0" border="0"> |
| <TR class="Row1"> |
| <TD class="Col1"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col2"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col3"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col4"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col5"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| </TR> |
| <TR class="Row2"> |
| <TD class="Col1"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col2"> </TD> |
| <TD class="Col3" id="breadcrumbs"> |
| <!-- $TOP_NAV_BAR --> |
| <A href="../OPENEJB/index.html" title="Index">Home</A> | <A href="../OPENEJB/download.html" title="Download">Download</A> | <A href="../OPENEJB/mailing-lists.html" title="Mailing Lists">Lists</A> | <A href="http://issues.apache.org/jira/browse/OPENEJB" class="external-link" rel="nofollow">Issues</A> |
| |
| </TD> |
| <TD class="Col4"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col5"> </TD> |
| </TR> |
| <TR class="Row3"> |
| <TD class="Col1"><IMG alt="" class="Row3Img" id="thinLine" src="http://openejb.apache.org/images/line_sm.gif"></TD> |
| <TD class="Col2"><IMG alt="" class="Row3Img" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col3"><IMG alt="" class="Row3Img" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col4"><IMG alt="" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col5"><IMG alt="" class="Row3Img" src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| </TR> |
| <TR class="Row4"> |
| <TD class="Col1"> |
| <SPAN id="Navigation"> |
| |
| <H3><A name="Navigation-Overview"></A>Overview</H3> |
| |
| <UL class="alternate" type="square"> |
| <LI><A href="../OPENEJB/index.html" title="Index">Home</A></LI> |
| <LI><A href="../OPENEJB/news.html" title="News">News</A></LI> |
| <LI><A href="../OPENEJB/faq.html" title="FAQ">FAQ</A></LI> |
| <LI><A href="../OPENEJB/download.html" title="Download">Download</A></LI> |
| <LI><A href="index.html" title="Index">Documentation</A></LI> |
| <LI><A href="../OPENEJB/examples.html" title="Examples">Examples</A></LI> |
| <LI><A href="http://cwiki.apache.org/confluence/display/OPENEJB/Lightening%20Demos" class="external-link" rel="nofollow">Lightning Demos</A></LI> |
| <LI><A href="../OPENEJB/mailing-lists.html" title="Mailing Lists">Mailing Lists</A></LI> |
| <LI><A href="../OPENEJB/source-code.html" title="Source Code">Source Code</A></LI> |
| <LI><A href="http://blogs.apache.org/openejb" class="external-link" rel="nofollow">Project Blog</A></LI> |
| </UL> |
| |
| |
| <H3><A name="Navigation-Servers"></A>Servers</H3> |
| |
| <UL class="alternate" type="square"> |
| <LI><A href="../OPENEJB/local-server.html" title="Local Server">Local</A></LI> |
| <LI><A href="../OPENEJB/remote-server.html" title="Remote Server">Remote</A></LI> |
| </UL> |
| |
| |
| <H3><A name="Navigation-Integrations"></A>Integrations</H3> |
| |
| <UL class="alternate" type="square"> |
| <LI><A href="tomcat.html" title="Tomcat">Tomcat</A></LI> |
| <LI><A href="../OPENEJB/geronimo.html" title="Geronimo">Geronimo</A></LI> |
| <LI><A href="../OPENEJB/webobjects.html" title="WebObjects">WebObjects</A></LI> |
| </UL> |
| |
| |
| <H3><A name="Navigation-Community"></A>Community</H3> |
| |
| <UL class="alternate" type="square"> |
| <LI><A href="../OPENEJB/team.html" title="Team">Team</A></LI> |
| <LI><A href="../OPENEJB/articles.html" title="Articles">Articles</A></LI> |
| <LI><A href="http://webchat.freenode.net/?channels=openejb" class="external-link" rel="nofollow">IRC</A></LI> |
| </UL> |
| |
| |
| <H3><A name="Navigation-RelatedProjects"></A>Related Projects</H3> |
| |
| <UL class="alternate" type="square"> |
| <LI><A href="http://activemq.apache.org/" class="external-link" rel="nofollow">ActiveMQ</A></LI> |
| <LI><A href="http://openjpa.apache.org/" class="external-link" rel="nofollow">OpenJPA</A></LI> |
| <LI><A href="http://cxf.apache.org/" class="external-link" rel="nofollow">CXF</A></LI> |
| </UL> |
| |
| |
| <H3><A name="Navigation-Index"></A>Index</H3> |
| <UL class="alternate" type="square"> |
| <LI><A href="../OPENEJB/space-index.html" title="Space Index">Site Index</A></LI> |
| <LI><A href="space-index.html" title="Space Index">Doc Index</A></LI> |
| </UL> |
| |
| <H3> |
| <A name="Navigation-Feeds"></A> |
| Feeds |
| </H3> |
| |
| <UL class="feeds"> |
| <LI> |
| <A href="http://cwiki.apache.org/confluence/spaces/rss.action?key=OPENEJB&newPages=false"> |
| <IMG src="http://openejb.apache.org/images/rss.gif"></A> |
| <A class="feedsText" href="http://cwiki.apache.org/confluence/spaces/rss.action?key=OPENEJB&newPages=false">Site</A> |
| </LI> |
| |
| <LI><A href="http://cwiki.apache.org/confluence/spaces/blogrss.action?key=OPENEJB"> |
| <IMG src="http://openejb.apache.org/images/rss.gif"></A> |
| <A class="feedsText" href="http://cwiki.apache.org/confluence/spaces/blogrss.action?key=OPENEJB">News</A> |
| </LI> |
| </UL> |
| </SPAN> |
| </TD> |
| <TD class="Col2"> </TD> |
| <TD class="Col3"> |
| <TABLE id="PageHeader" border="0" width="100%"> |
| <TR> |
| <TD> |
| <A href="http://openejb.org/"> |
| <IMG hspace="0" src="http://openejb.apache.org/images/logo_openejb.gif" vspace="0"> |
| </A> |
| </TD> |
| <TD align="right"> |
| <A href="http://www.apache.org/"> |
| <IMG src="http://www.apache.org/images/asf-logo.gif" width="258" height="66"> |
| </A> |
| </TD> |
| </TR> |
| <TR> |
| <TD id="page_title"> |
| <!-- $TITLE --> |
| Dynamic Datasource |
| </TD> |
| |
| <TD align="right"> |
| <BR><BR> |
| <!-- Google CSE Search Box Begins --> |
| <FORM id="searchbox_010475492895890475512:_t4iqjrgx90" action="http://www.google.com/cse"> |
| <INPUT type="hidden" name="cx" value="010475492895890475512:_t4iqjrgx90"> |
| <INPUT type="hidden" name="cof" value="FORID:0"> |
| <INPUT name="q" type="text" size="25"> |
| <INPUT type="submit" name="sa" value="Search"> |
| </FORM> |
| <SCRIPT type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_010475492895890475512:_t4iqjrgx90"></SCRIPT> |
| <!-- Google CSE Search Box Ends --> |
| |
| </TD> |
| </TR> |
| </TABLE> |
| <P> |
| <!-- $BODY --> |
| <DIV id="PageContent"> |
| <H1><A name="DynamicDatasource-OpenEJBdynamicdatasource"></A>OpenEJB dynamic datasource</H1> |
| |
| <H2><A name="DynamicDatasource-Goal"></A>Goal</H2> |
| |
| <P>The openejb dynamic datasource api aims to allow to use multiple data sources as one.</P> |
| |
| <P>It can be useful for technical reasons (load balancing for example) or functionnal reasons (filtering, aggregation, enriching...).</P> |
| |
| <H2><A name="DynamicDatasource-TheAPI"></A>The API</H2> |
| |
| <P>The interface Router (<TT>org.apache.openejb.resource.jdbc.Router</TT>) have only one method to get the datasource to use:</P> |
| |
| <DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent"> |
| <PRE class="code-java">Router.getDataSource()</PRE> |
| </DIV></DIV> |
| |
| <P>The <TT>org.apache.openejb.resource.jdbc.RoutedDataSource</TT> wraps a classical data source. It has to be used to declare your datasource.</P> |
| |
| <P>You can implement all the policy you want in your Router implementation.</P> |
| |
| <P>A class called <TT>org.apache.openejb.resource.jdbc.AbstractRouter</TT> is available to ease router development.</P> |
| |
| <H2><A name="DynamicDatasource-Knownlimitation%28s%29"></A>Known limitation(s)</H2> |
| |
| <P>You have to use the same kind of databases (same version, same configuration...).</P> |
| |
| <P>All database have to be created when you use the router. The way to do it automatically can depend of your JPA provider.</P> |
| |
| <H3><A name="DynamicDatasource-OpenJPA"></A>OpenJPA</H3> |
| |
| <P>OpenJPA initializes its database when the entitymanager is called for the first time so you need to initialize all your proxied datasource before using the other one. It can be done using an Init EJB doing a find() on each proxied datasource.</P> |
| |
| <H3><A name="DynamicDatasource-Hibernate"></A>Hibernate</H3> |
| |
| <P>Hibernate initializes the database when it starts so if you declare a persistence unit by database all databases will be initialized at the start up.</P> |
| |
| <H2><A name="DynamicDatasource-Example"></A>Example </H2> |
| |
| <H3><A name="DynamicDatasource-Thestory%28theunittestexample%29"></A>The story (the unit test example)</H3> |
| |
| <P>You want to use only one datasource in the code but you have a criteria to set to choose the real database to use between three.</P> |
| |
| <P>So in your code you want something like:</P> |
| |
| <DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent"> |
| <PRE class="code-java">@Stateless |
| <SPAN class="code-keyword">public</SPAN> class RoutedEJBBean { |
| @PersistenceContext(unitName = <SPAN class="code-quote">"router"</SPAN>) |
| <SPAN class="code-keyword">private</SPAN> EntityManager em; |
| |
| @Resource(name = <SPAN class="code-quote">"My Router"</SPAN>, type = DeterminedRouter.class) |
| <SPAN class="code-keyword">private</SPAN> DeterminedRouter router; <SPAN class="code-comment">// <SPAN class="code-keyword">this</SPAN> router is not automatic, we need it to select the database to use |
| </SPAN> |
| <SPAN class="code-keyword">public</SPAN> void persist(<SPAN class="code-object">int</SPAN> id, <SPAN class="code-object">String</SPAN> name, <SPAN class="code-object">String</SPAN> clientDatasource) { |
| router.setDataSource(clientDatasource); |
| em.persist(<SPAN class="code-keyword">new</SPAN> Person(id, name)); |
| } |
| }</PRE> |
| </DIV></DIV> |
| |
| <H2><A name="DynamicDatasource-Therouterimplementation"></A>The router implementation</H2> |
| |
| <P>The router will simply manage a map to store proxied datasources and a field to store the datasource used in the current thread (ThreadLocal).</P> |
| |
| <DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent"> |
| <PRE class="code-java"><SPAN class="code-keyword">public</SPAN> class DeterminedRouter <SPAN class="code-keyword">implements</SPAN> Router { |
| <SPAN class="code-keyword">private</SPAN> <SPAN class="code-object">String</SPAN> dataSourceNames; <SPAN class="code-comment">// used to store configuration (openejb.xml) |
| </SPAN> <SPAN class="code-keyword">private</SPAN> <SPAN class="code-object">String</SPAN> defaultDataSourceName; <SPAN class="code-comment">// defautl data source name |
| </SPAN> <SPAN class="code-keyword">private</SPAN> Map<<SPAN class="code-object">String</SPAN>, DataSource> dataSources = <SPAN class="code-keyword">null</SPAN>; <SPAN class="code-comment">// proxied data sources |
| </SPAN> <SPAN class="code-keyword">private</SPAN> ThreadLocal<DataSource> currentDataSource = <SPAN class="code-keyword">new</SPAN> ThreadLocal<DataSource>(); <SPAN class="code-comment">// the datasource to use or <SPAN class="code-keyword">null</SPAN> |
| </SPAN> |
| /** |
| * @param datasourceList datasource resource name, separator is a space |
| */ |
| <SPAN class="code-keyword">public</SPAN> void setDataSourceNames(<SPAN class="code-object">String</SPAN> datasourceList) { |
| dataSourceNames = datasourceList; |
| } |
| |
| /** |
| * lookup datasource in openejb resources |
| */ |
| <SPAN class="code-keyword">private</SPAN> void init() { <SPAN class="code-comment">// looking up datasources declared as proxied |
| </SPAN> dataSources = <SPAN class="code-keyword">new</SPAN> ConcurrentHashMap<<SPAN class="code-object">String</SPAN>, DataSource>(); |
| <SPAN class="code-keyword">for</SPAN> (<SPAN class="code-object">String</SPAN> ds : dataSourceNames.split(<SPAN class="code-quote">" "</SPAN>)) { |
| ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class); |
| |
| <SPAN class="code-object">Object</SPAN> o = <SPAN class="code-keyword">null</SPAN>; |
| Context ctx = containerSystem.getJNDIContext(); |
| <SPAN class="code-keyword">try</SPAN> { |
| o = ctx.lookup(<SPAN class="code-quote">"openejb:Resource/"</SPAN> + ds); |
| <SPAN class="code-keyword">if</SPAN> (o <SPAN class="code-keyword">instanceof</SPAN> DataSource) { |
| dataSources.put(ds, (DataSource) o); |
| } |
| } <SPAN class="code-keyword">catch</SPAN> (NamingException ignore) { |
| } |
| } |
| } |
| |
| /** |
| * @<SPAN class="code-keyword">return</SPAN> the user selected data source <SPAN class="code-keyword">if</SPAN> it is set |
| * or the <SPAN class="code-keyword">default</SPAN> one |
| * @<SPAN class="code-keyword">throws</SPAN> IllegalArgumentException <SPAN class="code-keyword">if</SPAN> the data source is not found |
| */ |
| <SPAN class="code-keyword">public</SPAN> DataSource getDataSource() { |
| <SPAN class="code-comment">// lazy init of routed datasources |
| </SPAN> <SPAN class="code-keyword">if</SPAN> (dataSources == <SPAN class="code-keyword">null</SPAN>) { |
| init(); |
| } |
| |
| <SPAN class="code-comment">// <SPAN class="code-keyword">if</SPAN> no datasource is selected use the <SPAN class="code-keyword">default</SPAN> one |
| </SPAN> <SPAN class="code-keyword">if</SPAN> (currentDataSource.get() == <SPAN class="code-keyword">null</SPAN>) { |
| <SPAN class="code-keyword">if</SPAN> (dataSources.containsKey(defaultDataSourceName)) { |
| <SPAN class="code-keyword">return</SPAN> dataSources.get(defaultDataSourceName); |
| |
| } <SPAN class="code-keyword">else</SPAN> { |
| <SPAN class="code-keyword">throw</SPAN> <SPAN class="code-keyword">new</SPAN> IllegalArgumentException(<SPAN class="code-quote">"you have to specify at least one datasource"</SPAN>); |
| } |
| } |
| |
| <SPAN class="code-comment">// the developper set the datasource to use |
| </SPAN> <SPAN class="code-keyword">return</SPAN> currentDataSource.get(); |
| } |
| |
| /** |
| * |
| * @param datasourceName data source name |
| */ |
| <SPAN class="code-keyword">public</SPAN> void setDataSource(<SPAN class="code-object">String</SPAN> datasourceName) { |
| <SPAN class="code-keyword">if</SPAN> (dataSources == <SPAN class="code-keyword">null</SPAN>) { |
| init(); |
| } |
| <SPAN class="code-keyword">if</SPAN> (!dataSources.containsKey(datasourceName)) { |
| <SPAN class="code-keyword">throw</SPAN> <SPAN class="code-keyword">new</SPAN> IllegalArgumentException(<SPAN class="code-quote">"data source called "</SPAN> + datasourceName + <SPAN class="code-quote">" can't be found."</SPAN>); |
| } |
| DataSource ds = dataSources.get(datasourceName); |
| currentDataSource.set(ds); |
| } |
| |
| <SPAN class="code-keyword">public</SPAN> void setDefaultDataSourceName(<SPAN class="code-object">String</SPAN> name) { |
| <SPAN class="code-keyword">this</SPAN>.defaultDataSourceName = name; |
| } |
| }</PRE> |
| </DIV></DIV> |
| |
| |
| |
| <H2><A name="DynamicDatasource-Creationoftheserviceproviderfortherouter"></A>Creation of the service provider for the router</H2> |
| |
| <P>To be able to use your router add a file called service-jar.xml under META-INF/<package>. For example META-INF/org.router.</P> |
| |
| <P>This file will contain something like:</P> |
| |
| <DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent"> |
| <PRE class="code-xml"><SPAN class="code-tag"><?xml version=<SPAN class="code-quote">"1.0"</SPAN> encoding=<SPAN class="code-quote">"UTF-8"</SPAN>?></SPAN> |
| <SPAN class="code-tag"><ServiceJar></SPAN> |
| <ServiceProvider id=<SPAN class="code-quote">"DeterminedRouter"</SPAN> service=<SPAN class="code-quote">"Resource"</SPAN> |
| type=<SPAN class="code-quote">"org.apache.openejb.resource.jdbc.Router"</SPAN> class-name=<SPAN class="code-quote">"implementation class"</SPAN>> |
| Param defaultValue |
| ParamWithNoDefaultValue |
| <SPAN class="code-tag"></ServiceProvider></SPAN> |
| <SPAN class="code-tag"></ServiceJar></SPAN></PRE> |
| </DIV></DIV> |
| |
| <H2><A name="DynamicDatasource-openejb.xml"></A>openejb.xml</H2> |
| |
| <P>In the openejb.xml file, you have to declare your dynamic database and in our example it needs the proxied datasources too:</P> |
| |
| <DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent"> |
| <PRE class="code-xml"><SPAN class="code-tag"><Resource id=<SPAN class="code-quote">"router"</SPAN> type=<SPAN class="code-quote">"<your implementation></SPAN>"</SPAN> provider=<SPAN class="code-quote">"<SPAN class="code-tag"><your provider></SPAN>"</SPAN>> |
| Param value |
| <SPAN class="code-tag"></Resource></SPAN> |
| <SPAN class="code-tag"><Resource id=<SPAN class="code-quote">"route db"</SPAN> type=<SPAN class="code-quote">"DataSource"</SPAN> provider=<SPAN class="code-quote">"RoutedDataSource"</SPAN>></SPAN> |
| Router router |
| <SPAN class="code-tag"></Resource></SPAN> |
| |
| <SPAN class="code-tag"><!–- real databases – for our example --></SPAN> |
| <SPAN class="code-tag"><Resource id=<SPAN class="code-quote">"db1"</SPAN> type=<SPAN class="code-quote">"DataSource"</SPAN>></SPAN> |
| JdbcDriver org.hsqldb.jdbcDriver |
| JdbcUrl jdbc:hsqldb:mem:db1 |
| UserName sa |
| Password |
| JtaManaged true |
| <SPAN class="code-tag"></Resource></SPAN> |
| <SPAN class="code-tag"><Resource id=<SPAN class="code-quote">"db2"</SPAN> type=<SPAN class="code-quote">"DataSource"</SPAN>></SPAN> |
| JdbcDriver org.hsqldb.jdbcDriver |
| JdbcUrl jdbc:hsqldb:mem:db2 |
| UserName sa |
| Password |
| JtaManaged true |
| <SPAN class="code-tag"></Resource></SPAN> |
| <SPAN class="code-tag"><Resource id=<SPAN class="code-quote">"db3"</SPAN> type=<SPAN class="code-quote">"DataSource"</SPAN>></SPAN> |
| JdbcDriver org.hsqldb.jdbcDriver |
| JdbcUrl jdbc:hsqldb:mem:db3 |
| UserName sa |
| Password |
| JtaManaged true |
| <SPAN class="code-tag"></Resource></SPAN></PRE> |
| </DIV></DIV> |
| </DIV> |
| </P> |
| </TD> |
| <TD class="Col4"><IMG src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col5"> |
| |
| |
| </TD> |
| </TR> |
| <TR class="Row5"> |
| <TD class="Col1"> </TD> |
| <TD class="Col2"> </TD> |
| <TD class="Col3"> |
| <BR> |
| <BR> |
| <IMG width="100%" height="1" src="http://openejb.apache.org/images/line_light.gif"> |
| <TABLE width="100%"> |
| <TR> |
| <TD> |
| <SPAN class="bodyGrey"> |
| <SMALL> |
| <NOTICE><!-- $FOOTER --> |
| Apache OpenEJB is an project of The Apache Software Foundation (ASF) |
| </NOTICE> |
| <BR> |
| Site Powered by |
| <A href="http://atlassian.com/">Atlassian</A> |
| <A href="http://atlassian.com/confluence/">Confluence</A> |
| . |
| </SMALL> |
| </SPAN> |
| </TD> |
| <TD align="right"> |
| <A style="color:#999;font-size:small;font-weight:normal;" href="https://cwiki.apache.org/confluence/pages/editpage.action?spaceKey=OPENEJBx30&title=Dynamic%20Datasource">[ edit ]</A> |
| </TD> |
| </TR> |
| </TABLE> |
| <BR> |
| </TD> |
| <TD class="Col4"><IMG src="http://openejb.apache.org/images/dotTrans.gif"></TD> |
| <TD class="Col5"> </TD> |
| </TR> |
| </TABLE> |
| |
| <!-- Needed for composition plugin --> |
| <!-- delay the loading of large javascript files to the end so that they don't interfere with the loading of page content --> |
| <SPAN style="display: none"> |
| <SCRIPT type="text/javascript" language="JavaScript" src="http://cwiki.apache.org/confluence/labels-javascript"></SCRIPT> |
| |
| <SCRIPT src="http://www.google-analytics.com/urchin.js" type="text/javascript"> |
| </SCRIPT> |
| <SCRIPT type="text/javascript"> |
| _uacct = "UA-2717626-1"; |
| urchinTracker(); |
| </SCRIPT> |
| </SPAN> |
| |
| </BODY> |
| </HTML> |