You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomee.apache.org by onyii5119 <on...@gmail.com> on 2014/03/16 19:30:33 UTC

Re: Dynamic DataSource - Exception

Does anyone have a simple *working example* of dynamic dataSource I can learn
from? Don't point me to documentations, I tried most and they don't work for
me.

Thanks.



--
View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668226.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by onyii5119 <on...@gmail.com>.
Thanks.



--
View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668237.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by Romain Manni-Bucau <rm...@gmail.com>.
kind of but not exactly.

TomEE supports configuration of datasources and resources (including router) in:
1) tomee.xml
2) resources.xml (app classloader)
3) system.properties or JVM system properties

All of them are static

If you want runtime resource definition you need to use internal
mecanism. Globally it doesn't need to be tomee datasource to work, it
can be custom ones. The easier will be to use DataSourceFactory:

DataSourceFactory.create(name, jta, driverOrDataSourceClass,
propertiesInString, waittime, evictionTimeout, evictableTimeout)

If you don't use JTA compatible datasource you can just use dbcp. If
you prefer just use
SystemInstance.get().getComponent(DataSourceCreator.class). The API is
maybe easier.
Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau



2014-03-16 21:31 GMT+01:00 onyii5119 <on...@gmail.com>:
> Are you saying that the only way it can work is for resources to be defined
> in resources.xml or tomee.xml? In other words using properties and reading
> the datasource params from a db will not work?
>
> Thanks,
> Jonathan
>
>
>
>
>
> --
> View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668235.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by onyii5119 <on...@gmail.com>.
Are you saying that the only way it can work is for resources to be defined
in resources.xml or tomee.xml? In other words using properties and reading
the datasource params from a db will not work?

Thanks,
Jonathan





--
View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668235.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by Romain Manni-Bucau <rm...@gmail.com>.
your postconstruct is where you define resources? it is just useless
actually. Resources are defined in resources.xml or tomee.xml

all you do with it is to start another container or nothing depending
the environment
Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau



