SlideShare a Scribd company logo
Migrating existing Projects to
Wonder
Maik Musall, Selbstdenker AG
Samstag, 22. Juni 13
• Existing application of some complexity
• Using perhaps custom frameworks, but not yet Wonder
• Want to use Wonder for several reasons, but uncertain where to
start and how to manage the migration process
The Task
Samstag, 22. Juni 13
Goals
• Make the switch at a chosen, planned point in time
• Being able to switch back to the non-Wonder version if
problems come up in production
• Identify which steps to do when, and how
Samstag, 22. Juni 13
The Big Steps
• Move to Git (if you haven‘t already)
• Prepare the code base ahead of the actual wonderization
• Create a wonderization branch
• Wonderize in that branch, periodically merge new stuff from
your main branch
• Release and celebrate
Samstag, 22. Juni 13
Prep step: Move to Git
• You‘ll need branches during the migration
• Wonder is Git-based anyway
• It just makes everything easier
• Plan some time to get up to speed using Git first
• Use Sourcetree
Samstag, 22. Juni 13
Prep step: Move to Git
Time
release branches
masterdevelop hotfixes
feature
branches
Feature
for future
release
Tag
1.0
Major
feature for
next release
From this point on,
“next release”
means the release
after 1.0
Severe bug
fixed for
production:
hotfix 0.2
Bugfixes from
rel. branch
may be
continuously
merged back
into develop
Tag
0.1
Tag
0.2
Incorporate
bugfix in
develop
Only
bugfixes!
Start of
release
branch for
1.0
Author: Vincent Driessen
Samstag, 22. Juni 13
Prep step: Move to Git
Time
release branches
masterdevelop hotfixes
feature
branches
Feature
for future
release
Major
feature for
next release
Severe bug
fixed for
production:
hotfix 0.2
Tag
0.1
Tag
0.2
Incorporate
bugfix in
develop
Start ofSamstag, 22. Juni 13
Prep step: Move to Git
release
Tag
1.0
From this point on,
“next release”
means the release
after 1.0
Bugfixes from
rel. branch
may be
Tag
0.2
Incorporate
bugfix in
develop
Only
bugfixes!
Start of
release
branch for
1.0
Samstag, 22. Juni 13
Prep step: Move to Git
Tag
1.0
From this point on,
“next release”
means the release
after 1.0
Bugfixes from
rel. branch
may be
continuously
merged back
into develop
Only
bugfixes!
Start of
release
branch for
1.0
Samstag, 22. Juni 13
Managing Wonderization in Git
first wonderized release
second wonderized release
conventional version as fallback
conventional version as fallback
wonderized version merged into main
1.0
1.0
develop wonderize
1.1
feature
1.2
1.2
1.3
1.3
2.0
1.2
Samstag, 22. Juni 13
Prep step: Java packages
• You can‘t inherit from packaged classes if your classes aren‘t in
packages, too
• So if you haven‘t already, create packages and move all your
sources into them
• Benefit: clarified namespaces for your stuff
Samstag, 22. Juni 13
Java packages gotchas
• Getters and setters in components need to be(come) public
• Check class.getName() calls to become class.getSimpleName()
• Class.forName() needs full packaged path
• Overridden methods in enums become unreachable code in WO
bindings
Samstag, 22. Juni 13
public enum ContentType {
! literature {
! ! @Override public String cssClassName() { return "read"; }
! },
! film {
! ! @Override public String cssClassName() { return "watch"; }
! },
! music {
! ! @Override public String cssClassName() { return "listen"; }
! };
!
! public abstract String cssClassName();
! public boolean isAvailable() { return true; }
}
Packages: overriding enum methods
Samstag, 22. Juni 13
Packages: overriding enum methods
public enum ContentType {
! literature {
! ! @Override public String cssClassName() { return "read"; }
! },
! film {
! ! @Override public String cssClassName() { return "watch"; }
! },
! music {
! ! @Override public String cssClassName() { return "listen"; }
! },
! pr0n {
! ! @Override public String cssClassName() {
! ! ! return getUser().isAdult() ? "watch" : "nothingForYou";
! ! }
! };
!
! public abstract String cssClassName();
}
Samstag, 22. Juni 13
Packages: overriding enum methods
public enum ContentType {
! literature {
! ! @Override String cssClassNameImpl() { return "read"; }
! },
! film {
! ! @Override String cssClassNameImpl() { return "watch"; }
! },
! music {
! ! @Override String cssClassNameImpl() { return "listen"; }
! },
! pr0n {
! ! @Override String cssClassNameImpl() {
! ! ! return getUser().isAdult() ? "watch" : "nothingForYou";
! ! }
! };
!
! abstract String cssClassNameImpl();
! public String cssClassName() { return cssClassNameImpl(); }
}
Samstag, 22. Juni 13
Packages: overriding enum methods
public enum ContentType implements NSKeyValueCoding {
! literature {
! ! @Override public String cssClassName() { return "read"; }
! },
! film {
! ! @Override public String cssClassName() { return "watch"; }
! },
! music {
! ! @Override public String cssClassName() { return "listen"; }
! },
! pr0n {
! ! @Override public String cssClassName() {
! ! ! return getUser().isAdult() ? "watch" : "nothingForYou";
! ! }
! };
! !
! public abstract String cssClassName();
! @Override public void takeValueForKey( Object obj, String s ) { return; }
! @Override public Object valueForKey( String s ) {
! ! try {
! ! ! return this.getClass().getMethod( s, (Class<?>[]) null ).invoke( this, (Object[]) null );
! ! } catch( Exception e ) {
! ! ! throw new RuntimeException( e );
! ! }
! }
}
Samstag, 22. Juni 13
Prep step: own EC class
• You gain a lot of flexibility by using your own EOEditingContext
subclass
• example: logging on saveChanges() or invalidateAllObjects()
• example: undoManager().removeAllActions() after saves
• Changing the superclass later to ERXEC becomes easy
Samstag, 22. Juni 13
Prep step: own DA class
• Create a common superclass between concrete DirectAction
classes and WODirectAction
• Changing the superclass later to ERXDirectAction becomes easy
Samstag, 22. Juni 13
Prep step: own logging class
• Create your own org.apache.log4j.Logger subclass
• Changing the superclass later to ERXLogger becomes easy
Samstag, 22. Juni 13
import org.apache.log4j.Logger;
public class MyLogger extends Logger {
! public MyLogger( String name ) {
! ! super( name );
! }
! public static Factory factory = null;
! static {
! ! String factoryClassName = MyLogger.Factory.class.getName();
! ! try {
! ! ! MyLogger.factory = (Factory) Class.forName( factoryClassName ).newInstance();
! ! } catch( Exception ex ) {
! ! ! System.err.println( "Exception while creating logger factory of class " + factoryClassName + ": " + ex );
! ! }
! }
! public static class Factory implements org.apache.log4j.spi.LoggerFactory {
! ! @Override
! ! public Logger makeNewLoggerInstance( String name ) {
! ! ! return new MyLogger( name );
! ! }
! ! public void loggingConfigurationDidChange() {
! ! }
! }
Your own logging class (1/2)
Samstag, 22. Juni 13
! public static MyLogger getMyLogger( String name ) {
! ! Logger logger = MyLogger.getLogger( name );
! ! if( logger != null && ! (logger instanceof MyLogger) ) {
! ! ! throw new RuntimeException(
! ! ! ! "Can't load Logger for ""
! ! ! ! + name
! ! ! ! + "" because it is not of class MyLogger but ""
! ! ! ! + logger.getClass().getName()
! ! ! ! + "". Check if there is a "log4j.loggerFactory=er.extensions.Logger$Factory" line in your properties."
! ! ! );
! ! }
! ! return (MyLogger) logger;
! }
! public static Logger getLogger( String name ) {
! ! return Logger.getLogger( name, MyLogger.factory );
! }
! public static MyLogger getMyLogger( Class clazz ) {
! ! return MyLogger.getMyLogger( clazz.getName() );
! }
! public static Logger getLogger( Class clazz ) {
! ! return MyLogger.getMyLogger( clazz );
! }
}
Your own logging class (2/2)
Samstag, 22. Juni 13
Prep step: rename enums
• ERXKey constants in new templates could collide with enum
names
• Common collision pattern: uppercase enum with same name as
EO attribute
• Eclipse refactoring tools are your friend
• Make this a separate commit
Samstag, 22. Juni 13
public class MyFlightRoute extends _MyFlightRoute {
! public static enum STATUS {
! ! obsolete,
! ! current,
! ! preliminary,
! ! deleted;
! }
! public void setStatus( STATUS status ) {
! ! super.setStatus( status.name() );
! }
}
enum renames
Samstag, 22. Juni 13
public class MyFlightRoute extends _MyFlightRoute {
! public static enum STATUS {
! ! obsolete,
! ! current,
! ! preliminary,
! ! deleted;
! }
! public void setStatus( STATUS status ) {
! ! super.setStatus( status.name() );
! }
}
public abstract class _MyFlightRoute extends MyEOGenericRecord {
! public static final ERXKey<String> STATUS = new ERXKey<String>("status");
! public static final String STATUS_KEY = STATUS.key();
}
enum renames
Samstag, 22. Juni 13
public class MyFlightRoute extends _MyFlightRoute {
! public static enum STATUS {
! ! obsolete,
! ! current,
! ! preliminary,
! ! deleted;
! }
! public void setStatus( STATUS status ) {
! ! super.setStatus( status.name() );
! }
}
public abstract class _MyFlightRoute extends MyEOGenericRecord {
! public static final ERXKey<String> STATUS = new ERXKey<String>("status");
! public static final String STATUS_KEY = STATUS.key();
}
enum renames
Samstag, 22. Juni 13
public class MyFlightRoute extends _MyFlightRoute {
! public static enum FRSTATUS {
! ! obsolete,
! ! current,
! ! preliminary,
! ! deleted;
! }
! public void setStatus( FRSTATUS status ) {
! ! super.setStatus( status.name() );
! }
}
public abstract class _MyFlightRoute extends MyEOGenericRecord {
! public static final ERXKey<String> STATUS = new ERXKey<String>("status");
! public static final String STATUS_KEY = STATUS.key();
}
enum renames
Samstag, 22. Juni 13
Prep step: instance settings
•-XX:MaxPermSize=256m
Samstag, 22. Juni 13
Wonderization: Frameworks
• Now is the time to start the actual wonderization
• Start by the usual way to import Wonder into Eclipse
• Then add ERJars, ERExtensions,WOOgnl and Wonder‘s
JavaWOExtensions to your project
• And ERPrototypes if you want to use them
• Remove log4j and potentially other jars that are contained in
ERJars (check version compatibilities)
Samstag, 22. Juni 13
Properties file
• Wonder manages nearly all settings through Properties
• Live in file Resources/Properties
• You have to create at least a minimal file to start with
Samstag, 22. Juni 13
Properties file
# OGNL
ognl.active = true
ognl.helperFunctions = true
ognl.inlineBindings = true
ognl.parseStandardTags = false
# Misc
er.extensions.stackTrace.cleanup = true
file.encoding = UTF-8
# EOF
er.extensions.ERXEC.safeLocking = true
er.extensions.ERXEC.useSharedEditingContext = false
er.extensions.ERXEnterpriseObject.applyRestrictingQualifierOnInsert = true
er.extensions.ERXRaiseOnMissingEditingContextDelegate = false
# Migrations
er.migration.migrateAtStartup = true
er.migration.createTablesIfNecessary = true
er.migration.modelNames = MYMODELNAME
MYMODELNAME.MigrationClassPrefix=com.selbstdenker.foo.bar.migration.MYMODELNAME
Samstag, 22. Juni 13
Application.java
• Requirement: subclass ERXApplication
• If you subclassed a custom base class instead of WOApplication,
you can either make that inherit ERXApplication, or copy the
methods you need over to your Application class.
Samstag, 22. Juni 13
public class Application extends ERXApplication {
! public static void main( String[] argv ) {
! ! ERXApplication.main( argv, Application.class );
! }
Application.java (1/2)
Samstag, 22. Juni 13
public class Application extends ERXApplication {
! public static void main( String[] argv ) {
! ! ERXApplication.main( argv, Application.class );
! }
! public Application() {
! ! WOMessage.setDefaultEncoding( "UTF-8" );
! ! ERXMessageEncoding.setDefaultEncodingForAllLanguages( "UTF-8" );
! ! // ...and whatever else you need to have here, but not more.
! ! log.info( "######### Application startup complete #########" );
! }
Application.java (1/2)
Samstag, 22. Juni 13
public class Application extends ERXApplication {
! public static void main( String[] argv ) {
! ! ERXApplication.main( argv, Application.class );
! }
! public Application() {
! ! WOMessage.setDefaultEncoding( "UTF-8" );
! ! ERXMessageEncoding.setDefaultEncodingForAllLanguages( "UTF-8" );
! ! // ...and whatever else you need to have here, but not more.
! ! log.info( "######### Application startup complete #########" );
! }
! // everything that can be deferred better goes here instead
! @Override public void didFinishLaunching() {
! ! new ERXShutdownHook() {
! ! ! @Override public void hook() {
! ! ! ! // cleanup that needs to run when application is shut down
! ! ! }
! ! };
! ! // example for project-specific stuff
! ! taskManager = new BackgroundTaskManager();
! ! taskManager.newRecurringTask( new MySystemState.SystemStateUpdaterTask(), 60 );
! ! super.didFinishLaunching();
! ! log.info( "######### post-startup sequence complete #########" );
! }
Application.java (1/2)
Samstag, 22. Juni 13
public class Application extends ERXApplication {
! public static void main( String[] argv ) {
! ! ERXApplication.main( argv, Application.class );
! }
! public Application() {
! ! WOMessage.setDefaultEncoding( "UTF-8" );
! ! ERXMessageEncoding.setDefaultEncodingForAllLanguages( "UTF-8" );
! ! // ...and whatever else you need to have here, but not more.
! ! log.info( "######### Application startup complete #########" );
! }
! // everything that can be deferred better goes here instead
! @Override public void didFinishLaunching() {
! ! new ERXShutdownHook() {
! ! ! @Override public void hook() {
! ! ! ! // cleanup that needs to run when application is shut down
! ! ! }
! ! };
! ! // example for project-specific stuff
! ! taskManager = new BackgroundTaskManager();
! ! taskManager.newRecurringTask( new MySystemState.SystemStateUpdaterTask(), 60 );
! ! super.didFinishLaunching();
! ! log.info( "######### post-startup sequence complete #########" );
! }
Application.java (1/2)
Samstag, 22. Juni 13
! @Override protected void migrationsWillRun( ERXMigrator migrator ) {
! ! log.info( "Starting migrations" );
! }
!
! @Override protected void migrationsDidRun( ERXMigrator migrator ) {
! ! log.info( "Finished migrations" );
! }
}
Application.java (2/2)
Samstag, 22. Juni 13
! // instead of using a Property, this switches gzip on/off based on system type
! @Override public boolean responseCompressionEnabled() {
! ! switch( systemType() ) {
! ! ! case TESTING! ! : return true;
! ! ! case DEVELOPMENT! : return true;
! ! default!! ! ! : return false; // gzip done by load balancer
! ! }
! }
! @Override protected void migrationsWillRun( ERXMigrator migrator ) {
! ! log.info( "Starting migrations" );
! }
!
! @Override protected void migrationsDidRun( ERXMigrator migrator ) {
! ! log.info( "Finished migrations" );
! }
}
Application.java (2/2)
Samstag, 22. Juni 13
! // instead of using a Property, this switches gzip on/off based on system type
! @Override public boolean responseCompressionEnabled() {
! ! switch( systemType() ) {
! ! ! case TESTING! ! : return true;
! ! ! case DEVELOPMENT! : return true;
! ! default!! ! ! : return false; // gzip done by load balancer
! ! }
! }
! // the default context logging for exceptions is a bit too bulky for my taste, so strip that down a bit
! @Override public NSMutableDictionary extraInformationForExceptionInContext( Exception e, WOContext context ) {
! ! NSMutableDictionary<String,Object> extraInfo = ERXRuntimeUtilities.informationForException( e );
! ! // copy informatinForContext() from ERXApplication, override and strip down
! ! extraInfo.addEntriesFromDictionary( informationForContext( context ) );
! ! extraInfo.addEntriesFromDictionary( ERXRuntimeUtilities.informationForBundles() );
! ! return extraInfo;
! }
! @Override protected void migrationsWillRun( ERXMigrator migrator ) {
! ! log.info( "Starting migrations" );
! }
!
! @Override protected void migrationsDidRun( ERXMigrator migrator ) {
! ! log.info( "Finished migrations" );
! }
}
Application.java (2/2)
Samstag, 22. Juni 13
Session.java
• Requirement: subclass ERXSession
• No code to show, nothing special to adapt
• Except when you had used MultiECLockManager
• If you did and you want to switch to ERXEC autolocking,
remove any code related to MultiECLockManager from your
Session class
Samstag, 22. Juni 13
MyEditingContext.java
• Recommendation: subclass ERXEC
• You need to implement a factory
• You can have multiple factories, like one that produces
autolocking contexts, and another for manual locking, without
having different classes.
Samstag, 22. Juni 13
MyEOEditingContext.java
public class MyEOEditingContext extends ERXEC {
! private boolean doCommitLogging;
! /*
! * Constructors and Factories
! */
! private static Factory _myAutoLockingFactory;
! private static Factory _myManualLockingFactory;
! private static synchronized Factory myAutoLockingFactory() {
! ! if( _myAutoLockingFactory == null ) {
! ! ! _myAutoLockingFactory = new MyECAutoLockingFactory();
! ! }
! ! return _myAutoLockingFactory;
! }
! private static synchronized Factory myManualLockingFactory() {
! ! if( _myManualLockingFactory == null ) {
! ! ! _myManualLockingFactory = new MyECManualLockingFactory();
! ! }
! ! return _myManualLockingFactory;
! }
Samstag, 22. Juni 13
! public static class MyECAutoLockingFactory extends ERXEC.DefaultFactory {
! ! @Override protected EOEditingContext _createEditingContext( EOObjectStore parent ) {
! ! ! MyEOEditingContext ec = new MyEOEditingContext(
! ! ! ! ! parent == null ? EOEditingContext.defaultParentObjectStore() : parent );
! ! ! setDefaultDelegateOnEditingContext( ec );
! ! ! return ec;
! ! }
! }
!
! public static class MyECManualLockingFactory extends ERXEC.DefaultFactory {
! ! @Override protected EOEditingContext _createEditingContext( EOObjectStore parent ) {
! ! ! MyEOEditingContext ec = new MyEOEditingContext(
! ! ! ! ! parent == null ? EOEditingContext.defaultParentObjectStore() : parent ) {
! ! ! ! @Override public boolean useAutoLock() { return false; }
! ! ! ! @Override public boolean coalesceAutoLocks() { return false; }
! ! ! };
! ! ! setDefaultDelegateOnEditingContext( ec );
! ! ! return ec;
! ! }
! }
MyEOEditingContext.java
Samstag, 22. Juni 13
! public static MyEOEditingContext newAutoLockingEC() {
! ! MyEOEditingContext newEC = (MyEOEditingContext) myAutoLockingFactory()._newEditingContext();
! ! newEC.init();
! ! return newEC;
! }
! public static MyEOEditingContext newAutoLockingEC( EOObjectStore objectStore ) {
! ! MyEOEditingContext newEC = (MyEOEditingContext) myAutoLockingFactory()._newEditingContext( objectStore );
! ! newEC.init();
! ! return newEC;
! }
! public static MyEOEditingContext newManualLockingEC() {
! ! MyEOEditingContext newEC = (MyEOEditingContext) myManualLockingFactory()._newEditingContext();
! ! newEC.init();
! ! return newEC;
! }
! public static MyEOEditingContext newManualLockingEC( EOObjectStore objectStore ) {
! ! MyEOEditingContext newEC = (MyEOEditingContext) myManualLockingFactory()._newEditingContext( objectStore );
! ! newEC.init();
! ! return newEC;
! }
! private void init() {
! ! doCommitLogging = true;
! ! setRetainsRegisteredObjects( true );! // http://lists.apple.com/archives/webobjects-dev/2010/Nov/msg00009.html
! }
MyEOEditingContext.java
Samstag, 22. Juni 13
! @Override public void saveChanges() {
! ! StringBuilder buf = null;
! ! if( doCommitLogging ) {
! ! ! buf = new StringBuilder();
! ! ! buf.append( "MyEC" ).append( useAutoLock() ? " autoLocking" : " manualLocking" ).append( " saveChanges()" );
! ! ! StackTraceElement[] stack = new Throwable().getStackTrace();
! ! ! if( stack != null && stack.length > 1 )! buf.append( "; " ).append( stack[1].toString() );
! ! ! Collection<String> updatedClasses = setOfClassesFor( updatedObjects() );
! ! ! Collection<String> insertedClasses = setOfClassesFor( insertedObjects() );
! ! ! Collection<String> deletedClasses = setOfClassesFor( deletedObjects() );
! ! ! if( insertedClasses.size() > 0 ) buf.append( "; ins: " ).append( Joiner.on(",").join( insertedClasses ) );
! ! ! if( updatedClasses.size() > 0 ) buf.append( "; upd: " ).append( Joiner.on(",").join( updatedClasses ) );
! ! ! if( deletedClasses.size() > 0 ) buf.append( "; del: " ).append( Joiner.on(",").join( deletedClasses ) );
! ! }
! ! long ms1 = 0; if( buf != null ) ms1 = System.currentTimeMillis();
! ! super.saveChanges();
! ! long ms2 = 0; if( buf != null ) ms2 = System.currentTimeMillis();
! ! NSUndoManager undoManager = undoManager();
! ! if( undoManager != null ) undoManager.removeAllActions();
! ! long ms3 = 0; if( buf != null ) ms3 = System.currentTimeMillis();
! ! if( buf != null ) {
! ! ! buf.append( "; times " ).append( ms2-ms1 ).append( " " ).append( ms3-ms2 );
! ! ! log.info( buf.toString() );
! ! }
! }
MyEOEditingContext.java
Samstag, 22. Juni 13
! @Override public void saveChanges() {
! ! StringBuilder buf = null;
! ! if( doCommitLogging ) {
! ! ! buf = new StringBuilder();
! ! ! buf.append( "MyEC" ).append( useAutoLock() ? " autoLocking" : " manualLocking" ).append( " saveChanges()" );
! ! ! StackTraceElement[] stack = new Throwable().getStackTrace();
! ! ! if( stack != null && stack.length > 1 )! buf.append( "; " ).append( stack[1].toString() );
! ! ! Collection<String> updatedClasses = setOfClassesFor( updatedObjects() );
! ! ! Collection<String> insertedClasses = setOfClassesFor( insertedObjects() );
! ! ! Collection<String> deletedClasses = setOfClassesFor( deletedObjects() );
! ! ! if( insertedClasses.size() > 0 ) buf.append( "; ins: " ).append( Joiner.on(",").join( insertedClasses ) );
! ! ! if( updatedClasses.size() > 0 ) buf.append( "; upd: " ).append( Joiner.on(",").join( updatedClasses ) );
! ! ! if( deletedClasses.size() > 0 ) buf.append( "; del: " ).append( Joiner.on(",").join( deletedClasses ) );
! ! }
! ! long ms1 = 0; if( buf != null ) ms1 = System.currentTimeMillis();
! ! super.saveChanges();
! ! long ms2 = 0; if( buf != null ) ms2 = System.currentTimeMillis();
! ! NSUndoManager undoManager = undoManager();
! ! if( undoManager != null ) undoManager.removeAllActions();
! ! long ms3 = 0; if( buf != null ) ms3 = System.currentTimeMillis();
! ! if( buf != null ) {
! ! ! buf.append( "; times " ).append( ms2-ms1 ).append( " " ).append( ms3-ms2 );
! ! ! log.info( buf.toString() );
! ! }
! }
MyEOEditingContext.java
MyEC autoLocking saveChanges();
com.selbstdenker.foo.bar.MyJourneyManager.createNewInvoice(MyJourneyManager.java:650);
ins: MyCustomerClaimItem(3),MyCustomerLiability(1),MyCustomerClaim(1);
upd: PDCJourney(1);
times 171 1
Samstag, 22. Juni 13
! private Collection<String> setOfClassesFor( NSArray<EOEnterpriseObject> objects ) {
! ! Multiset<String> classNames = HashMultiset.create();
! ! for( EOEnterpriseObject eo : objects ) {
! ! ! classNames.add( eo.getClass().getSimpleName() );
! ! }
! ! List<String> namesWithCount = Lists.newArrayList();
! ! for( Multiset.Entry entry : classNames.entrySet() ) {
! ! ! namesWithCount.add( entry.getElement() + "(" + entry.getCount() + ")" );
! ! }
! ! return namesWithCount;
! }
! public void setLoggingOnCommit( boolean value ) {
! ! this.doCommitLogging = value;
! }
MyEOEditingContext.java
Samstag, 22. Juni 13
!
public void lockIfManualLocking() {
! ! if( useAutoLock() ) return;
! ! lock();
! }
! public void unlockIfManualLocking() {
! ! if( useAutoLock() ) return;
! ! unlock();
! }
!
! public void saveChangesWithLockIfNecessary() {
! ! if( hasChanges() ) {
! ! ! lockIfManualLocking();
! ! ! try {
! ! ! ! saveChanges();
! ! ! } finally {
! ! ! ! unlockIfManualLocking();
! ! ! }
! ! }
! }
!
}
MyEOEditingContext.java
Samstag, 22. Juni 13
autolock vs. manual
• In general, autolocking is the right choice for almost everything
• Consider using manual locking for db-intensive background tasks
• Main autolocking tradeoff: looots of lock/unlock calls that could
become a significant overhead, depending on what you‘re doing
Samstag, 22. Juni 13
! public static void deleteObsoleteFolderEntries() {
! ! Thread thread = new Thread() {
! ! ! @Override
! ! ! public void run() {
! ! ! ! log.info( "deleteObsoleteFolderEntries: starting" );
! ! ! ! MyEOEditingContext ec = MyEOEditingContext.newManualLockingEC();
! ! ! ! ec.lock();
! ! ! ! try {
! ! ! ! ! MyJourneyFolderEntry.deleteObsoleteEntries( ec );
! ! ! ! ! ec.saveChanges();
! ! ! ! } catch( Exception e ) {
! ! ! ! ! ec.revert();
! ! ! ! } finally {
! ! ! ! ! ec.unlock();
! ! ! ! }
! ! ! ! log.info( "deleteObsoleteFolderEntries: completed" );
! ! ! }
! ! };
! ! thread.start();
! }
Manual locking case example
Samstag, 22. Juni 13
! public static void deleteObsoleteFolderEntries() {
! ! Thread thread = new Thread() {
! ! ! @Override
! ! ! public void run() {
! ! ! ! log.info( "deleteObsoleteFolderEntries: starting" );
! ! ! ! MyEOEditingContext ec = MyEOEditingContext.newManualLockingEC();
! ! ! ! ec.lockIfManualLocking();
! ! ! ! try {
! ! ! ! ! MyJourneyFolderEntry.deleteObsoleteEntries( ec );
! ! ! ! ! ec.saveChanges();
! ! ! ! } catch( Exception e ) {
! ! ! ! ! ec.revert();
! ! ! ! } finally {
! ! ! ! ! ec.unlockIfManualLocking();
! ! ! ! }
! ! ! ! log.info( "deleteObsoleteFolderEntries: completed" );
! ! ! }
! ! };
! ! thread.start();
! }
Manual locking case example
Samstag, 22. Juni 13
ERXGenericRecord
• Requirement: subclass ERXGenericRecord
• With EOGenerator, simply change your template‘s superclass
declaration and import statements
• Of course you can change them to your own MyGenericRecord
class instead, and let that extend ERXGenericRecord
• If you had a delegate in your EC to do stuff before saves, you can
now use ERXGenericRecord.willUpdate() and .willInsert()
instead
Samstag, 22. Juni 13
EO Templates
• Use Wonder templates from WOLips
• There‘s a wiki page with all sorts of alternatives
• In any case, take one that defines proper ERXKey constants
Samstag, 22. Juni 13
ERXDirectAction
• Requirement: subclass ERXDirectAction
• As usual, you can make your own base class in between
Samstag, 22. Juni 13
You‘re done!
Samstag, 22. Juni 13
You‘re done!
almost...
Samstag, 22. Juni 13
Suggestions to proceed
• Beautify your qualifiers
• Migrations
• Array operators and bindings
Samstag, 22. Juni 13
ERX*Qualifier, ERXKey and ERXQ
public class MyFlightRoute extends _MyFlightRoute {
! public static enum FRSTATUS {
! ! obsolete,
! ! current,
! ! preliminary,
! ! deleted;
! }
! public void setStatus( FRSTATUS status ) {
! ! super.setStatus( status.name() );
! }
}
public abstract class _MyFlightRoute extends MyEOGenericRecord {
! public static final ERXKey<String> STATUS = new ERXKey<String>("status");
! public static final String STATUS_KEY = STATUS.key();
}
Samstag, 22. Juni 13
EOQualifier flightRouteValidQualifier =
! ! MyFlightRoute.STATUS.eq( FRSTATUS.current.name() ).or(
! ! MyFlightRoute.STATUS.eq( FRSTATUS.preliminary.name() )
);
EOQualifier flightRouteValidQualifier = ERXQ.or(
! ! MyFlightRoute.STATUS.eq( FRSTATUS.current.name() ),
! ! MyFlightRoute.STATUS.eq( FRSTATUS.preliminary.name() )
);
EOQualifier flightRouteValidQualifier = new EOOrQualifier( new NSArray( new Object[]{
! new EOKeyValueQualifier( MyFlightRoute.STATUS_KEY, EOQualifier.QualifierOperatorEqual, FRSTATUS.current.name() ),
! new EOKeyValueQualifier( MyFlightRoute.STATUS_KEY, EOQualifier.QualifierOperatorEqual, FRSTATUS.preliminary.name() )
} ) );
EOQualifier flightRouteValidQualifier =
! ! MyFlightRoute.STATUS.inObjects( FRSTATUS.current.name(), FRSTATUS.preliminary.name() );
ERX*Qualifier, ERXKey and ERXQ
Samstag, 22. Juni 13
public class MYMODELNAME17 extends MyMigration {
! @Override public void upgrade( EOEditingContext editingContext, ERXMigrationDatabase database ) throws Throwable {
! ! ERXMigrationTable journeyTable = database.existingTableNamed( MyJourney.ENTITY_NAME );
! ! journeyTable.newFlagBooleanColumn( MyJourney.MY_NEW_ATTR_KEY, ALLOWS_NULL );
! !
! ! String sql = "UPDATE MyJourney SET myNewAttr = false WHERE customerRef IN (...whatever...)";
! ! NSLog.out.appendln( "Executing SQL: " + sql );
! ! ERXJDBCUtilities.executeUpdate( database.adaptorChannel(), sql, true );
! ! MyUserRole specialRole = MyUserRole.newInEc( editingContext );
! ! specialRole.setName( "Speziaaaal" );
! ! specialRole.setRoleType( MyUserRole.ROLETYPE.special.name() );
! }
}
package com.selbstdenker.foo.bar.migration;
import com.webobjects.eocontrol.EOEditingContext;
import er.extensions.migration.ERXMigrationDatabase;
import er.extensions.migration.ERXMigrationDatabase.Migration;
public abstract class MyMigration extends Migration {
! @Override public void downgrade( EOEditingContext editingContext, ERXMigrationDatabase database ) throws Throwable {
! ! // do nothing
! }
}
Migrations
Samstag, 22. Juni 13
JourneyElementRepetition : WORepetition {
! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus;
! item = aPassenger;
}
Array operators and Bindings
Samstag, 22. Juni 13
<wo:if condition = "$selectedJourney.passengerArray.@isEmpty">
! <p>blah</p>
</wo:if>
JourneyElementRepetition : WORepetition {
! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus;
! item = aPassenger;
}
Array operators and Bindings
Samstag, 22. Juni 13
// valid
<wo:if condition = "$selectedJourney.passengerArray.@isEmpty">
! <p>blah</p>
</wo:if>
JourneyElementRepetition : WORepetition {
! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus;
! item = aPassenger;
}
Array operators and Bindings
Samstag, 22. Juni 13
// valid
<wo:if condition = "$selectedJourney.passengerArray.@isEmpty">
! <p>blah</p>
</wo:if>
JourneyElementRepetition : WORepetition {
! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus;
! item = aPassenger;
}
Array operators and Bindings
Samstag, 22. Juni 13
// valid
<wo:if condition = "$selectedJourney.passengerArray.@isEmpty">
! <p>blah</p>
</wo:if>
JourneyElementRepetition : WORepetition {
! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus;
! item = aPassenger;
}
Array operators and Bindings
Samstag, 22. Juni 13
Information sources
• Wiki page „Project Wonder Installation“
• Wiki page „Integrate Wonder into an Existing Application“
• Wiki page „EOGenerator Templates and Additions“
• Wiki page „UTF-8 Encoding Tips“
• projectlombok.org
Samstag, 22. Juni 13
Q&A
email: maik@selbstdenker.ag
twitter and app.net: @maikm
Samstag, 22. Juni 13

More Related Content

Viewers also liked

iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative version
WO Community
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWS
WO Community
 
Build and deployment
Build and deploymentBuild and deployment
Build and deployment
WO Community
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnit
WO Community
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W
WO Community
 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERREST
WO Community
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systems
WO Community
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real World
WO Community
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
WO Community
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
WO Community
 
WOver
WOverWOver
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
WO Community
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache Cayenne
WO Community
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on Windows
WO Community
 
High availability
High availabilityHigh availability
High availability
WO Community
 
KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
WO Community
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" pattern
WO Community
 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
WO Community
 

Viewers also liked (18)

iOS for ERREST - alternative version
iOS for ERREST - alternative versioniOS for ERREST - alternative version
iOS for ERREST - alternative version
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWS
 
Build and deployment
Build and deploymentBuild and deployment
Build and deployment
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnit
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W
 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERREST
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systems
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real World
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
 
WOver
WOverWOver
WOver
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache Cayenne
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on Windows
 
High availability
High availabilityHigh availability
High availability
 
KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" pattern
 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
 

Similar to Migrating existing Projects to Wonder

Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)
Martijn Verburg
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
Andres Almiray
 
