Archive

Archive for July, 2009

I use connection pooling to fix a hibernate problem

Friday, 31. July 2009 Andreas Höhmann Leave a comment

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 com.siemens.spice.common.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>

JSF value binding

Wednesday, 29. July 2009 Andreas Höhmann Leave a comment

Today i will explain three types of value binding:

  • “direct” value binding (one setter / getter for each value)
  • “list based” value binding (one setter / getter for a list of values)
  • “map based” value binding (one setter / getter for a map of values)

Direct value binding

This is the classic usage of value binding in jsf, the following facelets-snippet is self-explanatory:

<h:inputText value="#{bean.foo}"/>
<h:inputText value="#{bean.bar}"/>

Our bean have a setter and a getter for foo and bar:

class Bean {
 private String foo, bar;
 public String getFoo() ...
 public void setFoo(String) ...
 public String getBar() ...  
 public void setBar(String) ...
}

List based value binding

I use this to avoid setter and getter for similar values/properties, i.e.

<h:inputText value="#{bean.product[0]}"/>
<h:inputText value="#{bean.product[1]}"/>
<h:inputText value="#{bean.product[2]}"/>
...

With the “classic” value binding i have to write a lot of getter/setter (product0, product1, product2,…). But with list based value binding its much easier.


class Bean {
 private static final int MAX_NUMBER_OF_PRODUCTS = 5;
 private final Product[] products = new Product[MAX_NUMBER_OF_PRODUCTS];
 public Bean () {
 for (int i = 0; i < MAX_NUMBER_OF_PRODUCTS; i++) {
 products[i] = null;
 }
 }
 public List<Product> getProduct() {
 return Arrays.asList(Product);
 }
}

The initialization of the internal array/list is necessary for correct working! During runtime jsf will access each value via index (0, 1, 2, …), a uninitialized list will throw a IndexOutOfBounds Exception.

Map based value binding

I used this type of value binding in a generic “CRUD list” view to implement filtering in a rich:dataTable. I want  a selectbox for each “filterable” column:


<rich:column>
 <f:facet name="header">
 <h:selectOneMenu value="#{bean.filterValue['foo']}">
 <f:selectItems value="#{bean.filterValues['foo']}" />
 </h:selectOneMenu>
 </f:facet>
 ...
</rich:column>

<rich:column>
 <f:facet name="header">
 <h:selectOneMenu value="#{bean.filterValue['bar']}">
 <f:selectItems value="#{bean.filterValues['bar']}" />
 </h:selectOneMenu>
 </f:facet>
 ...
 </rich:column>

To get this to work we need a “customized” map implementation:

class ArrayMap<K, T> extends HashMap<K, T> {
 private static final long serialVersionUID = -5766406097936988242L;
 @Override
 public T get(final Object theKey) {
 if (!containsKey(theKey)) {
 // to avoid typos in the ui we throw a exception if a "unknown" value-name is used
 throw new IllegalArgumentException(String.format("The given value-name '%s' is not available", theKey));
 }
 return super.get(theKey);
 }
 public void set(final K key, final T value) {
 super.put(key, value);
 }
 }

This ArrayMap have a getter and a setter (the “normal” Map have only get and put), for jsf value binding we need a set and a get.

Here is the final filter – bean:


class FilterBean {

/**
 * Contain all available filter-values for each supported filter-name.
 */
 private final Map<String, List<SelectItem>> filterValues = new ArrayMap<String, List<SelectItem>>();

 /**
 * Contain the current filter-value for each supported filter-name.
 */
 private final ArrayMap<String, Object> filterValue = new ArrayMap<String, Object>();

/*
 * Constructor.
 */
public FilterBean() {
 initFilterValue();
 }

/**
 * @return a map of lists with {@link SelectItem}s
 */
 public Map<String, List<SelectItem>> getFilterValues() {
 return filterValues;
 }

 /**
 * @return the map of filter values
 */
 public ArrayMap<String, Object> getFilterValue() {
 return filterValue;
 }

/**
 * Prepare <tt>filterValue</tt>, add all supported filter-names to the list.
 */
 private void initFilterValue() {
 filterValue.set("foo", null);
 filterValue.set("bar", null);
}

/**
 * Prepare <tt>filterValues</tt>, the given list contains all rows for the datatable. Each filter-selectbox must
 * show a unique list of available filter-values (per supported filter column).
 */
public synchronized void initFilterValues(final List<T> theInitialFilterList) {
 filterValues.clear();
 filterValues.put("foo", getFilterSelectItemsFoo(theInitialFilterList));
 filterValues.put("bar", getFilterSelectItemsBar(theInitialFilterList));}
}

}

