Schlagwörter: Spring Kommentarverlauf ein-/ausschalten | Tastaturkürzel

  • Andreas Höhmann 0:53 am Tuesday, 16. July 2013 Permalink |
    Tags: Neo4j, Spring   

    Lets play with neo4j 

    Der „Leipziger Firmenlauf 2013“ ist nun auch langsam Geschichte. Doch als ich heute nochmals durch die Ergebnisse stöberte, kam ich auf die Idee die Daten doch einfach mal in eine „NoSQL“ Datenbank, in meinem Fall jetzt mal Neo4j, zu importieren.

    Also gesagt getan, das Besorgen der Daten ist ein Kinderspiel. Die Homepage liefert alle gewünschten Datensätze per JSON, im Chrome die „CURL“ kopieren, auf Kommandozeile ausführen, in eine Datei umleiten … fertig 🙂

    $ curl 'http://results.davengo.com/query' -H 'Origin: http://results.davengo.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Host: results.davengo.com' -H 'Accept-Language: en,de;q=0.8
    ,en-US;q=0.6' -H 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36' -H 'Content-Type: application/json' -H 
    'Accept: */*' -H 'Referer: http://results.davengo.com/?event=50d426afb8ed1d2318282f54' -H 'Cookie: __utma=9661994.565730006.1373516179.1373516179.1373909845.2; __utmb=9661994.2.10.1373909845; 
    __utmc=9661994; __utmz=9661994.1373909845.2.2.utmcsr=leipzig-firmenlauf.de|utmccn=(referral)|utmcmd=referral|utmcct=/ergebnisse2013.html; 
    __utma=268406157.662336661.1373516307.1373516307.1373909929.2; __utmb=268406157.1.10.1373909929; __utmc=268406157; __utmz=268406157.1373516307.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); 
    projekktorplayercontrolbar_volume=0.5' -H 'Connection: keep-alive' --data-binary '{"key":"50d426afb8ed1d2318282f54", "offset":0, "limit":100000, "where":{"categoryName":"Einzelwertung"}, "order":
    {"firma":"ASC"}, "category":"Einzelwertung"}' --compressed > results_2013.json
    

    Jetzt kommt der „schwierige“ Part, JSON parsen und via Spring Data Neo4j in eine Neo4j Datenbank einfügen.

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<groupId>com.mymita.tools</groupId>
    	<artifactId>firmenlauf2013</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<dependencies>
    		<dependency>
    			<groupId>org.codehaus.jackson</groupId>
    			<artifactId>jackson-mapper-asl</artifactId>
    			<version>1.9.12</version>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.data</groupId>
    			<artifactId>spring-data-neo4j</artifactId>
    			<version>2.2.1.RELEASE</version>
    		</dependency>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    			<version>0.11.8</version>
    		</dependency>
    		<dependency>
    			<groupId>com.google.guava</groupId>
    			<artifactId>guava</artifactId>
    			<version>14.0.1</version>
    		</dependency>
    		<dependency>
    			<groupId>cglib</groupId>
    			<artifactId>cglib</artifactId>
    			<version>2.2.2</version>
    		</dependency>
    		<dependency>
    			<groupId>javax.validation</groupId>
    			<artifactId>validation-api</artifactId>
    			<version>1.1.0.Final</version>
    		</dependency>
    		<dependency>
    			<groupId>ch.qos.logback</groupId>
    			<artifactId>logback-classic</artifactId>
    			<version>1.0.13</version>
    		</dependency>
    	</dependencies>
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.apache.maven.plugins</groupId>
    				<artifactId>maven-compiler-plugin</artifactId>
    				<version>3.1</version>
    				<configuration>
    					<source>1.7</source>
    					<target>1.7</target>
    				</configuration>
    			</plugin>
    		</plugins>
    	</build>
    </project>
    

    Der Importerservice

    package com.mymita.firmenlauf2013.service;
    
    import java.io.IOException;
    import java.util.Map;
    
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    import org.codehaus.jackson.map.ObjectMapper;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.data.neo4j.support.Neo4jTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import com.google.common.base.Objects;
    import com.google.common.collect.Maps;
    import com.mymita.firmenlauf2013.model.Company;
    import com.mymita.firmenlauf2013.model.Run;
    import com.mymita.firmenlauf2013.model.Runner;
    import com.mymita.firmenlauf2013.model.Team;
    
    @Service
    public class ImportService {
    
    	@Getter
    	@AllArgsConstructor
    	@ToString
    	public static class JsonRunner {
    
    		public JsonRunner(Object[] data) {
    			this((Integer) data[0], (Integer) data[1], (Integer) data[2],
    					(Integer) data[3], (String) data[4], (String) data[5],
    					(String) data[6], (String) data[7], (String) data[8],
    					(String) data[9], (String) data[10]);
    		}
    
    		Integer platz;
    		Integer platzMaennlich;
    		Integer platzWeiblich;
    		Integer nummer;
    		String vorname;
    		String nachname;
    		String team;
    		String zeit;
    		String firma;
    		String dummy;
    		String key;
    	}
    
    	@Getter
    	@Setter
    	public static class JsonRunners {
    		Object[][] items;
    	}
    
    	Logger logger = LoggerFactory.getLogger(getClass());
    
    	@Autowired
    	private Neo4jTemplate template;
    
    	private final Map<String, Company> companies = Maps.newHashMap();
    	private final Map<String, Team> teams = Maps.newHashMap();
    	private final Map<Integer, Runner> runners = Maps.newHashMap();
    	private final Map<String, Run> runs = Maps.newHashMap();
    
    	@Transactional
    	public void importData() {
    		try {
    			JsonRunners jsonRunners = new ObjectMapper().readValue(
    					new ClassPathResource("results.json").getInputStream(),
    					JsonRunners.class);
    			for (int i = 0; i < jsonRunners.items.length; i++) {
    				JsonRunner jsonRunner = new JsonRunner(jsonRunners.items[i]);
    				String teamName = jsonRunner.getTeam();
    				String companyName = jsonRunner.getFirma();
    				String time = jsonRunner.getZeit();
    				Company company = companies.get(companyName);
    				if (company == null) {
    					company = new Company(Objects.firstNonNull(companyName,
    							"NONAME"));
    					template.save(company);
    					companies.put(company.getName(), company);
    					logger.debug("Created company '{}'", company);
    				}
    				Team team = teams.get(teamName);
    				if (team == null) {
    					team = new Team(teamName).sponsoredBy(company);
    					template.save(team);
    					teams.put(team.getName(), team);
    					logger.debug("Created team '{}'", team);
    				}
    				Run run = runs.get(time);
    				if (run == null) {
    					run = new Run(time);
    					template.save(run);
    					runs.put(run.getTime(), run);
    					logger.debug("Created run '{}'", run);
    				}
    				Runner runner = new Runner(jsonRunner.getNummer(),
    						jsonRunner.getVorname(), jsonRunner.getNachname())
    						.fightFor(team).finished(run);
    				template.save(runner);
    				runners.put(runner.getNumber(), runner);
    				logger.debug("Created runner '{}'", runner);
    			}
    			for (Team t : teams.values()) {
    				template.save(t);
    				logger.debug("Updated team '{}'", t);
    			}
    			for (Run r : runs.values()) {
    				template.save(r);
    				logger.debug("Updated run '{}'", r);
    			}
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    Der Spring Context

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:neo4j="http://www.springframework.org/schema/data/neo4j"
    	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    		                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    		                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    		                http://www.springframework.org/schema/data/neo4j http://www.springframework.org/schema/data/neo4j/spring-neo4j.xsd">
    	<neo4j:repositories base-package="com.mymita.firmenlauf2013" />
    	<neo4j:config graphDatabaseService="graphDatabaseService" />
    	<bean id="graphDatabaseService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
    		destroy-method="shutdown">
    		<constructor-arg value="target/firmenlauf2013.db" />
    	</bean>
    	<context:annotation-config />
    	<context:component-scan base-package="com.mymita.firmenlauf2013" />
    	<tx:annotation-driven mode="proxy"
    		transaction-manager="transactionManager" />
    </beans>
    

    Und ein kleines Hauptprogramm um alles zu starten

    package com.mymita.firmenlauf2013.importer;
    
    import java.io.File;
    import java.io.IOException;
    
    import org.neo4j.kernel.impl.util.FileUtils;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.mymita.firmenlauf2013.service.ImportService;
    
    public class Importer {
    
    	public static void main(String[] args) throws IOException {
    		FileUtils.deleteRecursively(new File("target/firmenlauf2013.db"));
    		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
    				"classpath:application-context.xml");
    		try {
    			new Importer().importData(ctx);
    		} finally {
    			ctx.close();
    		}
    	}
    
    	private void importData(ClassPathXmlApplicationContext ctx) {
            ctx.getBean(ImportService.class).importData();
        }
    
    }
    

    Die NodeEntites sehen folgendermassen aus …

    package com.mymita.firmenlauf2013.model;
    
    import lombok.ToString;
    import org.springframework.data.neo4j.annotation.GraphId;
    
    @ToString
    public abstract class AbstractEntity {
    
    	@GraphId
    	private Long id;
    
    	public Long getId() {
    		return id;
    	}
    
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj) {
    			return true;
    		}
    		if (id == null || obj == null || !getClass().equals(obj.getClass())) {
    			return false;
    		}
    		return id.equals(((AbstractEntity) obj).id);
    	}
    
    	@Override
    	public int hashCode() {
    		return id == null ? 0 : id.hashCode();
    	}
    }
    

    Die Firma für die ein Team von Läufern startete

    package com.mymita.firmenlauf2013.model;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import org.springframework.data.annotation.TypeAlias;
    import org.springframework.data.neo4j.annotation.Indexed;
    import org.springframework.data.neo4j.annotation.NodeEntity;
    
    @Getter
    @NoArgsConstructor
    @ToString(callSuper=true)
    @NodeEntity
    @TypeAlias("Company")
    public class Company extends AbstractEntity {
    
        @Indexed(unique=true)
        private String name;
    
        public Company(String name) {
    		this.name = name;
    	}
    
    }
    

    Das Team von Läufern

    package com.mymita.firmenlauf2013.model;
    import java.util.Set;
    
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import org.springframework.data.annotation.TypeAlias;
    import org.springframework.data.neo4j.annotation.Indexed;
    import org.springframework.data.neo4j.annotation.NodeEntity;
    import org.springframework.data.neo4j.annotation.RelatedTo;
    
    import com.google.common.collect.Sets;
    
    @Getter
    @NoArgsConstructor
    @ToString(callSuper=true, exclude={"runners"})
    @NodeEntity
    @TypeAlias("Team")
    public class Team extends AbstractEntity {
    
        @Indexed(unique=true)
        private String name;
        @RelatedTo(type="have")
        private Set<Runner> runners = Sets.newHashSet();
        @RelatedTo(type="sponsored_by")
        private Company company;
    
        public Team(String name) {
    		this.name = name;
    	}
    
        public Team sponsoredBy(Company company) {
        	this.company = company;
        	return this;
        }
    
        public Team have(Runner runner) {
        	runners.add(runner);
        	return this;
        }
    
    }
    

    Ein Läufer

    package com.mymita.firmenlauf2013.model;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import org.springframework.data.annotation.TypeAlias;
    import org.springframework.data.neo4j.annotation.Indexed;
    import org.springframework.data.neo4j.annotation.NodeEntity;
    import org.springframework.data.neo4j.annotation.RelatedTo;
    
    @Getter
    @NoArgsConstructor
    @ToString(callSuper=true, exclude={"run", "team"})
    @NodeEntity
    @TypeAlias("Runner")
    public class Runner extends AbstractEntity{
    
        @Indexed(numeric=true,unique=true)
        private Integer number;
        @Indexed
        private String firstName;
        @Indexed
        private String lastName;
        @RelatedTo(type="fight_for")
        private Team team;
        @RelatedTo(type="finished")
        private Run run;
    
        public Runner(Integer number, String firstName, String lastName) {
    		this.number = number;
    		this.firstName = firstName;
    		this.lastName = lastName;
        }
    
        public Runner fightFor(Team team) {
        	this.team=team;
        	team.have(this);
        	return this;
        }
    
        public Runner finished(Run run) {
        	this.run=run;
        	run.finishedBy(this);
        	return this;
        }
    
    }
    

    Und das Ergebnis eines Laufs

    package com.mymita.firmenlauf2013.model;
    import java.util.Set;
    
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import org.springframework.data.annotation.TypeAlias;
    import org.springframework.data.neo4j.annotation.NodeEntity;
    import org.springframework.data.neo4j.annotation.RelatedTo;
    
    import com.google.common.collect.Sets;
    
    @Getter
    @NoArgsConstructor
    @ToString(callSuper=true, exclude={"runners"})
    @NodeEntity
    @TypeAlias("Run")
    public class Run extends AbstractEntity{
    
    	private String time;
    
    	@RelatedTo(type="finished_by")
    	private Set<Runner> runners = Sets.newHashSet();
    
        public Run(String time) {
    		this.time = time;
        }
    
    	public Run finishedBy(Runner runner) {
    		runners.add(runner);
    		return this;
    	}
    }
    

    Ergebnis der ganze Mühen ist ein Verzeichnis im target Ordner des Mavenprojekts, dessen Inhalt in einen Neo4j-Server (http://www.neo4j.org/download) kopiert wird. Ist der Server hochgefahren, kann man unter http://localhost:7474 das Ergebnis bestaunen 🙂

    Eine kleine Abfrage bringt dann auch alle meine lieben Kollegen vom „Running suckz“ Team zum Vorschein

    neo4j_firmenlauf2013

     
  • Andreas Höhmann 13:46 am Friday, 31. July 2009 Permalink |
    Tags: C3PO, Connection, , , JPA, Pool, revision managment, Spring   

    I use connection pooling to fix a hibernate problem 

    Yesterday i had a problem with hibernate envers and a sql-server database and the solution was to switch from a „non pooled“ to a „pooled“ datasource with JPA/hibernate/spring.

    The problem

    I got this wonderfull stacktrace:

    Caused by: org.hibernate.exception.JDBCConnectionException: Cannot open connection
     at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:97)
     at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
     at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
     at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
     at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
     at org.hibernate.jdbc.AbstractBatcher.prepareQueryStatement(AbstractBatcher.java:161)
     at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1573)
     at org.hibernate.loader.Loader.doQuery(Loader.java:696)
     at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
     at org.hibernate.loader.Loader.doList(Loader.java:2228)
     at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125)
     at org.hibernate.loader.Loader.list(Loader.java:2120)
     at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:401)
     at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:361)
     at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196)
     at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1148)
     at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
     at org.hibernate.envers.entities.mapper.relation.lazy.initializor.AbstractCollectionInitializor.initialize(AbstractCollectionInitializor.java:62)
     at org.hibernate.envers.entities.mapper.relation.lazy.proxy.CollectionProxy.checkInit(CollectionProxy.java:47)
     at org.hibernate.envers.entities.mapper.relation.lazy.proxy.CollectionProxy.toString(CollectionProxy.java:118)
     at org.apache.commons.beanutils.converters.StringConverter.convert(StringConverter.java:57)
     at org.apache.commons.beanutils.ConvertUtilsBean.convert(ConvertUtilsBean.java:400)
     at org.apache.commons.beanutils.BeanUtilsBean.getNestedProperty(BeanUtilsBean.java:699)
     at org.apache.commons.beanutils.BeanUtilsBean.getProperty(BeanUtilsBean.java:723)
     at org.apache.commons.beanutils.BeanUtilsBean.describe(BeanUtilsBean.java:504)
     at org.apache.commons.beanutils.BeanUtils.describe(BeanUtils.java:145)
     at de.ahoehma.persistence.revision.BeanDiff.getAllProperties(BeanDiff.java:170)

    The background story

    We use envers for revision-management of persisted objects. Our application have a „changelog-view“ for change-statistics (which object changed from version A to version B, differences between these versions for each object etc.):

    changelog_table

    During the creation of the table data our code find out the changed objects (with a envers query). We use our RevisionsDaoImpl for that, i.e. the getRevisions method:

    
    @Repository
    @Transactional
    class RevisionsDaoImpl<T,KEY, REVINFO> {
    
     protected final Class<T> classOfT;
     protected EntityManager entityManager;
    
     public RevisionsDaoImpl(final Class<T> clazz) {
     super(clazz);
     }
    
     public List<Revision<T, REVINFO>> getRevisions(final int theRevisionFrom, final int theRevisionTo) {
     final AuditReader reader = ExtendedAuditReaderFactory.get(entityManager);
     AuditQuery query = reader.createQuery().forRevisionsOfEntity(classOfT, false, true);
     query = query.addOrder(AuditEntity.revisionNumber().asc());
     // all items newer or equal than theRevisionFrom
     query = query.add(AuditEntity.revisionNumber().ge(Integer.valueOf(theRevisionFrom)));
     // all items older or equal than theRevisionTo
     query = query.add(AuditEntity.revisionNumber().le(Integer.valueOf(theRevisionTo)));
     return fetchRevisions(query, reader);
     }
    
     protected List<Revision<T, REVINFO>> fetchRevisions(final AuditQuery query, final AuditReader reader) {
     try {
     final Object resultList = query.getResultList();
     final List<Object[]> queryResult = (List<Object[]>) resultList;
     final List<Revision<T, REVINFO>> result = new ArrayList<Revision<T, REVINFO>>(queryResult.size());
     for (final Object[] array : queryResult) {
     result.add(new RevisionImpl<T, REVINFO>((T) array[0], (REVINFO) array[1], (RevisionType) array[2]));
     }
     return result;
     } catch (final RevisionDoesNotExistException ex) {
     return null;
     } catch (final NoResultException ex) {
     return null;
     }
     }
     ...
    }
    
    

    In the datatable bean we are loading all revisions (from version A to version B) . Then we use org.apache.commons.beanutils.BeanUtils to get all properties from version A and B and then we compare these properties for each object. The result is the list of changed objects and all differences for each object (diffRevision(T versionA, T version B)):

    
    protected List<T> getChangeLog() {
     final List<T> result = new ArrayList<T>();
     final VersionedDao<T, Integer, RevisionInfo> dao = getRevisionsDao();
     // get all revisions from A to B for objects T
     final List<Revision<T, RevisionInfo>> revs = dao.getRevisions(fromRevision.intValue(), toRevision.intValue());
     // get A revision and B revision for each object T with revisions
     final Map<Integer, List<Revision<T, RevisionInfo>>> oldNewRevisions = dao.getOldNewRevisions(revs, fromRevision, toRevision);
     // build diff for each object
     for (final Revision rev : revs) {
     final T entity = rev.getEntity();
     final Revision<T, RevisionInfo> oldestRevision = oldNewRevisions.get(entity.getId()).get(0);
     final Revision<T, RevisionInfo> newestRevision = oldNewRevisions.get(entity.getId()).get(1);
     result.add(diffRevision(newestRevision, oldestRevision));
     }
    
    

    In the ui layer we are using rich:dataTable which have sortable columns. The above exception occured if a column-sort was triggered.

    Maybe inside hibernate or envers too many transactions or connections created and not fast enough released during the table data creation or the table rendering (lazy loaded properties may play a role in this game). Or the jdbc driver we are using is the bad guy (net.sourceforge.jtds:jtds:1.2).

    The solution

    Anyway! A workaround was to use a pooled datasource instead of a standard datasource. I found a list of pooling frameworks for hibernate here. The Hibernate  documentation contains some information too. I decide to try the 3CPO framework. Its very easy to add  a new dependency:

    
    <dependency>
     <groupId>org.hibernate</groupId>
     <artifactId>hibernate-c3p0</artifactId>
     <version>3.3.1.GA</version>
     <scope>runtime</scope>
     </dependency>
    
    

    And change the datasource:

    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${jpa.driver}" />
    <property name="url" value="${jpa.url}" />
    <property name="username" value="${jpa.username}" />
    <property name="password" value="${jpa.password}" />
    </bean>
    
    <bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="jdbcUrl" value="${jpa.url}" />
    <property name="user" value="${jpa.username}" />
    <property name="password" value="${jpa.password}" />
    <property name="initialPoolSize" value="1" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="3" />
    <property name="idleConnectionTestPeriod" value="500" />
    <property name="acquireIncrement" value="1" />
    <property name="maxStatements" value="50" />
    <property name="numHelperThreads" value="1" />
    </bean>
    
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="loadTimeWeaver">
     <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
     </property>
    <property name="dataSource" ref="pooledDataSource" />
    <property name="persistenceUnitName" value="sid-admin-web-persistence" />
    <property name="jpaVendorAdapter">
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
    <property name="showSql" value="false" />
    <property name="generateDdl" value="true" />
    <property name="databasePlatform" value="${jpa.hibernate.dialect}" />
     </bean>
     </property>
    </bean>
    
    
    <bean id=“dataSource“ class=“org.springframework.jdbc.datasource.DriverManagerDataSource“>
    <property name=“driverClassName“ value=“${jpa.driver}“ />
    <property name=“url“ value=“${jpa.url}“ />
    <property name=“username“ value=“${jpa.username}“ />
    <property name=“password“ value=“${jpa.password}“ />
    </bean>

    <bean id=“pooledDataSource“ class=“com.mchange.v2.c3p0.ComboPooledDataSource“ destroy-method=“close“>
    <description>
    Wir muessen eine „pooled data source“ benutzen weil im changelog massiv transaktionen/connections
    erzeugt werden, dies fuehrt in verbindung mit dem sql-server zu einem knappwerden der sockets und
    zu einem jdbc-error
    </description>
    <property name=“driverClass“ value=“${jpa.driver}“ />
    <property name=“jdbcUrl“ value=“${jpa.url}“ />
    <property name=“user“ value=“${jpa.username}“ />
    <property name=“password“ value=“${jpa.password}“ />
    <property name=“initialPoolSize“ value=“1″ />
    <property name=“minPoolSize“ value=“1″ />
    <property name=“maxPoolSize“ value=“3″ />
    <property name=“idleConnectionTestPeriod“ value=“500″ />
    <property name=“acquireIncrement“ value=“1″ />
    <property name=“maxStatements“ value=“50″ />
    <property name=“numHelperThreads“ value=“1″ />
    </bean>

    <bean id=“entityManagerFactory“ class=“org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean“>
    <property name=“loadTimeWeaver“>
    <bean class=“org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver“ />
    </property>
    <property name=“dataSource“ ref=“dataSource“ />
    <property name=“persistenceUnitName“ value=“sid-admin-web-persistence“ />
    <property name=“jpaVendorAdapter“>
    <bean class=“org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter“>
    <property name=“showSql“ value=“false“ />
    <property name=“generateDdl“ value=“true“ />
    <property name=“databasePlatform“ value=“${jpa.hibernate.dialect}“ />
    </bean>
    </property>
    </bean>

     
    • anshuiitk 18:45 am Donnerstag, 29. Dezember 2011 Permalink | Zum Antworten anmelden

      Hello .. I am trying to solve the same problem once more … I just stumbled upon your post .. I am trying to implement revision management for our entites using envers too …

      Can you tell me how did you generate object differences on a given object graph ?, Would it be possible to share some code docs to explain the way you implemented revision management ?. You can email me at himanshu _ kgp at gmail dot com

      • Andreas Höhmann 1:43 am Samstag, 31. Dezember 2011 Permalink | Zum Antworten anmelden

        Sorry I can’t give you any code examples … this was a commercial project for Siemens. I remember we wrote some utility methods to calculate the differences between to bean revisions but there was no „generic way“ for that. I guess Envers allows to access the changed properties per revision?!

    • bkiew 19:11 am Freitag, 20. Januar 2012 Permalink | Zum Antworten anmelden

      anshuiitk :
      Hello .. I am trying to solve the same problem once more … I just stumbled upon your post .. I am trying to implement revision management for our entites using envers too …
      Can you tell me how did you generate object differences on a given object graph ?, Would it be possible to share some code docs to explain the way you implemented revision management ?. You can email me at himanshu _ kgp at gmail dot com

      Using the AuditReader of Envers you can get the state of an object with given revision. Get the two states of the object (f.e. User) to compare. Then compare the properties using BeanUtils and reflection.

      Pseudo-Code / there are good examples in the web out there

      revisionA=AuditReader.getRevisionXXX(42, User.class);
      revisionB=AuditReader.getRevisionXXX(43, User.class);

      String valueA=org.apache.commons.beanutils.BeanUtils.getProperty(revisionA, "email")
      String valueB=org.apache.commons.beanutils.BeanUtils.getProperty(revisionB, "email")

      hasChanged=!valueA.equals(valueB);

      + special handling of deletes (when revisionB does not exist)
      + special handling of inserts (when revisionA does not exist)

      I know BeanUtils works with reflection and the iteration of all properties is slow (so it can be a performance issue), but you got the basics?

  • Andreas Höhmann 12:02 am Wednesday, 3. June 2009 Permalink |
    Tags: , jdbc, logging, , Spring, sql   

    Hibernate sql logging with values 

    As you might know already, Hibernate supports logging for sql-statements. Your Spring-configuration (e.g. spring-database.xml) must contain this:

    
    <bean id="entityManagerFactory"
     class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceUnitName" value="logging-test" />
    <property name="jpaVendorAdapter">
     <bean>
    <property name="showSql" value="true" />
    <property name="generateDdl" value="true" />
    <property name="databasePlatform" value="${jpa.hibernate.dialect}" />
     </bean>
     </property>
    <property name="jpaProperties" value="hibernate.dialect=${jpa.hibernate.dialect}" />
     </bean>
    
    

    With showSql=true hibernate will show you logmessages like this:

    Hibernate:
       delete
       from
          SoftwareCategory_SoftwareCategory
       where
          SoftwareCategory_id=?
    Hibernate:
       update
          SoftwareCategory
       set
          concurrentVersion=?,
          CATEGORY_NAME=?,
          PARENT_ID=?
       where
          id=?
          and concurrentVersion=?
    Hibernate:
       insert
       into
          SoftwareCategory_SoftwareCategory
          (SoftwareCategory_id, POSITION, children_id)
       values
          (?, ?, ?)

    To see the values and not the placeholders (?) you must define the loglevel trace for hibernate-types in the log4j.xml:

    
    <category name="org.hibernate.type">
    <priority value="trace" />
     </category>
    
    

    Then you will see logmessages like this:

    Hibernate:
       insert
       into
          SoftwareCategory_SoftwareCategory
          (SoftwareCategory_id, POSITION, children_id)
       values
          (?, ?, ?)
    NullableType:151 - binding '68' to parameter: 1
    NullableType:151 - binding '0' to parameter: 2
    NullableType:151 - binding '69' to parameter: 3

    Not bad but there is a better way for this 🙂

    Yesterday i found the project JDBCLogger.  They have implemented a „JDBC-Proxy“ with logging support. Its Maven-ready and comes with a easy Spring-integration. So how can we use this cool stuff … it is so easy:

    1. Define the JDBCLogger dependencies in the pom.xml:

    
    <dependencies>
    <dependency>
     <groupId>net.sourceforge.jdbclogger</groupId>
     <artifactId>jdbclogger-core</artifactId>
     <version>0.7-SNAPSHOT</version>
     </dependency>
     <dependency>
     <groupId>net.sourceforge.jdbclogger</groupId>
     <artifactId>jdbclogger-spring</artifactId>
     <version>0.7-SNAPSHOT</version>
     </dependency>
     </dependencies>
    
    

    The informations from the installation-guide on the project-site is a little too old, so the maven-repository http://jdbclogger.sourceforge.net/m2-repo/ doesn’t exists. No problem we can build jdbclogger-core and jdbclogger-spring by ourself (read more). The simplest way to build the two artifacts is:

    • checkout from  svn
    • edit master-pom, comment out all modules, leave only core and spring active
    • run mvn clean install from root-dir

    2. Change your Spring-configuration, switch showSql off and add the following bean:

    
    <bean id="jdbcLoggerConfig"
     class="net.sourceforge.jdbclogger.spring.JdbcLoggerBeanPostProcessor">
    <property name="enabled" value="true" />
    <property name="dataSourceConfigurations">
    	<list>
     <bean class="net.sourceforge.jdbclogger.spring.JdbcLoggerDataSourceConfiguration">
    <property name="dataSourceBeanName" value="dataSource" />
    <property name="driverClassNamePropertyName" value="driverClassName" />
     </bean>
     </list>
     </property>
    <property name="targetDriverClassNames">
    	<list>
     <value>${jpa.driver}</value>
     </list>
     </property>
     </bean>
    
    

    3.  Activate logging in the log4j.xml:

    
    <category name="net.sourceforge.jdbclogger">
    <priority value="debug" />
     </category>
    <category name="net.sourceforge.jdbclogger.spring">
    <priority value="error" />
     </category>
    
    

    Thats it 🙂 Now you will see logmessages like this:

    JdbcLoggerDriver:65 – Wrapper ’net.sourceforge.jdbclogger.JdbcLoggerDriver‘ successfully registed for driver ‚com.mysql.jdbc.Driver‘
    PreparedStatementWrapper:156 – Prepared Statement : select softwareca0_.id as id0_, softwareca0_.concurrentVersion as concurre2_0_, softwareca0_.CATEGORY_NAME as CATEGORY3_0_, softwareca0_.PARENT_ID as PARENT4_0_ from SoftwareCategory softwareca0_ where softwareca0_.PARENT_ID is null
    StatementWrapper:45 – Statement : delete from softwarecategory_softwareobject
    PreparedStatementWrapper:156 – Prepared Statement : insert into SoftwareCategory_SoftwareCategory (SoftwareCategory_id, POSITION, children_id) values (’92‘, ‚3‘, ’96‘)

     
    • Amit Telang 19:34 am Dienstag, 6. Mai 2014 Permalink | Zum Antworten anmelden

      Hi, I tried everything like setting type to TRACE and everything found in other sites, but still I am unable to see parameter values. I am using hibernate 3.6.

  • Andreas Höhmann 17:18 am Wednesday, 15. October 2008 Permalink |
    Tags: request, scope, session, singleton, Spring, test, , unit   

    Using Session/Request-Scoped SpringBeans in TestNG 

    Today i will show you how to use spring-beans (especially session-scoped respectively request-scoped) in Unittests.

    First of all … its easy to use a singleton bean (no scope) in a unit-test, load the ClassPathXmlApplicationContext with configLocations, use getBean(„name“) and then use the returned objects.

    But if you want use a enhanced (J2EE) spring-configuration in your unit-test you have to use the XmlWebApplicationContext.

    Lets use a simple example! Imagine you have different context-files, e.g. spring-beans-application.xml:

      <bean id="Foobar1" class="de.ahoehma.test.Foobar" scope="request"/>
      <bean id="Foobar2" class="de.ahoehma.test.Foobar" scope="session"/>
      <bean id="Foobar3" class="de.ahoehma.test.Foobar" />
    

    Then you have your unit-test:

    public class SpringBeansTestNg {
    
      //
      // XXX we have to define all spring-context-files - later this could be done via test-ng-provider or
      //     via spring with "spring-beans-*.xml" (i try it but it doesnt work)
      //
      private final String[] contextLocations = new String[]{
          "spring-beans-application.xml",
          "spring-beans-services.xml",
          "spring-beans-persistence.xml",
          "spring-beans-security.xml",};
    
      private ApplicationContext applicationContext;
    
      @BeforeTest
      private void loadApplicationContext() {
        final XmlWebApplicationContext xmlApplicationContext = new XmlWebApplicationContext();
        xmlApplicationContext.setConfigLocations(contextLocations);
        final MockServletContext servletContext = new MockServletContext("");
        xmlApplicationContext.setServletContext(servletContext);
        final RequestContextListener requestContextListener = new RequestContextListener();
        final MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
        final ServletRequestEvent requestEvent = new ServletRequestEvent(servletContext, request);
        requestContextListener.requestInitialized(requestEvent);
        xmlApplicationContext.refresh();
        applicationContext = xmlApplicationContext;
      }
    
      /**
       * @return request scoped bean
       */
      private Foobar getFoobar1() {
        return (Foobar) applicationContext.getBean("Foobar1"); //$NON-NLS-1$
      }
    
     /**
       * @return session scoped bean
       */
      private Foobar getFoobar2() {
        return (Foobar) applicationContext.getBean("Foobar2"); //$NON-NLS-1$
      }
    
     /**
       * @return singleton bean
       */
      private Foobar getFoobar3() {
        return (Foobar) applicationContext.getBean("Foobar3"); //$NON-NLS-1$
      }
    }
    

    The magic happend in the loadApplicationContext.

    Try it 🙂

     
  • Andreas Höhmann 12:34 am Wednesday, 16. April 2008 Permalink |
    Tags: , , , Spring   

    Maven + Eclipse + Spring 

    Today i show how you can easily develop a Mavenproject with Spring-Beans
    in your Eclipse-IDE. You have to add a new plugin to your pom’s
    plugins-section:

    
    ...
    
    <build>
      <plugins>
        <plugin>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
              <projectNameTemplate>[artifactId]</projectNameTemplate>
              <downloadSources>true</downloadSources>
              <downloadJavadocs>true</downloadJavadocs>
              <wtpmanifest>true</wtpmanifest>
              <wtpapplicationxml>true</wtpapplicationxml>
              <wtpversion>2.0</wtpversion>
              <manifest>${basedir}/src/main/resources/META-INF/MANIFEST.MF</manifest>
              <additionalProjectnatures>
                <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
              </additionalProjectnatures>
              <additionalBuildcommands>
                <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
              </additionalBuildcommands>
              <additionalConfig>
                <file>
                  <name>.springBeans</name>
                  <content>
                    <!&#91;CDATA&#91;<?xml version="1.0" encoding="UTF-8"?>
    <beansProjectDescription>
      <configExtensions>
        <configExtension>xml</configExtension>
      </configExtensions>
      <configs>
        <config>src/main/resource/services.xml</config>
        <config>src/main/resource/datasource.xml</config>
      </configs>
      <configSets>
        <configSet>
          <name>core</name>
          <allowBeanDefinitionOverriding>true</allowBeanDefinitionOverriding>
          <incomplete>false</incomplete>
          <configs>
           <config>src/main/resource/services.xml</config>
           <config>src/main/resource/datasource.xml</config>
          </configs>
        </configSet>
      </configSets>
    </beansProjectDescription>&#93;&#93;>
                  </content>
                </file>
                <file>
                  <name>.settings/org.springframework.ide.eclipse.core.prefs</name>
                  <content>
                    <!&#91;CDATA&#91;<?xml version="1.0" encoding="UTF-8"?>
    eclipse.preferences.version=1
    org.springframework.ide.eclipse.core.builders.enable.aopreferencemodelbuilder=true
    org.springframework.ide.eclipse.core.enable.project.preferences=true
    org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinition-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinitionHolder-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanFactory-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanInitDestroyMethod-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanReference-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.requiredProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.action-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.actionstate-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attribute-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attributemapper-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.beanaction-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationaction-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationresult-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.exceptionhandler-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.import-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.inputattribute-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.mapping-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.outputattribute-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.set-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.state-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.subflowstate-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.transition-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.variable-org.springframework.ide.eclipse.webflow.core.validator=false
    org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.webflowstate-org.springframework.ide.eclipse.webflow.core.validator=false
    &#93;&#93;>
                  </content>
                </file>
              </additionalConfig>
            </configuration>
          </plugin>
        </plugins>
      </build>
    ...
    

    Then you can run mvn eclipse:clean eclipse:eclipse (eclipse:clean is not required). The eclipse-plugin will create/change the .springBean and the .settings/org.springframework.ide.eclipse.core.prefs. Then you can refresh the eclipse-project (F5) from now the project contains a Spring-Builder which will handle the defined spring-configuration-files services.xml and datasource.xml. If you have more Springfiles you have to change the plugin-configuration.

     
c
Neuen Beitrag erstellen
j
nächster Beitrag/nächster Kommentar
k
vorheriger Beitrag/vorheriger Kommentar
r
Antworten
e
Bearbeiten
o
zeige/verstecke Kommentare
t
Zum Anfang gehen
l
zum Login
h
Zeige/Verberge Hilfe
Shift + ESC
Abbrechen