blob: 2a7fc38734bb9f60b958d884dbd75c7d07238cca [file] [log] [blame]
/*
* Copyright 2011 Marc Grue.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zest.sample.dcicargo.sample_a.infrastructure;
import javax.servlet.http.HttpServletRequest;
import org.apache.wicket.Page;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.cycle.AbstractRequestCycleListener;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.zest.api.Qi4j;
import org.apache.zest.api.composite.TransientBuilderFactory;
import org.apache.zest.api.injection.scope.Service;
import org.apache.zest.api.injection.scope.Structure;
import org.apache.zest.api.query.QueryBuilderFactory;
import org.apache.zest.api.structure.Application;
import org.apache.zest.api.structure.Module;
import org.apache.zest.api.unitofwork.ConcurrentEntityModificationException;
import org.apache.zest.api.unitofwork.UnitOfWork;
import org.apache.zest.api.unitofwork.UnitOfWorkCompletionException;
import org.apache.zest.api.unitofwork.UnitOfWorkFactory;
import org.apache.zest.api.usecase.UsecaseBuilder;
import org.apache.zest.api.value.ValueBuilderFactory;
import org.apache.zest.bootstrap.ApplicationAssembler;
import org.apache.zest.bootstrap.Energy4Java;
import org.apache.zest.sample.dcicargo.sample_a.infrastructure.conversion.EntityToDTOService;
import org.apache.zest.sample.dcicargo.sample_a.infrastructure.dci.Context;
import org.apache.zest.sample.dcicargo.sample_a.infrastructure.model.Queries;
import org.apache.zest.sample.dcicargo.sample_a.infrastructure.model.ReadOnlyModel;
import org.apache.zest.sample.dcicargo.sample_a.infrastructure.wicket.page.BaseWebPage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Base Wicket Web Application containing the Zest application.
*/
public class WicketQi4jApplication
extends WebApplication
{
public Logger logger = LoggerFactory.getLogger( WicketQi4jApplication.class );
protected Application qi4jApp;
protected Module qi4jModule;
@Structure
protected UnitOfWorkFactory uowf;
@Structure
protected ValueBuilderFactory vbf;
@Structure
protected QueryBuilderFactory qbf;
@Structure
protected TransientBuilderFactory tbf;
@Structure
protected Qi4j qi4j;
@Service
protected EntityToDTOService valueConverter;
/**
* Zest Assembler
*
* To let the custom application class (DCISampleApplication_x) focus on starting up the
* Wicket environment, I made a convention of having Zest Assembler files in an 'assembly'
* folder beside the custom application class.
*
* There's always only one application file, but we could split the assemblage into several
* files ie. one for each layer. In that case, the Assembler file would be distributing to
* the individual LayerXAssembler classes.
*
* If you like, you can also override this method in the custom application class and simply
* return an instance of YourAssembler:
*
* @Override protected ApplicationAssembler getAssembler() {
* return new YourAssemblerInAnyPath();
* }
*/
protected ApplicationAssembler getAssembler()
throws Exception
{
String appPath = getClass().getCanonicalName();
String expectedPathFromApplication = ".assembly.Assembler";
String assemblerPath = appPath.substring( 0, appPath.lastIndexOf( "." ) ) + expectedPathFromApplication;
try
{
return (ApplicationAssembler) Class.forName( assemblerPath ).newInstance();
}
catch( ClassNotFoundException e )
{
throw new Exception( "Couldn't find Zest assembler in path '" + assemblerPath + "'" );
}
}
protected String defaultLayerName()
{
return "BOOTSTRAP";
}
protected String defaultModuleName()
{
return "BOOTSTRAP-Bootstrap";
}
// Override this to bootstrap the wicket application
protected void wicketInit()
{
}
@Override
protected void init()
{
startQi4j();
handleUnitOfWork();
Context.prepareContextBaseClass( uowf );
BaseWebPage.prepareBaseWebPageClass( tbf );
ReadOnlyModel.prepareModelBaseClass( qi4jModule, qi4j, valueConverter );
Queries.prepareQueriesBaseClass( uowf, qbf );
wicketInit();
}
private void startQi4j()
{
try
{
logger.info( "Starting Zest application" );
Energy4Java qi4j = new Energy4Java();
qi4jApp = qi4j.newApplication( getAssembler() );
qi4jApp.activate();
qi4jModule = qi4jApp.findModule( defaultLayerName(), defaultModuleName() );
// Zest injects @Structure and @Service elements into this application instance
//qi4jModule.newObject( WicketQi4jApplication.class );
qi4jModule.injectTo( this );
logger.info( "Started Zest application" );
}
catch( Exception e )
{
logger.error( "Could not start Zest application." );
e.printStackTrace();
System.exit( 100 );
}
}
private void handleUnitOfWork()
{
getRequestCycleListeners().add( new AbstractRequestCycleListener()
{
@Override
public void onBeginRequest( final RequestCycle requestCycle )
{
super.onBeginRequest( requestCycle );
logger.debug( "================================" );
logger.debug( "REQUEST start" );
logger.debug( requestCycle.getRequest().toString() );
logger.debug( requestCycle.getRequest().getRequestParameters().toString() );
UnitOfWork uow = uowf.newUnitOfWork( UsecaseBuilder.newUsecase( "REQUEST" ) );
logger.debug( " ### NEW " + uow + " ### MODULE: " + qi4jModule );
}
@Override
public void onEndRequest( final RequestCycle requestCycle )
{
UnitOfWork uow = uowf.currentUnitOfWork();
if( uow != null )
{
try
{
if( "POST".equals( ( (HttpServletRequest) requestCycle.getRequest()
.getContainerRequest() ).getMethod() ) )
{
// "Save"
logger.debug( " ### COMPLETE " + uow + " ### MODULE: " + qi4jModule );
uow.complete();
}
else
{
// GET requests
logger.debug( " ### DISCARD " + uow + " ### MODULE: " + qi4jModule );
uow.discard();
}
}
catch( ConcurrentEntityModificationException e )
{
logger.error( " ### DISCARD " + uow + " ### MODULE: " + qi4jModule );
uow.discard();
e.printStackTrace();
}
catch( UnitOfWorkCompletionException e )
{
logger.error( " ### DISCARD " + uow + " ### MODULE: " + qi4jModule );
uow.discard();
e.printStackTrace();
}
}
logger.debug( "REQUEST end" );
logger.debug( "------------------------------------" );
}
} );
}
// Since Zest can only add concrete classes in the assembly, we need to implement a (dummy) getHomePage()
// method here. Override in wicket application class with a real returned page class.
@Override
public Class<? extends Page> getHomePage()
{
return null;
}
@Override
protected void onDestroy()
{
if( qi4jApp == null )
{
return;
}
try
{
logger.info( "Passivating Zest application" );
qi4jApp.passivate();
}
catch( Exception e )
{
e.printStackTrace();
}
}
public String appVersion()
{
return qi4jApp.version();
}
}