The method initFilterValues(final List<T>) will be triggered from a external bean. Then the filter-bean  can create a list of SelectItems for each filter-column.

If the User select a value from such a filter-list the value binding will call our ArrayMap.set method.

Try it :D

Categories: JSF, Java Tags: ,

Ein Virus bedroht das Land – Grunz – Vorsicht ;)

Monday, 27. July 2009 Andreas Höhmann Leave a comment

Vorsicht! Der altbekannte BI-LD Virus greift wieder einmal verstärkt um sich. Diesmal in einer mutierten Form und zwar als BI1-LD1. Auf der momentanen Welle der H1N1 Panikmache erreicht er quasi jedes Ohr und Auge.

Der Virus tarnt sich dabei als normale Meldung und ist eine bunte Mischung aus Angstmache, Halbwissen, WHO-Statistiken, Impfstoffwerbung  und vielem mehr, wie man an diesem sichergestellten Exemplar (Vorsicht! Beim Lesen unbedingt mitdenken) gut erkennen kann.

Der Virus arbeitet dabei auf eine ganz hinterhältige Art und Weise … er dringt über die Augen ein, meist in Form von Meldungen des RKI und setzt sich im Gehirn fest. Nach und nach verursacht er dort eine Art Angst vor bösen bösen H1N1 Viren, die unser Leben bedrohen. Auch kann er über die Ohren in Form der Untergattung “Hören-Sagen” eindringen.

Der BI1-LD1 Virus selbst hat allerdings noch viele Brüderchen und Schwesterchen, die alle auf eine ähnliche Weise wirken. Aber es besteht Hoffnung! Das immer gleiche Schema-F nach dem diese Virengruppe funktioniert, kann nach einer Weile vom Körper zum Aufbau einer natürlichen Immunität verwendet werden.

Sorge ist geboten wenn sich erste Anzeichen für eine schwere Infektion einstellen. Diese bestehen z.B. aus Überlegungen sich einer Grippe-Schutz-Impfung zu unterziehen. Oder wenn sich der Betroffene nicht mehr unter Leute wagt, aus Angst Opfer der heimtückischen H1N1 Viren zu werden.

Vorbeugend kann man allerdings jede Menge tun: z.B. H1N1 einfach ignorieren!

Categories: Medien

My Eclipse Plugin List

Wednesday, 22. July 2009 Andreas Höhmann Leave a comment

Today i updated my Eclipse 3.5 M7 to the final 3.5. Here are my plugin list:

eclipse3.5

  • PropEdit – nice Propertyeditor which can handle UTF-8 correctly
  • Spring-IDE – Beansearch, Contexteditor with content assistant
  • FindBugs - Check your code for bugs
  • WTP – of course for a web developer ;-)
  • Subversive – for SVN integration
  • JBoss Tools – nice XHTML (facelets) editor, web.xml editor, faces-config editor and more
  • m2Eclipse – cool maven integration
  • EclEmma – code coverage
  • TeamCity – continues integration platform
  • MoreUnit – jump from Code to Unittest, create new Test if not exists
  • TestNG – integration for these unittests

What are your prefered plugins?

Fadein and Fadeout a Richfaces ModalPanel

Wednesday, 22. July 2009 Andreas Höhmann Leave a comment

Today i explain you a cool combination for rich:modalPanel and rich:effect.

In the richfaces forum i found a article about a modalpanel with scriptaculous-effects (“fade-in a modalpanel”). The answer was a link to the official richfaces demo-application (photoalbum). There we can find a login-dialog (svn source) with a “appear-effect”:

<rich:modalPanel id="loginPanel"
onshow="applyModalPanelEffect('loginPanel', appearFunc,{delay: 0.5, afterFinish: function(){$('loginPanelForm:username').focus();}})"
styleClass="login-panel"
showWhenRendered="#{authenticator.loginFailed}"
width="400" height="150" autosized="true">
<f:facet name="header">#{messages['login.login']}</f:facet>
<f:facet name="controls">
<h:panelGroup id="loginPanelHideControl">
<h:graphicImage value="/img/modal/close.png" style="cursor:pointer"
id="loginPanelhidelink" onclick="#{rich:component('loginPanel')}.hide();"/>
</h:panelGroup>
</f:facet>
...
<rich:effect type="Appear" name="appearFunc"/>
...