2014-03-16 21:10 GMT+01:00 onyii5119 <on...@gmail.com>:
> I did what you are suggesting before posting my request.
>
> Please find my code and see if you could identify what is wrong with my code
> (it is a simple example)
>
> public class DeterminedRouter extends AbstractRouter implements Serializable
> {
>         private static final long serialVersionUID = -4973022035526665822L;
>         final Logger log = LoggerFactory.getLogger(this.getClass());
>
>     private String dataSourceNames;
>     private String defaultDataSourceName;
>     private Map<String, DataSource> dataSources = null;
>     private ThreadLocal<DataSource> currentDataSource = new
> ThreadLocal<DataSource>();
>
>         /**
>          *
>          */
>         public DeterminedRouter() {
>         }
>
>     /**
>      * @param datasourceList datasource resource name, separator is a space
>      */
>     public void setDataSourceNames(String datasourceList) {
>         dataSourceNames = datasourceList;
>     }
>
>     /**
>      * lookup datasource in openejb resources
>      */
>     private void init() {
>         dataSources = new ConcurrentHashMap<String, DataSource>();
>         for (String ds : dataSourceNames.split(" ")) {
>             try {
>                 Object o = getOpenEJBResource(ds);
>                 if (o instanceof DataSource) {
>                     dataSources.put(ds, DataSource.class.cast(o));
>                 }
>             }catch (NamingException e) {
>                 e.printStackTrace();
>             }
>         }
>     }
>
>     /**
>      * @return the user selected data source if it is set
>      *         or the default one
>      *  @throws IllegalArgumentException if the data source is not found
>      */
>     @Override
>     public DataSource getDataSource() {
>         // lazy init of routed datasources
>         if (dataSources == null) {
>             init();
>         }
>
>         // if no datasource is selected use the default one
>         if (currentDataSource.get() == null) {
>             if (dataSources.containsKey(defaultDataSourceName)) {
>                 return dataSources.get(defaultDataSourceName);
>
>             } else {
>                 throw new IllegalArgumentException("you have to specify at
> least one datasource");
>             }
>         }
>
>         // the developper set the datasource to use
>         return currentDataSource.get();
>     }
>
>     /**
>      *
>      * @param datasourceName data source name
>      */
>     public void setDataSource(String datasourceName) {
>         if (dataSources == null) {
>             init();
>         }
>         if (!dataSources.containsKey(datasourceName)) {
>             throw new IllegalArgumentException("data source called " +
> datasourceName + " can't be found.");
>         }
>         DataSource ds = dataSources.get(datasourceName);
>         currentDataSource.set(ds);
>     }
>
>     /**
>      * reset the data source
>      */
>     public void clear() {
>         currentDataSource.remove();
>     }
>
>     public void setDefaultDataSourceName(String name) {
>         this.defaultDataSourceName = name;
>     }
>
> }
>
> ////////////////////////////////////////////////////////////////
>
> @Stateless
> public class RoutedPersister implements Serializable {
>         private static final long serialVersionUID = -4630430944530409705L;
>         final Logger log = LoggerFactory.getLogger(this.getClass());
>
>     @Resource(name="TsRouter", type = DeterminedRouter.class)
>     private DeterminedRouter router;
>
>         @PersistenceContext(unitName = "router")
>     private EntityManager em;
>
>         private RoutedPersister routedPersister;
>
>         private String[] databases;
>         private Properties properties;
>
>
>         /**
>          *
>          */
>         public RoutedPersister() {
>         }
>
>         @PostConstruct
>         public void init(){
>                 try{
>                     databases = new String[]{"db1", "db2", "db3"};
>
>                     properties = new Properties();
>                     properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
> LocalInitialContextFactory.class.getName());
>
>                     // resources
>                     // datasources
>                     for (int i = 1; i <= databases.length; i++) {
>                         String dbName = databases[i - 1];
>                         properties.setProperty(dbName, "new://Resource?type=DataSource");
>                         dbName += ".";
>                         properties.setProperty(dbName + "JdbcDriver",
> "com.mysql.jdbc.Driver");
>                         properties.setProperty(dbName + "JdbcUrl",
> "jdbc:mysql://domain.com:3306/" + i);
>                         properties.setProperty(dbName + "UserName", "username");
>                         properties.setProperty(dbName + "Password", "password");
>                         properties.setProperty(dbName + "JtaManaged", "true");
>                     }
>
>                     // router
>                     properties.setProperty("TsRouter",
> "new://Resource?provider=org.router:DeterminedRouter&type=" +
> DeterminedRouter.class.getName());
>                     properties.setProperty("TsRouter.DatasourceNames", "db1 db2 db3");
>                     properties.setProperty("TsRouter.DefaultDataSourceName", "db1");
>
>                     // routed datasource
>                     properties.setProperty("Routed Datasource",
> "new://Resource?provider=RoutedDataSource&type=" + Router.class.getName());
>                     properties.setProperty("Routed Datasource.Router", "TsRouter");
>
>                     Context ctx =
> EJBContainer.createEJBContainer(properties).getContext();
>                     routedPersister = (RoutedPersister)
> ctx.lookup("java:global/dynamic-datasource-routing/RoutedPersister");
>
>                 }catch(Exception e){
>                         e.printStackTrace();
>                 }
>         }
>
>     public RoutedPersister getRoutedPersister() {
>                 return routedPersister;
>         }
>
>         public void setRoutedPersister(RoutedPersister routedPersister) {
>                 this.routedPersister = routedPersister;
>         }
>
>         public void persist(int id, String name, String ds) {
>         router.setDataSource(ds);
> //        em.persist(new Person(id, name));
>     }
>
> }
>
> ////////////////////////////////////////////////////////////////////////////
>
> <?xml version="1.0" encoding="UTF-8"?>
> <ServiceJar>
>
>         <ServiceProvider id="TsRouter"
>         service="Resource"
>         type="org.apache.openejb.resource.jdbc.Router"
>         class-name="test.datasources.DeterminedRouter"
>         >
>
>         # the parameters
>
>         DataSourceNames
>         DefaultDataSourceName
>         </ServiceProvider>
> </ServiceJar>
>
> I placed this file in WEB-INF/classes/META-INF/org.router/service-jar.xml
>
> When I run it I get the following error message:
>
> Mar 16, 2014 4:07:23 PM org.apache.tomee.catalina.TomcatWebAppBuilder
> startInternal
> SEVERE: Unable to deploy collapsed ear in war
> StandardEngine[Catalina].StandardHost[l
> ocalhost].StandardContext[/rls]
> org.apache.openejb.OpenEJBException: Can't find resource for class
> test.datas
> ources.RoutedPersister#router. (No provider available for resource-ref
> 'null' of type
>  'test.datasources.DeterminedRouter' for 'rls.Comp1509825954'.)
>         at
> org.apache.openejb.config.AutoConfig.processResourceRef(AutoConfig.java:11
> 74)
>         at org.apache.openejb.config.AutoConfig.deploy(AutoConfig.java:858)
>         at org.apache.openejb.config.AutoConfig.deploy(AutoConfig.java:193)
>         at
> org.apache.openejb.config.ConfigurationFactory$Chain.deploy(ConfigurationF
> actory.java:396)
>         at
> org.apache.openejb.config.ConfigurationFactory.configureApplication(Config
> urationFactory.java:938)
>         at
> org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBu
> ilder.java:1171)
>         at
> org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppB
> uilder.java:1051)
>         at
> org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListe
> nerSupport.java:127)
>         at
> org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupp
> ort.java:119)
>         at
> org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.ja
>
>
>
> --
> View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668232.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by onyii5119 <on...@gmail.com>.
I did what you are suggesting before posting my request.

