JBoss - .properties vom Kunden änderbar machen

Diskutiere JBoss - .properties vom Kunden änderbar machen im Application Tier Forum; Hi! Folgende Sachlage: Ich habe hier einen JBoss AS 7.1.1 und eine Webapplikation (Spring, Hibernate, JSON, JQuery) und nun habe ich die Aufgabe...

  1. springMe
    springMe Guest
    Hi!
    Folgende Sachlage:
    Ich habe hier einen JBoss AS 7.1.1 und eine Webapplikation (Spring, Hibernate, JSON, JQuery) und nun habe ich die Aufgabe dass gewisse .properties Dateien vom Kunden adaptiert werden wollen. Sprich die .properties nichts in .war sondern ins Filesystem oder dergleichen, hierbei kommt aber hinzu dass die Applikation beim Kunden natürlich in einem Cluster läuft.

    Hat hiermit schon jemand Erfahrungen gemacht und kann mir einen Tipp geben?

    Natürlich gibt es JBoss Modules (MBean?) jedoch dürfte das auch nicht so ohne weiteres im Cluster funktionieren? Ein shared directory kommt leider auch nicht in Frage somit habe ich noch eine andere Variante in Betracht gezogen, nämlich in der Applikation eine Adminseite zur Verfügung zu stellen wo div. Properties ausgelesen und verändert werden können. Hierbei gibts aber natürlich auch Probleme, nämlich dass beim restart des JBoss dann alle Änderungen an den .properties obsolet, weil nicht mehr vorhanden, wären da der JBoss anscheinend nicht "physisch" deployed? D.h. nach dem restart sind wieder die .properties vom .war die aktuellesten da selbige ja nicht wirklich überschrieben wurden.

    Nun habe ich mir gedacht dann lege ich die .properties (jene die vom Kunden änderbar sein sollen sind eh in einem überschaubaren Rahmen) einfach in die Datenbank. Hierbei gibts natürlich wieder das Problem dass manche dieser Properties in der applicationContext.xml vom Spring benötigt werden und ich hierbei sicher nicht auf die Datenbank zugreifen kann?

    Bin für alle Vorschläge offen.
     
  2. Vielleicht hilft dir dieser Kurs hier weiter --> (hier klicken)
  3. FArt
    FArt Neues Mitglied
    Die Konfiguration sollte über einen Service geschehen. Vermutlich ist es tatsächlich das einfachste, diese Werte in einer DB zu halten. Von irgendwelchen Workarounds mit Propertiesdateien rate ich ab.
     
  4. y0dA
    y0dA Neues Mitglied
    Wäre auch dafür sie in der Datenbank abzulegen, nur wie kann ich dann in der applicationContext.xml darauf zugreifen? Habe im Netz ein paar uralt Beispiele gesehen, kann mir aber nicht vorstellen dass es da nicht eine aktueller Art der Verwendung gibt?

    Sprich wie kann ich die Properties aus der Datenbank hier hinzufügen:
    Code (Java):

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="locations">
                <list>
                    <value>classpath:database.properties</value>
                    <value>classpath:configuration.properties</value>
                    <value>classpath:mail.properties</value>
                </list>
            </property>
     
     
  5. FArt
    FArt Neues Mitglied
    Du musst nur eine Implementierung von PropertyPlaceholderConfigurer implementieren (evtl. davon ableiten), die Properties aus deiner alternativen Quelle (z.B. DB) ermittelt.
     
  6. y0dA
    y0dA Neues Mitglied
    Code (Java):

    public class JdbcPropertyPlaceholderConfigurer extends
            PropertyPlaceholderConfigurer {

        private Logger log = Logger
                .getLogger(JdbcPropertyPlaceholderConfigurer.class);

        private JdbcTemplate jdbcTemplate;

        private String nameColumn;

        private String valueColumn;

        private String propertiesTable;

        /**
         * Provide a different prefix
         */

        public JdbcPropertyPlaceholderConfigurer() {
            super();
            setPlaceholderPrefix("#{");
        }

        @Override
        protected void loadProperties(final Properties props) throws IOException {
            if (null == props) {
                throw new IOException(
                        "No properties passed by Spring framework - cannot proceed");
            }
            String sql = String.format("select %s, %s from %s", nameColumn,
                    valueColumn, propertiesTable);
            log.info("Reading configuration properties from database");
            try {
                jdbcTemplate.query(sql, new RowCallbackHandler() {

                    public void processRow(ResultSet rs) throws SQLException {
                        String name = rs.getString(nameColumn);
                        String value = rs.getString(valueColumn);
                        if (null == name || null == value) {
                            throw new SQLException(
                                    "Configuration database contains empty data. Name='"
                                            + name + "' Value='" + value + "'");
                        }
                        props.setProperty(name, value);
                    }

                });
            } catch (Exception e) {
                log.fatal("There is an error in either 'application.properties' or the configuration database.");
                throw new IOException(e);
            }
            if (props.size() == 0) {
                log.fatal("The configuration database could not be reached or does not contain any properties in '"
                        + propertiesTable + "'");
            }
        }

        public void setJdbcTemplate(DataSource dataSource) {
            this.jdbcTemplate = new JdbcTemplate(dataSource);
        }

        // public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        // this.jdbcTemplate = jdbcTemplate;
        // }

        public void setNameColumn(String nameColumn) {
            this.nameColumn = nameColumn;
        }

        public void setValueColumn(String valueColumn) {
            this.valueColumn = valueColumn;
        }

        public void setPropertiesTable(String propertiesTable) {
            this.propertiesTable = propertiesTable;
        }
    }
     
    applicationContext.xml snippet:
    [XML]
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
    <list>
    <value>classpath:database.properties</value>
    </list>
    </property>
    </bean>

    <bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="myPersistenceUnit" />
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"/>
    <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="databasePlatform" value="org.hibernate.dialect.SQLServerDialect" />
    <property name="showSql" value="false" />
    <property name="generateDdl" value="false" />
    </bean>
    </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
    <property name="driverClass" value="${database.driverClassName}" />
    <property name="jdbcUrl" value="${database.url}" />
    <property name="user" value="${database.username}" />
    <property name="password" value="${database.password}" />
    <!-- C3P0 connection pool configuration -->
    <property name="minPoolSize" value="5" />
    <property name="maxPoolSize" value="50" />
    <property name="initialPoolSize" value="10" />
    <property name="checkoutTimeout" value="0" />
    <property name="maxStatements" value="50" />
    <property name="maxIdleTime" value="300" />
    </bean>

    <!-- Enable configuration through the JDBC configuration with fall-through
    to framework.properties -->
    <bean id="jdbcProperties" class="com.myproject.persistence.JdbcPropertyPlaceholderConfigurer">
    <property name="ignoreUnresolvablePlaceholders" value="false" />
    <property name="order" value="2" />
    <property name="nameColumn" value="propKey" />
    <property name="valueColumn" value="propValue" />
    <property name="propertiesTable" value="prop_configuration" />
    <property name="jdbcTemplate" ref="dataSource" />
    </bean>
    [/XML]

    Exception beim ausführen der Query:
    Code (Java):

    org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.IOException: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Connections could not be acquired from the underlying database!
        at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:87)
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:681)
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:656)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:446)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4135)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:4630)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
        at org.apache.catalina.core.StandardHost.start(StandardHost.java:785)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
        at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:445)
        at org.apache.catalina.startup.Embedded.start(Embedded.java:825)
        at org.codehaus.mojo.tomcat.AbstractRunMojo.startContainer(AbstractRunMojo.java:558)
        at org.codehaus.mojo.tomcat.AbstractRunMojo.execute(AbstractRunMojo.java:255)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:320)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:601)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
    Caused by: java.io.IOException: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Connections could not be acquired from the underlying database!
        at com.myproject.persistence.JdbcPropertyPlaceholderConfigurer.loadProperties(JdbcPropertyPlaceholderConfigurer.java:73)
        at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.java:161)
        at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:78)
        ... 36 more
    Caused by: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Connections could not be acquired from the underlying database!
        at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:382)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:456)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:460)
        at com.myproject.persistence.JdbcPropertyPlaceholderConfigurer.loadProperties(JdbcPropertyPlaceholderConfigurer.java:57)
        ... 38 more
    Caused by: java.sql.SQLException: Connections could not be acquired from the underlying database!
        at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
        at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:529)
        at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
        at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
        at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
        ... 42 more
    Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
        at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1319)
        at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
        at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
        at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
        ... 45 more
     
    Ich glaub die Bean "dataSource" gibts zu dem Zeitpunkt noch gar nicht?
     
    Zuletzt bearbeitet: 19. Nov. 2012
  7. FArt
    FArt Neues Mitglied
    Davon würde ich ausgehen. Die Properties werden in der Initialisierungsphase gesetzt. Da kann man mit den Beans natürlich noch nicht arbeiten. Regel den Zugriff direkt, ohne Springbeans, die gerade erst mal initialisiert sind.
     
  8. y0dA
    y0dA Neues Mitglied
    Das Problem liegt hierbei aber dass die Datenbank Sachen (url,driver,user,pwd) in einem separaten .properties File liegen und auf selbiges kann ich aber, zu dem Zeitpunkt, anscheinend auch noch nicht zugreifen. Hatte folgendes probiert:

    Code (Java):
        <bean id="jdbcProperties" class="com.myproject.persistence.JdbcPropertyPlaceholderConfigurer">
            <property name="ignoreUnresolvablePlaceholders" value="false" />
            <property name="order" value="2" />
            <property name="nameColumn" value="propKey" />
            <property name="valueColumn" value="propValue" />
            <property name="propertiesTable" value="prop_configuration" />
            <property name="driverClass" value="${database.driverClassName}" />
            <property name="jdbcUrl" value="${database.url}" />
            <property name="user" value="${database.username}" />
            <property name="password" value="${database.password}" />
        </bean>
     
    In der Klasse stehen dann in den jeweiligen String Objekten nicht der Value des Properties drinnen sondern bspw. "${database.password}"..

    Abgesehen davon mit welcher Klasse soll ich "DataSource" initialisieren? "BasicDataSource" hab ich nicht im classpath..DriverManagerDataSource?

    Und abschliessend muss ich dann diese von der db geladenen properties so adden?
    Code (Java):
        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="locations">
                <list>
                    <value>classpath:database.properties</value>
                    <value>classpath:configuration.properties</value>
                    <ref bean="jdbcProperties"/>
                </list>
            </property>
        </bean>
     
    Zuletzt bearbeitet: 19. Nov. 2012
  9. y0dA
    y0dA Neues Mitglied
    Ok bin wohl ein wenig durcheinander gekommen. Oben extende ich ja von PropertyPlaceholderConfigurer und versuche dann selbige Bean dem PropertyPlaceholderConfigurer hinzuzufügen - kann nicht funktionieren.

    Was ist nun die bessere Herangehensweise, soll ich quasi PropertyPlaceholderConfigurer überschreiben (wie soll ich das umsetzen, will ja paar properties aus der DB und ein paar von anderen .properties Dateien; weiters sollen die geladenen Properties natürlich in der applicationContext.xml schon verfügbar sein damit mir die Platzhalter "${xyz}" überschrieben werden.

    Oder soll ich versuchen dem PropertyPlaceholderConfigurer einfach meine Klasse, welche die properties aus der DB holt, unter locations hinzuzufügen? Nur wovon muss da meiner Klasse erben?
     
  10. FArt
    FArt Neues Mitglied
    Prinzipiell kannst du glaube ich beides machen. Ich denke du kannst mehrere PlaceholderConfigurer anbieten, die dann der Reihe nach ihre Arbeit verrichten. So lange die dort hinterlegten Properties disjunkt sind, ist das gar kein Thema, sonst ersetzt halt der erste.

    Aber du kannst auch mit einer Ableitung dafür sorgen, dass ein Configurer alle Properties aus verschiedenen Quellen ersetzt.
     
  11. y0dA
    y0dA Neues Mitglied
    Könntest du mal bitte bissl konkreter werden, ich stehe hier einfach an. Oben genannter Code funktioniert einfach nicht..
    Du meinst ich kann einfach den bisherigen PlaceholderConfigurer so lassen und darunter einfach noch einen (Also eine weitere bean) definieren welcher dann mein JdbcPlaceholderConfigurer ist? Den anderen Weg schaffe ich nicht weil ich nicht weiß von welcher Klasse ich ableiten muss damit der Compiler nicht meckert ;)
     
    Zuletzt bearbeitet: 19. Nov. 2012
Die Seite wird geladen...

JBoss - .properties vom Kunden änderbar machen - Ähnliche Themen

Properties-File in Jboss-Conf Verzeichnis ansprechen
Properties-File in Jboss-Conf Verzeichnis ansprechen im Forum Allgemeines EE
Eclipse: JBoss Hibernate Tool: Kein Zugriff auf Datenbank
Eclipse: JBoss Hibernate Tool: Kein Zugriff auf Datenbank im Forum Datenbankprogrammierung
EJBs und Callbacks (Jboss 7.1)
EJBs und Callbacks (Jboss 7.1) im Forum Allgemeines EE
"localhost" zu DNS (z.B. my webapp.de) ändern bei JBoss / Wildfly
"localhost" zu DNS (z.B. my webapp.de) ändern bei JBoss / Wildfly im Forum Server einrichten und konfigurieren
JBoss H2 Database
JBoss H2 Database im Forum Data Tier
Thema: JBoss - .properties vom Kunden änderbar machen