The javascript method applyModalPanelEffect can be found in the photoalbum.js (svn source):

function applyModalPanelEffect(panelId, effectFunc, params) {
 if (panelId && effectFunc) {
 var modalPanel = $(panelId);
 if (modalPanel && modalPanel.component) {
 var component = modalPanel.component;
 var div = component.getSizedElement();
 Element.hide(div);
effectFunc.call(this, Object.extend({targetId: div.id}, params || {}));}}
}

With this the rich:modalPanel will not shown immediately … it appears ;-) This was the “fade-in part”.

I improved the code for the “fade-out part”, first the dialog:


<!-- first the effects -->
<rich:effect type="Appear" name="appearDialog"/>
 <rich:effect type="Fade" name="disappearDialog"/>

<!-- to keep the dialog-code clean -->
<c:set var="closeDialog" value="hideModalPanelWithEffect('myDialog',disappearDialog,{delay:0.1,duration:0.5})"/>

<rich:modalPanel id="myDialog"
 onshow="showModalPanelWithEffect('myDialog',appearDialog,{delay:0.1,duration:0.5})"
 width="610" height="350" minHeight="350" autosized="true" shadowDepth="0">
<f:facet name="controls">
<h:panelGroup>
<h:graphicImage value="/img/modal/close.png" style="cursor:pointer" onclick="#{closeDialog}"/>
</h:panelGroup>
</f:facet>
</rich:modalPanel>

and the javascript:

function applyModalPanelEffect(panelId, effectFunc, params, hide) {
 if (panelId && effectFunc) {
 var modalPanel = $(panelId);
 if (modalPanel && modalPanel.component) {
 var component = modalPanel.component;
 var div = component.getSizedElement();
 if (hide) {
 Element.hide(div);
 }
 effectFunc.call(this, Object.extend( {targetId : div.id}, params || {}));}}
}

function showModalPanelWithEffect(panelId, showEffect, params) {
 applyModalPanelEffect(panelId, showEffect, params, true);
}

function hideModalPanelWithEffect(panelId, hideEffect, params) {
 var _params = params;
_params['afterFinish'] = function(){Richfaces.hideModalPanel(panelId)};
 applyModalPanelEffect(panelId, hideEffect, params, false);
}

Now the dialog call showModalPanelWithEffect to fade-in and hideModalPanelWithEffect to fade-out.

Try it :D

Deploy maven war-project to tomcat

Friday, 10. July 2009 Andreas Höhmann Leave a comment

With maven it’s possible to deploy the current version of your webapplication (<packaging>war</packaging>) with one command!

mvn clean package tomcat:deploy-only

All we have to to is to define the tomcat-maven-plugin:


...
<packaging>war</packaging>
...
<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>tomcat-maven-plugin</artifactId>
 <configuration>
 <url>http://server[:port]/manager</url>
<path>/${project.build.finalName}</path>
 <update>true</update>
<server>tomcat_xyz</server>
 </configuration>
 </plugin>

You have to define username/password in your settings.xml:

<?xml version="1.0" encoding="UTF-8"?>
<settings 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/settings-1.0.0.xsd">

<servers>
<server>
<id>tomcat_xyz</id>
<username>admin</username>
<password>123geheim</password>
</server>
</servers>

</settings>

Check the tomcat-user.xml:

<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
 <role rolename="manager"/>
 <role rolename="admin"/>
 <user username="admin" password="123geheim" roles="admin,manager"/>
</tomcat-users>

If you  run the maven command you will see:

[INFO] [tomcat:deploy-only {execution: default-cli}]
[INFO] Deploying war to http://server:8080/foobar-1.0.0-SNAPSHOT-B20090710  
[INFO] OK - Deployed application at context path /foobar-1.0.0-SNAPSHOT-B20090710
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

To get the version and a buildnumber in the context-path you must define the finalName and you must use a “buildnumber-plugin”, e.g.  buildnumber-maven-plugin or maven-timestamp-plugin:


<build>
 <finalName>foobar-${project.version}-B${buildNumber}</finalName>
 </build>