Please find my code and see if you could identify what is wrong with my code
(it is a simple example)

public class DeterminedRouter extends AbstractRouter implements Serializable
{
	private static final long serialVersionUID = -4973022035526665822L;
	final Logger log = LoggerFactory.getLogger(this.getClass());	

    private String dataSourceNames;
    private String defaultDataSourceName;
    private Map<String, DataSource> dataSources = null;
    private ThreadLocal<DataSource> currentDataSource = new
ThreadLocal<DataSource>();

	/**
	 * 
	 */
	public DeterminedRouter() {
	}

    /**
     * @param datasourceList datasource resource name, separator is a space
     */
    public void setDataSourceNames(String datasourceList) {
        dataSourceNames = datasourceList;
    }

    /**
     * lookup datasource in openejb resources
     */
    private void init() {
        dataSources = new ConcurrentHashMap<String, DataSource>();
        for (String ds : dataSourceNames.split(" ")) {
            try {
                Object o = getOpenEJBResource(ds);
                if (o instanceof DataSource) {
                    dataSources.put(ds, DataSource.class.cast(o));
                }
            }catch (NamingException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @return the user selected data source if it is set
     *         or the default one
     *  @throws IllegalArgumentException if the data source is not found
     */
    @Override
    public DataSource getDataSource() {
        // lazy init of routed datasources
        if (dataSources == null) {
            init();
        }

        // if no datasource is selected use the default one
        if (currentDataSource.get() == null) {
            if (dataSources.containsKey(defaultDataSourceName)) {
                return dataSources.get(defaultDataSourceName);

            } else {
                throw new IllegalArgumentException("you have to specify at
least one datasource");
            }
        }

        // the developper set the datasource to use
        return currentDataSource.get();
    }

    /**
     *
     * @param datasourceName data source name
     */
    public void setDataSource(String datasourceName) {
        if (dataSources == null) {
            init();
        }
        if (!dataSources.containsKey(datasourceName)) {
            throw new IllegalArgumentException("data source called " +
datasourceName + " can't be found.");
        }
        DataSource ds = dataSources.get(datasourceName);
        currentDataSource.set(ds);
    }

    /**
     * reset the data source
     */
    public void clear() {
        currentDataSource.remove();
    }

    public void setDefaultDataSourceName(String name) {
        this.defaultDataSourceName = name;
    }

}

////////////////////////////////////////////////////////////////

@Stateless
public class RoutedPersister implements Serializable {
	private static final long serialVersionUID = -4630430944530409705L;
	final Logger log = LoggerFactory.getLogger(this.getClass());	

    @Resource(name="TsRouter", type = DeterminedRouter.class)
    private DeterminedRouter router;
	
	@PersistenceContext(unitName = "router")
    private EntityManager em;
	
	private RoutedPersister routedPersister;
	
	private String[] databases;
	private Properties properties;
	
    
	/**
	 * 
	 */
	public RoutedPersister() {
	}

	@PostConstruct
	public void init(){
		try{
		    databases = new String[]{"db1", "db2", "db3"};

		    properties = new Properties();
		    properties.setProperty(Context.INITIAL_CONTEXT_FACTORY,
LocalInitialContextFactory.class.getName());

		    // resources
		    // datasources
		    for (int i = 1; i <= databases.length; i++) {
		        String dbName = databases[i - 1];
		        properties.setProperty(dbName, "new://Resource?type=DataSource");
		        dbName += ".";
		        properties.setProperty(dbName + "JdbcDriver",
"com.mysql.jdbc.Driver");
		        properties.setProperty(dbName + "JdbcUrl",
"jdbc:mysql://domain.com:3306/" + i);
		        properties.setProperty(dbName + "UserName", "username");
		        properties.setProperty(dbName + "Password", "password");
		        properties.setProperty(dbName + "JtaManaged", "true");
		    }

		    // router
		    properties.setProperty("TsRouter",
"new://Resource?provider=org.router:DeterminedRouter&type=" +
DeterminedRouter.class.getName());
		    properties.setProperty("TsRouter.DatasourceNames", "db1 db2 db3");
		    properties.setProperty("TsRouter.DefaultDataSourceName", "db1");

		    // routed datasource
		    properties.setProperty("Routed Datasource",
"new://Resource?provider=RoutedDataSource&type=" + Router.class.getName());
		    properties.setProperty("Routed Datasource.Router", "TsRouter");

		    Context ctx =
EJBContainer.createEJBContainer(properties).getContext();
		    routedPersister = (RoutedPersister)
ctx.lookup("java:global/dynamic-datasource-routing/RoutedPersister");
			
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
    public RoutedPersister getRoutedPersister() {
		return routedPersister;
	}

	public void setRoutedPersister(RoutedPersister routedPersister) {
		this.routedPersister = routedPersister;
	}

	public void persist(int id, String name, String ds) {
        router.setDataSource(ds);
//        em.persist(new Person(id, name));
    }

}

////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="UTF-8"?>
<ServiceJar>
	
  	<ServiceProvider id="TsRouter" 
     	service="Resource"
      	type="org.apache.openejb.resource.jdbc.Router"
      	class-name="test.datasources.DeterminedRouter"
      	> 

    	# the parameters

    	DataSourceNames
    	DefaultDataSourceName
  	</ServiceProvider>
</ServiceJar>

I placed this file in WEB-INF/classes/META-INF/org.router/service-jar.xml

When I run it I get the following error message:

Mar 16, 2014 4:07:23 PM org.apache.tomee.catalina.TomcatWebAppBuilder
startInternal
SEVERE: Unable to deploy collapsed ear in war
StandardEngine[Catalina].StandardHost[l
ocalhost].StandardContext[/rls]
org.apache.openejb.OpenEJBException: Can't find resource for class
test.datas
ources.RoutedPersister#router. (No provider available for resource-ref
'null' of type
 'test.datasources.DeterminedRouter' for 'rls.Comp1509825954'.)
        at
org.apache.openejb.config.AutoConfig.processResourceRef(AutoConfig.java:11
74)
        at org.apache.openejb.config.AutoConfig.deploy(AutoConfig.java:858)
        at org.apache.openejb.config.AutoConfig.deploy(AutoConfig.java:193)
        at
org.apache.openejb.config.ConfigurationFactory$Chain.deploy(ConfigurationF
actory.java:396)
        at
org.apache.openejb.config.ConfigurationFactory.configureApplication(Config
urationFactory.java:938)
        at
org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBu
ilder.java:1171)
        at
org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppB
uilder.java:1051)
        at
org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListe
nerSupport.java:127)
        at
org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupp
ort.java:119)
        at
org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.ja



--
View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668232.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by Romain Manni-Bucau <rm...@gmail.com>.
I don't get the difference, remove the datasource parameter and that's
the same. You can take this project it is self contained.
Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau



2014-03-16 20:36 GMT+01:00 onyii5119 <on...@gmail.com>:
> Thanks Romain. Not exactly what I am looking for. In your case the
> datasources are hard coded in resources. I want the datasources to be
> generated dynamically. In which case the params will be read from a
> database. All I am looking for is a simple example that works, zip it up
> then I can try.
>
> Thanks again.
> Jonathan
>
>
>
>
> --
> View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668230.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by onyii5119 <on...@gmail.com>.
Thanks Romain. Not exactly what I am looking for. In your case the
datasources are hard coded in resources. I want the datasources to be
generated dynamically. In which case the params will be read from a
database. All I am looking for is a simple example that works, zip it up
then I can try.

Thanks again.
Jonathan




--
View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668230.html
Sent from the OpenEJB User mailing list archive at Nabble.com.

Re: Dynamic DataSource - Exception

Posted by Romain Manni-Bucau <rm...@gmail.com>.
well if you don't want to look the doc prepare a ready to run sample
with your conf showing it fails (mvn package tomee:run).

btw this sample has it
http://svn.apache.org/repos/asf/tomee/tomee/trunk/examples/polling-parent/polling-web/
( http://svn.apache.org/repos/asf/tomee/tomee/trunk/examples/polling-parent/polling-web/src/main/java/jug/routing/
) and here resources definitions
http://svn.apache.org/repos/asf/tomee/tomee/trunk/examples/polling-parent/polling-web/src/main/resources/META-INF/resources.xml
Romain Manni-Bucau
Twitter: @rmannibucau
Blog: http://rmannibucau.wordpress.com/
LinkedIn: http://fr.linkedin.com/in/rmannibucau
Github: https://github.com/rmannibucau



2014-03-16 19:30 GMT+01:00 onyii5119 <on...@gmail.com>:
> Does anyone have a simple *working example* of dynamic dataSource I can learn
> from? Don't point me to documentations, I tried most and they don't work for
> me.
>
> Thanks.
>
>
>
> --
> View this message in context: http://openejb.979440.n4.nabble.com/Dynamic-DataSource-Exception-tp4657657p4668226.html
> Sent from the OpenEJB User mailing list archive at Nabble.com.