What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?
Christophe Porteneuve
 
Grooscript greach 2015
Grooscript greach 2015Grooscript greach 2015
Grooscript greach 2015
Jorge Franco Leza
 
Modeling Patterns for JavaScript Browser-Based Games
Modeling Patterns for JavaScript Browser-Based GamesModeling Patterns for JavaScript Browser-Based Games
Modeling Patterns for JavaScript Browser-Based Games
Ray Toal
 
Connect2016 AD1387 Integrate with XPages and Java
Connect2016 AD1387 Integrate with XPages and JavaConnect2016 AD1387 Integrate with XPages and Java
Connect2016 AD1387 Integrate with XPages and Java
Julian Robichaux
 
AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...
AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...
AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...
panagenda
 
Developing Useful APIs
Developing Useful APIsDeveloping Useful APIs
Developing Useful APIs
Dmitry Buzdin
 
Java Quiz Questions
Java Quiz QuestionsJava Quiz Questions
Java Quiz Questions
CodeOps Technologies LLP
 
Java for beginners
Java for beginnersJava for beginners
Java for beginners
Saeid Zebardast
 
Javaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 GroovytestingJavaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 Groovytesting
Andres Almiray
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
James Williams
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8conf
GR8Conf
 
Webinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and MorphiaWebinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and Morphia
MongoDB
 
Having Fun with Kotlin Android - DILo Surabaya
Having Fun with Kotlin Android - DILo SurabayaHaving Fun with Kotlin Android - DILo Surabaya
Having Fun with Kotlin Android - DILo Surabaya
DILo Surabaya
 
Mastering Java ByteCode
Mastering Java ByteCodeMastering Java ByteCode
Mastering Java ByteCode
Ecommerce Solution Provider SysIQ
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
Praveen Puglia
 
Java.lang.object
Java.lang.objectJava.lang.object
Java.lang.object
Soham Sengupta
 
BookStoreCXFWS.classpathBookStoreCXFWS.project CXF.docx
BookStoreCXFWS.classpathBookStoreCXFWS.project  CXF.docxBookStoreCXFWS.classpathBookStoreCXFWS.project  CXF.docx
BookStoreCXFWS.classpathBookStoreCXFWS.project CXF.docx
hartrobert670
 
Refactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartRefactoring In Tdd The Missing Part
Refactoring In Tdd The Missing Part
Gabriele Lana
 

Similar to Migrating existing Projects to Wonder (20)

Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)Back to the future with Java 7 (Geekout June/2011)
Back to the future with Java 7 (Geekout June/2011)
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
 
What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?What's up with Prototype and script.aculo.us?
What's up with Prototype and script.aculo.us?
 
Grooscript greach 2015
Grooscript greach 2015Grooscript greach 2015
Grooscript greach 2015
 
Modeling Patterns for JavaScript Browser-Based Games
Modeling Patterns for JavaScript Browser-Based GamesModeling Patterns for JavaScript Browser-Based Games
Modeling Patterns for JavaScript Browser-Based Games
 
Connect2016 AD1387 Integrate with XPages and Java
Connect2016 AD1387 Integrate with XPages and JavaConnect2016 AD1387 Integrate with XPages and Java
Connect2016 AD1387 Integrate with XPages and Java
 
AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...
AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...
AD1387: Outside The Box: Integrating with Non-Domino Apps using XPages and Ja...
 
Developing Useful APIs
Developing Useful APIsDeveloping Useful APIs
Developing Useful APIs
 
Java Quiz Questions
Java Quiz QuestionsJava Quiz Questions
Java Quiz Questions
 
Java for beginners
Java for beginnersJava for beginners
Java for beginners
 
Javaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 GroovytestingJavaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 Groovytesting
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8conf
 
Webinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and MorphiaWebinar: MongoDB Persistence with Java and Morphia
Webinar: MongoDB Persistence with Java and Morphia
 
Having Fun with Kotlin Android - DILo Surabaya
Having Fun with Kotlin Android - DILo SurabayaHaving Fun with Kotlin Android - DILo Surabaya
Having Fun with Kotlin Android - DILo Surabaya
 
Mastering Java ByteCode
Mastering Java ByteCodeMastering Java ByteCode
Mastering Java ByteCode
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
 
Java.lang.object
Java.lang.objectJava.lang.object
Java.lang.object
 
BookStoreCXFWS.classpathBookStoreCXFWS.project CXF.docx
BookStoreCXFWS.classpathBookStoreCXFWS.project  CXF.docxBookStoreCXFWS.classpathBookStoreCXFWS.project  CXF.docx
BookStoreCXFWS.classpathBookStoreCXFWS.project CXF.docx
 
Refactoring In Tdd The Missing Part
Refactoring In Tdd The Missing PartRefactoring In Tdd The Missing Part
Refactoring In Tdd The Missing Part
 

More from WO Community

Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languages
WO Community
 
WOdka
WOdkaWOdka
ERGroupware
ERGroupwareERGroupware
ERGroupware
WO Community
 
D2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRollerD2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRoller
WO Community
 
CMS / BLOG and SnoWOman
CMS / BLOG and SnoWOmanCMS / BLOG and SnoWOman
CMS / BLOG and SnoWOman
WO Community
 
Using GIT
Using GITUsing GIT
Using GIT
WO Community
 
Persistent Session Storage
Persistent Session StoragePersistent Session Storage
Persistent Session Storage
WO Community
 
Back2 future
Back2 futureBack2 future
Back2 future
WO Community
 
WebObjects Optimization
WebObjects OptimizationWebObjects Optimization
WebObjects Optimization
WO Community
 
Dynamic Elements
Dynamic ElementsDynamic Elements
Dynamic Elements
WO Community
 
Practical ERSync
Practical ERSyncPractical ERSync
Practical ERSync
WO Community
 
ERRest: the Basics
ERRest: the BasicsERRest: the Basics
ERRest: the Basics
WO Community
 

More from WO Community (12)

Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languages
 
WOdka
WOdkaWOdka
WOdka
 
ERGroupware
ERGroupwareERGroupware
ERGroupware
 
D2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRollerD2W Branding Using jQuery ThemeRoller
D2W Branding Using jQuery ThemeRoller
 
CMS / BLOG and SnoWOman
CMS / BLOG and SnoWOmanCMS / BLOG and SnoWOman
CMS / BLOG and SnoWOman
 
Using GIT
Using GITUsing GIT
Using GIT
 
Persistent Session Storage
Persistent Session StoragePersistent Session Storage
Persistent Session Storage
 
Back2 future
Back2 futureBack2 future
Back2 future
 
WebObjects Optimization
WebObjects OptimizationWebObjects Optimization
WebObjects Optimization
 
Dynamic Elements
Dynamic ElementsDynamic Elements
Dynamic Elements
 
Practical ERSync
Practical ERSyncPractical ERSync
Practical ERSync
 
ERRest: the Basics
ERRest: the BasicsERRest: the Basics
ERRest: the Basics
 

Recently uploaded

Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Data structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdfData structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdf
TIPNGVN2
 
“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”
Claudio Di Ciccio
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
Matthew Sinclair
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
名前 です男
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
Kumud Singh
 
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex ProofszkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
Alex Pruden
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
Rohit Gautam
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
Neo4j
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
ThomasParaiso2
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 

Recently uploaded (20)

Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Data structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdfData structures and Algorithms in Python.pdf
Data structures and Algorithms in Python.pdf
 
“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”“I’m still / I’m still / Chaining from the Block”
“I’m still / I’m still / Chaining from the Block”
 
20240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 202420240605 QFM017 Machine Intelligence Reading List May 2024
20240605 QFM017 Machine Intelligence Reading List May 2024
 
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
みなさんこんにちはこれ何文字まで入るの?40文字以下不可とか本当に意味わからないけどこれ限界文字数書いてないからマジでやばい文字数いけるんじゃないの?えこ...
 
Mind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AIMind map of terminologies used in context of Generative AI
Mind map of terminologies used in context of Generative AI
 
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex ProofszkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
zkStudyClub - Reef: Fast Succinct Non-Interactive Zero-Knowledge Regex Proofs
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Large Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial ApplicationsLarge Language Model (LLM) and it’s Geospatial Applications
Large Language Model (LLM) and it’s Geospatial Applications
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 

Migrating existing Projects to Wonder

  • 1. Migrating existing Projects to Wonder Maik Musall, Selbstdenker AG Samstag, 22. Juni 13
  • 2. • Existing application of some complexity • Using perhaps custom frameworks, but not yet Wonder • Want to use Wonder for several reasons, but uncertain where to start and how to manage the migration process The Task Samstag, 22. Juni 13
  • 3. Goals • Make the switch at a chosen, planned point in time • Being able to switch back to the non-Wonder version if problems come up in production • Identify which steps to do when, and how Samstag, 22. Juni 13
  • 4. The Big Steps • Move to Git (if you haven‘t already) • Prepare the code base ahead of the actual wonderization • Create a wonderization branch • Wonderize in that branch, periodically merge new stuff from your main branch • Release and celebrate Samstag, 22. Juni 13
  • 5. Prep step: Move to Git • You‘ll need branches during the migration • Wonder is Git-based anyway • It just makes everything easier • Plan some time to get up to speed using Git first • Use Sourcetree Samstag, 22. Juni 13
  • 6. Prep step: Move to Git Time release branches masterdevelop hotfixes feature branches Feature for future release Tag 1.0 Major feature for next release From this point on, “next release” means the release after 1.0 Severe bug fixed for production: hotfix 0.2 Bugfixes from rel. branch may be continuously merged back into develop Tag 0.1 Tag 0.2 Incorporate bugfix in develop Only bugfixes! Start of release branch for 1.0 Author: Vincent Driessen Samstag, 22. Juni 13
  • 7. Prep step: Move to Git Time release branches masterdevelop hotfixes feature branches Feature for future release Major feature for next release Severe bug fixed for production: hotfix 0.2 Tag 0.1 Tag 0.2 Incorporate bugfix in develop Start ofSamstag, 22. Juni 13
  • 8. Prep step: Move to Git release Tag 1.0 From this point on, “next release” means the release after 1.0 Bugfixes from rel. branch may be Tag 0.2 Incorporate bugfix in develop Only bugfixes! Start of release branch for 1.0 Samstag, 22. Juni 13
  • 9. Prep step: Move to Git Tag 1.0 From this point on, “next release” means the release after 1.0 Bugfixes from rel. branch may be continuously merged back into develop Only bugfixes! Start of release branch for 1.0 Samstag, 22. Juni 13
  • 10. Managing Wonderization in Git first wonderized release second wonderized release conventional version as fallback conventional version as fallback wonderized version merged into main 1.0 1.0 develop wonderize 1.1 feature 1.2 1.2 1.3 1.3 2.0 1.2 Samstag, 22. Juni 13
  • 11. Prep step: Java packages • You can‘t inherit from packaged classes if your classes aren‘t in packages, too • So if you haven‘t already, create packages and move all your sources into them • Benefit: clarified namespaces for your stuff Samstag, 22. Juni 13
  • 12. Java packages gotchas • Getters and setters in components need to be(come) public • Check class.getName() calls to become class.getSimpleName() • Class.forName() needs full packaged path • Overridden methods in enums become unreachable code in WO bindings Samstag, 22. Juni 13
  • 13. public enum ContentType { ! literature { ! ! @Override public String cssClassName() { return "read"; } ! }, ! film { ! ! @Override public String cssClassName() { return "watch"; } ! }, ! music { ! ! @Override public String cssClassName() { return "listen"; } ! }; ! ! public abstract String cssClassName(); ! public boolean isAvailable() { return true; } } Packages: overriding enum methods Samstag, 22. Juni 13
  • 14. Packages: overriding enum methods public enum ContentType { ! literature { ! ! @Override public String cssClassName() { return "read"; } ! }, ! film { ! ! @Override public String cssClassName() { return "watch"; } ! }, ! music { ! ! @Override public String cssClassName() { return "listen"; } ! }, ! pr0n { ! ! @Override public String cssClassName() { ! ! ! return getUser().isAdult() ? "watch" : "nothingForYou"; ! ! } ! }; ! ! public abstract String cssClassName(); } Samstag, 22. Juni 13
  • 15. Packages: overriding enum methods public enum ContentType { ! literature { ! ! @Override String cssClassNameImpl() { return "read"; } ! }, ! film { ! ! @Override String cssClassNameImpl() { return "watch"; } ! }, ! music { ! ! @Override String cssClassNameImpl() { return "listen"; } ! }, ! pr0n { ! ! @Override String cssClassNameImpl() { ! ! ! return getUser().isAdult() ? "watch" : "nothingForYou"; ! ! } ! }; ! ! abstract String cssClassNameImpl(); ! public String cssClassName() { return cssClassNameImpl(); } } Samstag, 22. Juni 13
  • 16. Packages: overriding enum methods public enum ContentType implements NSKeyValueCoding { ! literature { ! ! @Override public String cssClassName() { return "read"; } ! }, ! film { ! ! @Override public String cssClassName() { return "watch"; } ! }, ! music { ! ! @Override public String cssClassName() { return "listen"; } ! }, ! pr0n { ! ! @Override public String cssClassName() { ! ! ! return getUser().isAdult() ? "watch" : "nothingForYou"; ! ! } ! }; ! ! ! public abstract String cssClassName(); ! @Override public void takeValueForKey( Object obj, String s ) { return; } ! @Override public Object valueForKey( String s ) { ! ! try { ! ! ! return this.getClass().getMethod( s, (Class<?>[]) null ).invoke( this, (Object[]) null ); ! ! } catch( Exception e ) { ! ! ! throw new RuntimeException( e ); ! ! } ! } } Samstag, 22. Juni 13
  • 17. Prep step: own EC class • You gain a lot of flexibility by using your own EOEditingContext subclass • example: logging on saveChanges() or invalidateAllObjects() • example: undoManager().removeAllActions() after saves • Changing the superclass later to ERXEC becomes easy Samstag, 22. Juni 13
  • 18. Prep step: own DA class • Create a common superclass between concrete DirectAction classes and WODirectAction • Changing the superclass later to ERXDirectAction becomes easy Samstag, 22. Juni 13
  • 19. Prep step: own logging class • Create your own org.apache.log4j.Logger subclass • Changing the superclass later to ERXLogger becomes easy Samstag, 22. Juni 13
  • 20. import org.apache.log4j.Logger; public class MyLogger extends Logger { ! public MyLogger( String name ) { ! ! super( name ); ! } ! public static Factory factory = null; ! static { ! ! String factoryClassName = MyLogger.Factory.class.getName(); ! ! try { ! ! ! MyLogger.factory = (Factory) Class.forName( factoryClassName ).newInstance(); ! ! } catch( Exception ex ) { ! ! ! System.err.println( "Exception while creating logger factory of class " + factoryClassName + ": " + ex ); ! ! } ! } ! public static class Factory implements org.apache.log4j.spi.LoggerFactory { ! ! @Override ! ! public Logger makeNewLoggerInstance( String name ) { ! ! ! return new MyLogger( name ); ! ! } ! ! public void loggingConfigurationDidChange() { ! ! } ! } Your own logging class (1/2) Samstag, 22. Juni 13
  • 21. ! public static MyLogger getMyLogger( String name ) { ! ! Logger logger = MyLogger.getLogger( name ); ! ! if( logger != null && ! (logger instanceof MyLogger) ) { ! ! ! throw new RuntimeException( ! ! ! ! "Can't load Logger for "" ! ! ! ! + name ! ! ! ! + "" because it is not of class MyLogger but "" ! ! ! ! + logger.getClass().getName() ! ! ! ! + "". Check if there is a "log4j.loggerFactory=er.extensions.Logger$Factory" line in your properties." ! ! ! ); ! ! } ! ! return (MyLogger) logger; ! } ! public static Logger getLogger( String name ) { ! ! return Logger.getLogger( name, MyLogger.factory ); ! } ! public static MyLogger getMyLogger( Class clazz ) { ! ! return MyLogger.getMyLogger( clazz.getName() ); ! } ! public static Logger getLogger( Class clazz ) { ! ! return MyLogger.getMyLogger( clazz ); ! } } Your own logging class (2/2) Samstag, 22. Juni 13
  • 22. Prep step: rename enums • ERXKey constants in new templates could collide with enum names • Common collision pattern: uppercase enum with same name as EO attribute • Eclipse refactoring tools are your friend • Make this a separate commit Samstag, 22. Juni 13
  • 23. public class MyFlightRoute extends _MyFlightRoute { ! public static enum STATUS { ! ! obsolete, ! ! current, ! ! preliminary, ! ! deleted; ! } ! public void setStatus( STATUS status ) { ! ! super.setStatus( status.name() ); ! } } enum renames Samstag, 22. Juni 13
  • 24. public class MyFlightRoute extends _MyFlightRoute { ! public static enum STATUS { ! ! obsolete, ! ! current, ! ! preliminary, ! ! deleted; ! } ! public void setStatus( STATUS status ) { ! ! super.setStatus( status.name() ); ! } } public abstract class _MyFlightRoute extends MyEOGenericRecord { ! public static final ERXKey<String> STATUS = new ERXKey<String>("status"); ! public static final String STATUS_KEY = STATUS.key(); } enum renames Samstag, 22. Juni 13
  • 25. public class MyFlightRoute extends _MyFlightRoute { ! public static enum STATUS { ! ! obsolete, ! ! current, ! ! preliminary, ! ! deleted; ! } ! public void setStatus( STATUS status ) { ! ! super.setStatus( status.name() ); ! } } public abstract class _MyFlightRoute extends MyEOGenericRecord { ! public static final ERXKey<String> STATUS = new ERXKey<String>("status"); ! public static final String STATUS_KEY = STATUS.key(); } enum renames Samstag, 22. Juni 13
  • 26. public class MyFlightRoute extends _MyFlightRoute { ! public static enum FRSTATUS { ! ! obsolete, ! ! current, ! ! preliminary, ! ! deleted; ! } ! public void setStatus( FRSTATUS status ) { ! ! super.setStatus( status.name() ); ! } } public abstract class _MyFlightRoute extends MyEOGenericRecord { ! public static final ERXKey<String> STATUS = new ERXKey<String>("status"); ! public static final String STATUS_KEY = STATUS.key(); } enum renames Samstag, 22. Juni 13
  • 27. Prep step: instance settings •-XX:MaxPermSize=256m Samstag, 22. Juni 13
  • 28. Wonderization: Frameworks • Now is the time to start the actual wonderization • Start by the usual way to import Wonder into Eclipse • Then add ERJars, ERExtensions,WOOgnl and Wonder‘s JavaWOExtensions to your project • And ERPrototypes if you want to use them • Remove log4j and potentially other jars that are contained in ERJars (check version compatibilities) Samstag, 22. Juni 13
  • 29. Properties file • Wonder manages nearly all settings through Properties • Live in file Resources/Properties • You have to create at least a minimal file to start with Samstag, 22. Juni 13
  • 30. Properties file # OGNL ognl.active = true ognl.helperFunctions = true ognl.inlineBindings = true ognl.parseStandardTags = false # Misc er.extensions.stackTrace.cleanup = true file.encoding = UTF-8 # EOF er.extensions.ERXEC.safeLocking = true er.extensions.ERXEC.useSharedEditingContext = false er.extensions.ERXEnterpriseObject.applyRestrictingQualifierOnInsert = true er.extensions.ERXRaiseOnMissingEditingContextDelegate = false # Migrations er.migration.migrateAtStartup = true er.migration.createTablesIfNecessary = true er.migration.modelNames = MYMODELNAME MYMODELNAME.MigrationClassPrefix=com.selbstdenker.foo.bar.migration.MYMODELNAME Samstag, 22. Juni 13
  • 31. Application.java • Requirement: subclass ERXApplication • If you subclassed a custom base class instead of WOApplication, you can either make that inherit ERXApplication, or copy the methods you need over to your Application class. Samstag, 22. Juni 13
  • 32. public class Application extends ERXApplication { ! public static void main( String[] argv ) { ! ! ERXApplication.main( argv, Application.class ); ! } Application.java (1/2) Samstag, 22. Juni 13
  • 33. public class Application extends ERXApplication { ! public static void main( String[] argv ) { ! ! ERXApplication.main( argv, Application.class ); ! } ! public Application() { ! ! WOMessage.setDefaultEncoding( "UTF-8" ); ! ! ERXMessageEncoding.setDefaultEncodingForAllLanguages( "UTF-8" ); ! ! // ...and whatever else you need to have here, but not more. ! ! log.info( "######### Application startup complete #########" ); ! } Application.java (1/2) Samstag, 22. Juni 13
  • 34. public class Application extends ERXApplication { ! public static void main( String[] argv ) { ! ! ERXApplication.main( argv, Application.class ); ! } ! public Application() { ! ! WOMessage.setDefaultEncoding( "UTF-8" ); ! ! ERXMessageEncoding.setDefaultEncodingForAllLanguages( "UTF-8" ); ! ! // ...and whatever else you need to have here, but not more. ! ! log.info( "######### Application startup complete #########" ); ! } ! // everything that can be deferred better goes here instead ! @Override public void didFinishLaunching() { ! ! new ERXShutdownHook() { ! ! ! @Override public void hook() { ! ! ! ! // cleanup that needs to run when application is shut down ! ! ! } ! ! }; ! ! // example for project-specific stuff ! ! taskManager = new BackgroundTaskManager(); ! ! taskManager.newRecurringTask( new MySystemState.SystemStateUpdaterTask(), 60 ); ! ! super.didFinishLaunching(); ! ! log.info( "######### post-startup sequence complete #########" ); ! } Application.java (1/2) Samstag, 22. Juni 13
  • 35. public class Application extends ERXApplication { ! public static void main( String[] argv ) { ! ! ERXApplication.main( argv, Application.class ); ! } ! public Application() { ! ! WOMessage.setDefaultEncoding( "UTF-8" ); ! ! ERXMessageEncoding.setDefaultEncodingForAllLanguages( "UTF-8" ); ! ! // ...and whatever else you need to have here, but not more. ! ! log.info( "######### Application startup complete #########" ); ! } ! // everything that can be deferred better goes here instead ! @Override public void didFinishLaunching() { ! ! new ERXShutdownHook() { ! ! ! @Override public void hook() { ! ! ! ! // cleanup that needs to run when application is shut down ! ! ! } ! ! }; ! ! // example for project-specific stuff ! ! taskManager = new BackgroundTaskManager(); ! ! taskManager.newRecurringTask( new MySystemState.SystemStateUpdaterTask(), 60 ); ! ! super.didFinishLaunching(); ! ! log.info( "######### post-startup sequence complete #########" ); ! } Application.java (1/2) Samstag, 22. Juni 13
  • 36. ! @Override protected void migrationsWillRun( ERXMigrator migrator ) { ! ! log.info( "Starting migrations" ); ! } ! ! @Override protected void migrationsDidRun( ERXMigrator migrator ) { ! ! log.info( "Finished migrations" ); ! } } Application.java (2/2) Samstag, 22. Juni 13
  • 37. ! // instead of using a Property, this switches gzip on/off based on system type ! @Override public boolean responseCompressionEnabled() { ! ! switch( systemType() ) { ! ! ! case TESTING! ! : return true; ! ! ! case DEVELOPMENT! : return true; ! ! default!! ! ! : return false; // gzip done by load balancer ! ! } ! } ! @Override protected void migrationsWillRun( ERXMigrator migrator ) { ! ! log.info( "Starting migrations" ); ! } ! ! @Override protected void migrationsDidRun( ERXMigrator migrator ) { ! ! log.info( "Finished migrations" ); ! } } Application.java (2/2) Samstag, 22. Juni 13
  • 38. ! // instead of using a Property, this switches gzip on/off based on system type ! @Override public boolean responseCompressionEnabled() { ! ! switch( systemType() ) { ! ! ! case TESTING! ! : return true; ! ! ! case DEVELOPMENT! : return true; ! ! default!! ! ! : return false; // gzip done by load balancer ! ! } ! } ! // the default context logging for exceptions is a bit too bulky for my taste, so strip that down a bit ! @Override public NSMutableDictionary extraInformationForExceptionInContext( Exception e, WOContext context ) { ! ! NSMutableDictionary<String,Object> extraInfo = ERXRuntimeUtilities.informationForException( e ); ! ! // copy informatinForContext() from ERXApplication, override and strip down ! ! extraInfo.addEntriesFromDictionary( informationForContext( context ) ); ! ! extraInfo.addEntriesFromDictionary( ERXRuntimeUtilities.informationForBundles() ); ! ! return extraInfo; ! } ! @Override protected void migrationsWillRun( ERXMigrator migrator ) { ! ! log.info( "Starting migrations" ); ! } ! ! @Override protected void migrationsDidRun( ERXMigrator migrator ) { ! ! log.info( "Finished migrations" ); ! } } Application.java (2/2) Samstag, 22. Juni 13
  • 39. Session.java • Requirement: subclass ERXSession • No code to show, nothing special to adapt • Except when you had used MultiECLockManager • If you did and you want to switch to ERXEC autolocking, remove any code related to MultiECLockManager from your Session class Samstag, 22. Juni 13
  • 40. MyEditingContext.java • Recommendation: subclass ERXEC • You need to implement a factory • You can have multiple factories, like one that produces autolocking contexts, and another for manual locking, without having different classes. Samstag, 22. Juni 13
  • 41. MyEOEditingContext.java public class MyEOEditingContext extends ERXEC { ! private boolean doCommitLogging; ! /* ! * Constructors and Factories ! */ ! private static Factory _myAutoLockingFactory; ! private static Factory _myManualLockingFactory; ! private static synchronized Factory myAutoLockingFactory() { ! ! if( _myAutoLockingFactory == null ) { ! ! ! _myAutoLockingFactory = new MyECAutoLockingFactory(); ! ! } ! ! return _myAutoLockingFactory; ! } ! private static synchronized Factory myManualLockingFactory() { ! ! if( _myManualLockingFactory == null ) { ! ! ! _myManualLockingFactory = new MyECManualLockingFactory(); ! ! } ! ! return _myManualLockingFactory; ! } Samstag, 22. Juni 13
  • 42. ! public static class MyECAutoLockingFactory extends ERXEC.DefaultFactory { ! ! @Override protected EOEditingContext _createEditingContext( EOObjectStore parent ) { ! ! ! MyEOEditingContext ec = new MyEOEditingContext( ! ! ! ! ! parent == null ? EOEditingContext.defaultParentObjectStore() : parent ); ! ! ! setDefaultDelegateOnEditingContext( ec ); ! ! ! return ec; ! ! } ! } ! ! public static class MyECManualLockingFactory extends ERXEC.DefaultFactory { ! ! @Override protected EOEditingContext _createEditingContext( EOObjectStore parent ) { ! ! ! MyEOEditingContext ec = new MyEOEditingContext( ! ! ! ! ! parent == null ? EOEditingContext.defaultParentObjectStore() : parent ) { ! ! ! ! @Override public boolean useAutoLock() { return false; } ! ! ! ! @Override public boolean coalesceAutoLocks() { return false; } ! ! ! }; ! ! ! setDefaultDelegateOnEditingContext( ec ); ! ! ! return ec; ! ! } ! } MyEOEditingContext.java Samstag, 22. Juni 13
  • 43. ! public static MyEOEditingContext newAutoLockingEC() { ! ! MyEOEditingContext newEC = (MyEOEditingContext) myAutoLockingFactory()._newEditingContext(); ! ! newEC.init(); ! ! return newEC; ! } ! public static MyEOEditingContext newAutoLockingEC( EOObjectStore objectStore ) { ! ! MyEOEditingContext newEC = (MyEOEditingContext) myAutoLockingFactory()._newEditingContext( objectStore ); ! ! newEC.init(); ! ! return newEC; ! } ! public static MyEOEditingContext newManualLockingEC() { ! ! MyEOEditingContext newEC = (MyEOEditingContext) myManualLockingFactory()._newEditingContext(); ! ! newEC.init(); ! ! return newEC; ! } ! public static MyEOEditingContext newManualLockingEC( EOObjectStore objectStore ) { ! ! MyEOEditingContext newEC = (MyEOEditingContext) myManualLockingFactory()._newEditingContext( objectStore ); ! ! newEC.init(); ! ! return newEC; ! } ! private void init() { ! ! doCommitLogging = true; ! ! setRetainsRegisteredObjects( true );! // http://lists.apple.com/archives/webobjects-dev/2010/Nov/msg00009.html ! } MyEOEditingContext.java Samstag, 22. Juni 13
  • 44. ! @Override public void saveChanges() { ! ! StringBuilder buf = null; ! ! if( doCommitLogging ) { ! ! ! buf = new StringBuilder(); ! ! ! buf.append( "MyEC" ).append( useAutoLock() ? " autoLocking" : " manualLocking" ).append( " saveChanges()" ); ! ! ! StackTraceElement[] stack = new Throwable().getStackTrace(); ! ! ! if( stack != null && stack.length > 1 )! buf.append( "; " ).append( stack[1].toString() ); ! ! ! Collection<String> updatedClasses = setOfClassesFor( updatedObjects() ); ! ! ! Collection<String> insertedClasses = setOfClassesFor( insertedObjects() ); ! ! ! Collection<String> deletedClasses = setOfClassesFor( deletedObjects() ); ! ! ! if( insertedClasses.size() > 0 ) buf.append( "; ins: " ).append( Joiner.on(",").join( insertedClasses ) ); ! ! ! if( updatedClasses.size() > 0 ) buf.append( "; upd: " ).append( Joiner.on(",").join( updatedClasses ) ); ! ! ! if( deletedClasses.size() > 0 ) buf.append( "; del: " ).append( Joiner.on(",").join( deletedClasses ) ); ! ! } ! ! long ms1 = 0; if( buf != null ) ms1 = System.currentTimeMillis(); ! ! super.saveChanges(); ! ! long ms2 = 0; if( buf != null ) ms2 = System.currentTimeMillis(); ! ! NSUndoManager undoManager = undoManager(); ! ! if( undoManager != null ) undoManager.removeAllActions(); ! ! long ms3 = 0; if( buf != null ) ms3 = System.currentTimeMillis(); ! ! if( buf != null ) { ! ! ! buf.append( "; times " ).append( ms2-ms1 ).append( " " ).append( ms3-ms2 ); ! ! ! log.info( buf.toString() ); ! ! } ! } MyEOEditingContext.java Samstag, 22. Juni 13
  • 45. ! @Override public void saveChanges() { ! ! StringBuilder buf = null; ! ! if( doCommitLogging ) { ! ! ! buf = new StringBuilder(); ! ! ! buf.append( "MyEC" ).append( useAutoLock() ? " autoLocking" : " manualLocking" ).append( " saveChanges()" ); ! ! ! StackTraceElement[] stack = new Throwable().getStackTrace(); ! ! ! if( stack != null && stack.length > 1 )! buf.append( "; " ).append( stack[1].toString() ); ! ! ! Collection<String> updatedClasses = setOfClassesFor( updatedObjects() ); ! ! ! Collection<String> insertedClasses = setOfClassesFor( insertedObjects() ); ! ! ! Collection<String> deletedClasses = setOfClassesFor( deletedObjects() ); ! ! ! if( insertedClasses.size() > 0 ) buf.append( "; ins: " ).append( Joiner.on(",").join( insertedClasses ) ); ! ! ! if( updatedClasses.size() > 0 ) buf.append( "; upd: " ).append( Joiner.on(",").join( updatedClasses ) ); ! ! ! if( deletedClasses.size() > 0 ) buf.append( "; del: " ).append( Joiner.on(",").join( deletedClasses ) ); ! ! } ! ! long ms1 = 0; if( buf != null ) ms1 = System.currentTimeMillis(); ! ! super.saveChanges(); ! ! long ms2 = 0; if( buf != null ) ms2 = System.currentTimeMillis(); ! ! NSUndoManager undoManager = undoManager(); ! ! if( undoManager != null ) undoManager.removeAllActions(); ! ! long ms3 = 0; if( buf != null ) ms3 = System.currentTimeMillis(); ! ! if( buf != null ) { ! ! ! buf.append( "; times " ).append( ms2-ms1 ).append( " " ).append( ms3-ms2 ); ! ! ! log.info( buf.toString() ); ! ! } ! } MyEOEditingContext.java MyEC autoLocking saveChanges(); com.selbstdenker.foo.bar.MyJourneyManager.createNewInvoice(MyJourneyManager.java:650); ins: MyCustomerClaimItem(3),MyCustomerLiability(1),MyCustomerClaim(1); upd: PDCJourney(1); times 171 1 Samstag, 22. Juni 13
  • 46. ! private Collection<String> setOfClassesFor( NSArray<EOEnterpriseObject> objects ) { ! ! Multiset<String> classNames = HashMultiset.create(); ! ! for( EOEnterpriseObject eo : objects ) { ! ! ! classNames.add( eo.getClass().getSimpleName() ); ! ! } ! ! List<String> namesWithCount = Lists.newArrayList(); ! ! for( Multiset.Entry entry : classNames.entrySet() ) { ! ! ! namesWithCount.add( entry.getElement() + "(" + entry.getCount() + ")" ); ! ! } ! ! return namesWithCount; ! } ! public void setLoggingOnCommit( boolean value ) { ! ! this.doCommitLogging = value; ! } MyEOEditingContext.java Samstag, 22. Juni 13
  • 47. ! public void lockIfManualLocking() { ! ! if( useAutoLock() ) return; ! ! lock(); ! } ! public void unlockIfManualLocking() { ! ! if( useAutoLock() ) return; ! ! unlock(); ! } ! ! public void saveChangesWithLockIfNecessary() { ! ! if( hasChanges() ) { ! ! ! lockIfManualLocking(); ! ! ! try { ! ! ! ! saveChanges(); ! ! ! } finally { ! ! ! ! unlockIfManualLocking(); ! ! ! } ! ! } ! } ! } MyEOEditingContext.java Samstag, 22. Juni 13
  • 48. autolock vs. manual • In general, autolocking is the right choice for almost everything • Consider using manual locking for db-intensive background tasks • Main autolocking tradeoff: looots of lock/unlock calls that could become a significant overhead, depending on what you‘re doing Samstag, 22. Juni 13
  • 49. ! public static void deleteObsoleteFolderEntries() { ! ! Thread thread = new Thread() { ! ! ! @Override ! ! ! public void run() { ! ! ! ! log.info( "deleteObsoleteFolderEntries: starting" ); ! ! ! ! MyEOEditingContext ec = MyEOEditingContext.newManualLockingEC(); ! ! ! ! ec.lock(); ! ! ! ! try { ! ! ! ! ! MyJourneyFolderEntry.deleteObsoleteEntries( ec ); ! ! ! ! ! ec.saveChanges(); ! ! ! ! } catch( Exception e ) { ! ! ! ! ! ec.revert(); ! ! ! ! } finally { ! ! ! ! ! ec.unlock(); ! ! ! ! } ! ! ! ! log.info( "deleteObsoleteFolderEntries: completed" ); ! ! ! } ! ! }; ! ! thread.start(); ! } Manual locking case example Samstag, 22. Juni 13
  • 50. ! public static void deleteObsoleteFolderEntries() { ! ! Thread thread = new Thread() { ! ! ! @Override ! ! ! public void run() { ! ! ! ! log.info( "deleteObsoleteFolderEntries: starting" ); ! ! ! ! MyEOEditingContext ec = MyEOEditingContext.newManualLockingEC(); ! ! ! ! ec.lockIfManualLocking(); ! ! ! ! try { ! ! ! ! ! MyJourneyFolderEntry.deleteObsoleteEntries( ec ); ! ! ! ! ! ec.saveChanges(); ! ! ! ! } catch( Exception e ) { ! ! ! ! ! ec.revert(); ! ! ! ! } finally { ! ! ! ! ! ec.unlockIfManualLocking(); ! ! ! ! } ! ! ! ! log.info( "deleteObsoleteFolderEntries: completed" ); ! ! ! } ! ! }; ! ! thread.start(); ! } Manual locking case example Samstag, 22. Juni 13
  • 51. ERXGenericRecord • Requirement: subclass ERXGenericRecord • With EOGenerator, simply change your template‘s superclass declaration and import statements • Of course you can change them to your own MyGenericRecord class instead, and let that extend ERXGenericRecord • If you had a delegate in your EC to do stuff before saves, you can now use ERXGenericRecord.willUpdate() and .willInsert() instead Samstag, 22. Juni 13
  • 52. EO Templates • Use Wonder templates from WOLips • There‘s a wiki page with all sorts of alternatives • In any case, take one that defines proper ERXKey constants Samstag, 22. Juni 13
  • 53. ERXDirectAction • Requirement: subclass ERXDirectAction • As usual, you can make your own base class in between Samstag, 22. Juni 13
  • 56. Suggestions to proceed • Beautify your qualifiers • Migrations • Array operators and bindings Samstag, 22. Juni 13
  • 57. ERX*Qualifier, ERXKey and ERXQ public class MyFlightRoute extends _MyFlightRoute { ! public static enum FRSTATUS { ! ! obsolete, ! ! current, ! ! preliminary, ! ! deleted; ! } ! public void setStatus( FRSTATUS status ) { ! ! super.setStatus( status.name() ); ! } } public abstract class _MyFlightRoute extends MyEOGenericRecord { ! public static final ERXKey<String> STATUS = new ERXKey<String>("status"); ! public static final String STATUS_KEY = STATUS.key(); } Samstag, 22. Juni 13
  • 58. EOQualifier flightRouteValidQualifier = ! ! MyFlightRoute.STATUS.eq( FRSTATUS.current.name() ).or( ! ! MyFlightRoute.STATUS.eq( FRSTATUS.preliminary.name() ) ); EOQualifier flightRouteValidQualifier = ERXQ.or( ! ! MyFlightRoute.STATUS.eq( FRSTATUS.current.name() ), ! ! MyFlightRoute.STATUS.eq( FRSTATUS.preliminary.name() ) ); EOQualifier flightRouteValidQualifier = new EOOrQualifier( new NSArray( new Object[]{ ! new EOKeyValueQualifier( MyFlightRoute.STATUS_KEY, EOQualifier.QualifierOperatorEqual, FRSTATUS.current.name() ), ! new EOKeyValueQualifier( MyFlightRoute.STATUS_KEY, EOQualifier.QualifierOperatorEqual, FRSTATUS.preliminary.name() ) } ) ); EOQualifier flightRouteValidQualifier = ! ! MyFlightRoute.STATUS.inObjects( FRSTATUS.current.name(), FRSTATUS.preliminary.name() ); ERX*Qualifier, ERXKey and ERXQ Samstag, 22. Juni 13
  • 59. public class MYMODELNAME17 extends MyMigration { ! @Override public void upgrade( EOEditingContext editingContext, ERXMigrationDatabase database ) throws Throwable { ! ! ERXMigrationTable journeyTable = database.existingTableNamed( MyJourney.ENTITY_NAME ); ! ! journeyTable.newFlagBooleanColumn( MyJourney.MY_NEW_ATTR_KEY, ALLOWS_NULL ); ! ! ! ! String sql = "UPDATE MyJourney SET myNewAttr = false WHERE customerRef IN (...whatever...)"; ! ! NSLog.out.appendln( "Executing SQL: " + sql ); ! ! ERXJDBCUtilities.executeUpdate( database.adaptorChannel(), sql, true ); ! ! MyUserRole specialRole = MyUserRole.newInEc( editingContext ); ! ! specialRole.setName( "Speziaaaal" ); ! ! specialRole.setRoleType( MyUserRole.ROLETYPE.special.name() ); ! } } package com.selbstdenker.foo.bar.migration; import com.webobjects.eocontrol.EOEditingContext; import er.extensions.migration.ERXMigrationDatabase; import er.extensions.migration.ERXMigrationDatabase.Migration; public abstract class MyMigration extends Migration { ! @Override public void downgrade( EOEditingContext editingContext, ERXMigrationDatabase database ) throws Throwable { ! ! // do nothing ! } } Migrations Samstag, 22. Juni 13
  • 60. JourneyElementRepetition : WORepetition { ! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus; ! item = aPassenger; } Array operators and Bindings Samstag, 22. Juni 13
  • 61. <wo:if condition = "$selectedJourney.passengerArray.@isEmpty"> ! <p>blah</p> </wo:if> JourneyElementRepetition : WORepetition { ! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus; ! item = aPassenger; } Array operators and Bindings Samstag, 22. Juni 13
  • 62. // valid <wo:if condition = "$selectedJourney.passengerArray.@isEmpty"> ! <p>blah</p> </wo:if> JourneyElementRepetition : WORepetition { ! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus; ! item = aPassenger; } Array operators and Bindings Samstag, 22. Juni 13
  • 63. // valid <wo:if condition = "$selectedJourney.passengerArray.@isEmpty"> ! <p>blah</p> </wo:if> JourneyElementRepetition : WORepetition { ! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus; ! item = aPassenger; } Array operators and Bindings Samstag, 22. Juni 13
  • 64. // valid <wo:if condition = "$selectedJourney.passengerArray.@isEmpty"> ! <p>blah</p> </wo:if> JourneyElementRepetition : WORepetition { ! list = selectedJourney.passengerArray.@sortDesc.sortKeyConsideringStatus; ! item = aPassenger; } Array operators and Bindings Samstag, 22. Juni 13
  • 65. Information sources • Wiki page „Project Wonder Installation“ • Wiki page „Integrate Wonder into an Existing Application“ • Wiki page „EOGenerator Templates and Additions“ • Wiki page „UTF-8 Encoding Tips“ • projectlombok.org Samstag, 22. Juni 13
  • 66. Q&A email: maik@selbstdenker.ag twitter and app.net: @maikm Samstag, 22. Juni 13