<plugins>
<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>buildnumber-maven-plugin</artifactId>
 <executions>
 <execution>
 <id>create-buildnumber</id>
<phase>validate</phase>
 <goals>
 <goal>create</goal>
 </goals>
 </execution>
 </executions>
 <configuration>
 <doUpdate>false</doUpdate>
 <doCheck>false</doCheck>
 <format>{0,date,yyyyMMdd}</format>
 <items>
 <item>timestamp</item>
 </items>
 <buildNumberPropertyName>buildNumber</buildNumberPropertyName>
</configuration>
 </plugin>
<plugin>
 <groupId>com.keyboardsamurais.maven</groupId>
 <artifactId>maven-timestamp-plugin</artifactId>
 <executions>
 <execution>
 <id>create-buildnumber</id>
 <goals>
 <goal>create</goal>
 </goals>
 <configuration>
<propertyName>buildNumber</propertyName>
 <timestampPattern>yyyyMMdd</timestampPattern>
 </configuration>
 </execution>
 </executions>
 </plugin>

</plugins>

Der teuerste Film aller Zeiten

Wednesday, 1. July 2009 Andreas Höhmann Leave a comment

und der schlechteste dazu! Was ich mir da gestern Abend in knapp 150 Minuten ansehen durfte war so unlogisch,dumm, sinnlos, einfältig, überflüssig, belanglos, effektüberladen … wie kaum ein anderer Film den ich jemals gesehen habe. Wenn ich mir allerdings die Beschreibung auf kino.de durchlese, frage ich mich welchen Film der Autor gesehen hat?!

Zum Beispiel: “Während Sam Witwicky und die Autobots noch an den Frieden glauben, hat Skorpinox die Überreste von Megatron aus den Händen des US-Militärs gestohlen und ihn wiederbelebt

Was heißt hier gestohlen? Der war doch überhaupt nicht gesichert! Im Film kommt die “geheime” Megatron-Versenk-Stelle im Atlantik durch die einfache (unbemerkte) Übernahme eines Militärsatelliten ans Licht und holter-die-polter tauchen ein paar böse Decepticons hinab und beleben ihren alten Boss mit Hilfe eines Splitters des im ersten Teil zerstörten Würfels (der erste Teil war schon so schlecht, dass ich mich an dessen Handlung NULL erinnern konnte). Unlogisch und konstruiert hoch 10. Irgs.

Oder: “Spektakel in Reinkultur: Die Fortsetzung des Welterfolgs bietet alle Elemente, die Blockbuster-Kino auszeichnen, im XXL-Format: Gigantische Action, gigantische Story, gigantisch viel Fun.” Waaaaaa … Story? Wo war da eine Story?

Oder: “bis hin zu einem atemberaubenden Showdown auf den Pyramiden, die real gefilmt und nicht etwa im Computer simuliert wurden.” Ähmm was wurde da real gefilmt ?!? Etwa wie eine 30 Meter hoher Roboter die Kuppe der Cheops-Pyramide abträgt um darunter eine Maschine freizulegen. Das war alles echt? WOW Krazz!

Oder: “Trotz aller pyrotechnischen Virtuosität schafft es Michael Bay dennoch, seine Charaktere zu akzentuieren, was auch deshalb gelingt, weil sich seine Hauptdarsteller Shia LaBeouf und Megan Fox seither schauspielerisch noch weiter entwickelt haben.” Die Dialoge strotzen nur so von Sinnlosigkeit, Gefühle wo? Etwa bei der parallel verlaufenden “Liebesgeschichte” zwischen Held und Heldin? Schauspielerisch weiterentwickelt … LOL … die langweiligen Zwischensequenzen (Gelaber!) hatten allerdings etwas Gutes … meine Augen/Magen konnten sich von den rasanten Renderszenen erholen.

Einziger Lichtblick war die Rolle von John Turturro, der war wirklich lustig drauf. Aber ansonst … bitte! … ich würde es ja verstehen wenn die Darsteller auch im Computer entstanden wären, aber so … OHje.

Skeptiker mögen diese Wundertüte an filmischen Elementen als Overkill empfinden” … Richtig!!!!

Ich kam mir wie in einem Werbefilm des US-Militärs vor …

Mehr bessere Filme ins Kino! :D

Categories: Film Tags: