Today''s Page Hits: 44
Hello, World! Another window
daily-money is a simple android application that helps me to record daily expanses, monthly incomes and assets.
the main idea comes from a desktop application "Money Assistant", I have used this app to record my expenses more than 5 years. however it is out of maintenance and for windows only (I have give up windows).
Because of I quit my last job last month and not yet find next job, so, I spent two days reading android doc and 6 days writing application, Daily-Money.
The main function of this application is free and open. I will write some report activity also in this month if i still a free man.
you can download the apk here if you want to : Daily-Money
Here is some screenshoots:
|
|
|
|
|
|
|
|
|
|
|
zkseasm2 - My parttime project that provides ZK and Seam2 integration.
project site : http://code.google.com/p/zkseam2/
DesktopConversation.begin();You usually begin a conversation in a conversation scope seam controller's creation method. for example :
@Name("winCtrl")
@Scope(ScopeType.CONVERSATION)
public class WinCtrl {
@Create
public void create(){
DesktopConversation.begin();
}
}
DesktopConversation.end();The conversation will be destroyed automatically when the desktop cleanup by zkau request or conversation timeout.
@In(value="desktop",required=false)
Desktop desktop;
@In(value="page",required=false) //the first page in current desktop
Page page;
@In(value="execution",required=false)
Execution exec;
@In(value="mypage1",required=false)
Page page;
@In(value="win",required=false)
Window window;
@In(value="win.btn",required=false)
Button btn;
@In(value="win.tb",required=false)
Textbox textbox;
Until now, I have no idea how to bind zk IdSapce in seam, if you want to inject a component, you have to know the component path and replace the path character '/' by '.'.
To enable this, you have to add a zk directive as follow
<?init class="com.infinitiessoft.zkseam.zk.AnnotateActionBinderInit"?>
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
ServletLifecycle.beginRequest(request);
try{
Requests.instance().setRequest(request);
// do some thing.
}finally{
ServletLifecycle.endRequest(request);
}
}
[Access Seam component in Thread]
public void run() {
Lifecycle.beginCall();
try{
//do something
}finally{
Lifecycle.endCall();
}
}
Since Lifecycle and ServletLifecycle handle application context in static, so you might get wrong application when use it.
package org.jboss.seam.contexts;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.jboss.seam.ScopeType;
import org.jboss.seam.core.Manager;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
/**
* A enhanced lifecycle controller for running seam in multiple war
*
* @author dennis
*/
public class LifecycleEx {
private static String NULL_APP_NAME = "LifecycleEx.NULL.APPNAME";
private static Map<String,Object> defaultApplication = null;
private static Map<String,Map<String,Object>> applications = new HashMap<String,Map<String,Object>>();
private static List<Map<String,Object>> applicationList = new LinkedList<Map<String,Object>>();
private static final Log log = Logging.getLog(LifecycleEx.class);
static public void registerApplication(String name,Map<String,Object> application){
name = name == null?NULL_APP_NAME:name;
if(applications.containsKey(name)){
log.warn("trying to register application '#0' again",name);
}
applications.put(name,application);
applicationList.add(application);
defaultApplication = application;
}
static public void unregisterApplication(String name){
name = name == null?NULL_APP_NAME:name;
Map<String,Object> app = applications.remove(name);
if(app!=null){
applicationList.remove(app);
if(app==defaultApplication){
if(applicationList.size()>0){
//last one
defaultApplication = applicationList.get(applicationList.size()-1);
}else{
defaultApplication = null;
}
}
}
}
static Map<String,Object> getApplication(String name){
return getApplication(name,false);
}
/**
* get Application context by name, if no application context found, then try to get default application context (the last registered)
* @param name name of application
* @param as_possible true: if get application not found, then return default application
* @return RuntimeException if no application found.
*/
static Map<String,Object> getApplication(String name,boolean as_possible){
name = name == null?NULL_APP_NAME:name;
Map<String,Object> app = applications.get(name);
if(app==null&&as_possible){
log.debug("name #0 not found, use default application",name);
app = defaultApplication;
}
if(app==null){
throw new RuntimeException("application "+name+" not found ");
}
return app;
}
public static void setupApplication(String name)
{
Contexts.applicationContext.set( new ApplicationContext(getApplication(name)) );
}
public static void cleanupApplication()
{
Contexts.applicationContext.set(null);
}
static void clearThreadlocals()
{
Contexts.eventContext.set(null);
Contexts.pageContext.set(null);
Contexts.sessionContext.set(null);
Contexts.conversationContext.set(null);
Contexts.businessProcessContext.set(null);
Contexts.applicationContext.set(null);
}
public static void beginCall(String appname){
beginCall(appname,false);
}
public static void beginCall(String appname,boolean as_possible)
{
Contexts.applicationContext.set( new ApplicationContext(getApplication(appname,as_possible)) );
Contexts.eventContext.set( new BasicContext(ScopeType.EVENT) );
//TODO should we initial session??
Contexts.sessionContext.set( new BasicContext(ScopeType.SESSION) );
Contexts.conversationContext.set( new BasicContext(ScopeType.CONVERSATION) );
Contexts.businessProcessContext.set( new BusinessProcessContext() );
}
public static void endCall()
{
try
{
Contexts.destroy( Contexts.getSessionContext() );
Contexts.flushAndDestroyContexts();
if ( Manager.instance().isLongRunningConversation() )
{
throw new IllegalStateException("Do not start long-running conversations in direct calls to EJBs");
}
}
finally
{
clearThreadlocals();
}
}
}
[ServletLifecycleEx] : helps you to retrieve application by name.package org.jboss.seam.contexts;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
import org.jboss.seam.servlet.ServletApplicationMap;
import org.jboss.seam.servlet.ServletRequestMap;
import org.jboss.seam.servlet.ServletRequestSessionMap;
import org.jboss.seam.web.Session;
/**
* A enhanced servlet lifecycle controller for running seam in multiple war
* @author dennis
*/
public class ServletLifecycleEx {
private static final Log log = Logging.getLog(ServletLifecycleEx.class);
static public void registerApplication(String name,ServletContext context){
log.info("Register application context name #0",name);
Map<String,Object> application = new ServletApplicationMap(context);
LifecycleEx.registerApplication(name,application);
}
static public void unregisterApplication(String name){
log.info("Unregister application context name #0",name);
LifecycleEx.unregisterApplication(name);
}
public static void beginRequest(String path,HttpServletRequest request){
log.debug( "begin web request #",path );
Contexts.eventContext.set( new EventContext( new ServletRequestMap(request) ) );
Contexts.sessionContext.set( new SessionContext( new ServletRequestSessionMap(request) ) );
Contexts.applicationContext.set(new ApplicationContext( LifecycleEx.getApplication(path) ) );
Contexts.conversationContext.set(null); //in case endRequest() was never called
}
public static void endRequest(HttpServletRequest request) {
log.debug("After request, destroying contexts");
try
{
Session session = Session.getInstance();
boolean sessionInvalid = session!=null && session.isInvalid();
Contexts.flushAndDestroyContexts();
if (sessionInvalid)
{
LifecycleEx.clearThreadlocals();
request.getSession().invalidate();
//actual session context will be destroyed from the listener
}
}
finally
{
LifecycleEx.clearThreadlocals();
}
}
}
[SeamLifecycleEx] : this component is for registering application context into LifecycleEx and ServletLifecycleEx.
package foo.bar;
import java.util.Map;
import javax.servlet.ServletContext;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.contexts.Lifecycle;
import org.jboss.seam.contexts.LifecycleEx;
import org.jboss.seam.contexts.ServletLifecycle;
import org.jboss.seam.contexts.ServletLifecycleEx;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
@Name("foo.bar.SeamLifecycleEx")
@Scope(ScopeType.APPLICATION)
@Startup @AutoCreate
public class SeamLifecycleEx {
private static final Log log = Logging.getLog(SeamLifecycleEx.class);
private String _name;
@Create
public void create(){
log.debug("Initial SeamLifecycleEx");
ServletContext context = ServletLifecycle.getServletContext();
if(context==null){
log.warn("servlet context not found, did you initial seam out of WAR moudle?");
Map<String,Object> currentApplication= Lifecycle.getApplication();
LifecycleEx.registerApplication(null,currentApplication);
return;
}
_name = context.getContextPath();
//in mock/test , _name is null
if(_name!=null && _name.startsWith("/")){
_name = _name.substring(1);
}
log.debug("register servlet application context with name #0 ",_name);
ServletLifecycleEx.registerApplication(_name,context);
}
@Destroy
public void destroy(){
ServletLifecycleEx.unregisterApplication(_name);
}
}
Ok, Now you have 3 java class, you have to put first 2 java into seam package (the package level protected issue) and put the seam component to where you want.
protected String name;
public void init() throws ServletException {
super.init();
if(name.startsWith("/")){
name = name.substring(1);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
ServletLifecycleEx.beginRequest(name,request);
try{
Requests.instance().setRequest(request);
// do some thing.
}finally{
ServletLifecycleEx.endRequest(request);
}
}
[Access Seam component in Thread]
// in thread, name is a configured string usually.
public void run() {
LifecycleEx.beginCall(name,true);
try{
//do something
}finally{
LifecycleEx.endCall();
}
}