タスク:オブジェクトとアクセス

タスク :Java Webアプリケーションからオブジェクトとそのパラメーターを取得するための迅速で便利な方法を編成する必要があります。



タスク自体について少し。


ブラウザRPGエンジンを書いています。 すべてのゲームロジック(場所間の遷移、購入など)はTomcat 6によって処理されます。ページはJSONオブジェクトを要求し、サーバーは要求を処理し、結果を返します。 最初は、アクションのグループごとに個別のサーブレットがありましたが、多くのコードと重複がありました。 一般的に、私は好きではなかった。





サーバーへのすべての呼び出しは、2つのタイプに分けられます。

1.オブジェクトの状態(プレイヤーの名前、レベル、その場所にいるプレイヤーのリスト)を取得する

2.オブジェクトの状態の変化(アイテムの購入、アイテムの組み立て、メッセージの送信)



2番目のタイプの処理も簡略化しましたが、次回はそれについてです。



アイデアは、結果を取得するための簡単なアルゴリズムを構築するために、すべてのオブジェクトを一般化することです。

これを行うために、インターフェイスを使用し、オブジェクトで実装しました。



package engine.core.obj;



import org.json.JSONObject;



/**

*

* @author chernser

* Interface used to work with core objects

*

*/

public interface ICoreObject {



/**

* Should implement encoding into

* JSON notation

* @param context TODO

*

* @return returns object in JSON notation

* @return null if error

*/

public JSONObject toJSON(Context context);





/**

*

* Should implement getting object's class

* name

*

* @return returns object class name

* @return null if error

*/

public String getClassName();





/**

* Should find child object by name

* and return it

* @param context TODO

*

* @return returns child object

* @return null if error

*/

public ICoreObject getChild(String name, Context context);





/**

* Should find child object

* by name and index then return it

* @param context TODO

*

* @return returns child object

* @return null if error

*/

public ICoreObject getChild(String name, Integer index, Context context);





/**

* Should return parameter's value

*

* @param name - parameter name

* @param context - current context

* @return returns value of parameter

* @return null if no such parameter

*

*/

public Object getParameter(String name, Context context);

}




* This source code was highlighted with Source Code Highlighter .








主な方法は次のとおりです。





これらのメソッドの実装のいくつかの例:



@Override

public ICoreObject getChild(String name, Context context) {

if (name.equals(AvatarBaseParams.CORE_OBJ_NAME)) {

return itsBaseParams;

} else if (name.equals(Location.CORE_OBJ_NAME)) {

return itsLocation;

} else if (name.equals(AvatarInventory.CORE_OBJ_NAME))

{

return itsInventory;

} else if (name.equals(AvatarSkills.CORE_OBJ_NAME))

{

return itsSkills;

} else if (name.equals(AvatarModifications.CORE_OBJ_NAME))

{

return itsModifications;

}



return null ;

}




* This source code was highlighted with Source Code Highlighter .








@Override

public ICoreObject getChild(String name, Context context) {

if (name.equals(AvatarBaseParams.CORE_OBJ_NAME)) {

return itsBaseParams;

} else if (name.equals(Location.CORE_OBJ_NAME)) {

return itsLocation;

} else if (name.equals(AvatarInventory.CORE_OBJ_NAME))

{

return itsInventory;

} else if (name.equals(AvatarSkills.CORE_OBJ_NAME))

{

return itsSkills;

} else if (name.equals(AvatarModifications.CORE_OBJ_NAME))

{

return itsModifications;

}



return null ;

}




* This source code was highlighted with Source Code Highlighter .










通常、このメソッドは単純なディスパッチャです。 この方法のおかげで、任意の階層を構築できます。



@Override

public JSONObject toJSON(Context context) {



JSONObject result = new JSONObject();

try {



result.put( "name" , itsName);

result.put( "bparams" , itsBaseParams.toJSON(context));



} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}



return result;

}




* This source code was highlighted with Source Code Highlighter .









@Override

public JSONObject toJSON(Context context) {



JSONObject result = new JSONObject();

try {



result.put( "name" , itsName);

result.put( "bparams" , itsBaseParams.toJSON(context));



} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}



return result;

}




* This source code was highlighted with Source Code Highlighter .









@Override

public JSONObject toJSON(Context context) {



JSONObject result = new JSONObject();

try {



result.put( "name" , itsName);

result.put( "bparams" , itsBaseParams.toJSON(context));



} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}



return result;

}




* This source code was highlighted with Source Code Highlighter .












ここで、必要なフィールドを持つJSONObjectを作成します。



したがって、一般的なルールに従うオブジェクトがあります。 チェーン全体をすばやくトラバースし、結果を返すためのアルゴリズムが必要です。 ここで、おそらく、最も難しい瞬間:-)



クエリ文字列は次のようになります。

user.avatar:name-アバターオブジェクトの名前を返します。 パラメーターへのアクセスにはコロンが使用されます。

user.avatar.location-ロケーションオブジェクトのJSON表現を返します。

user.avatar.inventory.slot [4]-プレーヤーのインベントリの4番目のスロットのJSON表現を返します。



リクエストは別のサーブレットに入り、これがリクエストの処理方法です。



1.リクエストと戻り値の初期チェック




protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {



/* Set encoding for request to properly parse parameters */

request.setCharacterEncoding( "UTF-8" );



// get user from session

User user = (User) request.getSession().getAttribute(

CommonConstants.USER);



// save query and prelimenary result

String query = request.getParameter( "query" );

String result = "{error: -1}" ;



// check if we have user

if (user != null )

{

Context context = user.itsContext;



// Check parameters

if (query != null )

{

// process query

result = ParseAndExecuteQuery(query, request.getSession(), context);

}

}



/* tune response to avoid problem with Russian */

response.setContentType( "text/javascript; charset=UTF-8" );

response.setHeader( "Cache-Control" , "no-cache" ); //HTTP 1.1

response.setHeader( "Pragma" , "no-cache" ); //HTTP 1.0

response.setDateHeader( "Expires" , 0); //prevents caching at the proxy server



response.getWriter().write(result);



}




* This source code was highlighted with Source Code Highlighter .








protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {



/* Set encoding for request to properly parse parameters */

request.setCharacterEncoding( "UTF-8" );



// get user from session

User user = (User) request.getSession().getAttribute(

CommonConstants.USER);



// save query and prelimenary result

String query = request.getParameter( "query" );

String result = "{error: -1}" ;



// check if we have user

if (user != null )

{

Context context = user.itsContext;



// Check parameters

if (query != null )

{

// process query

result = ParseAndExecuteQuery(query, request.getSession(), context);

}

}



/* tune response to avoid problem with Russian */

response.setContentType( "text/javascript; charset=UTF-8" );

response.setHeader( "Cache-Control" , "no-cache" ); //HTTP 1.1

response.setHeader( "Pragma" , "no-cache" ); //HTTP 1.0

response.setDateHeader( "Expires" , 0); //prevents caching at the proxy server



response.getWriter().write(result);



}




* This source code was highlighted with Source Code Highlighter .












2.リクエストの準備と初期オブジェクトの決定(ユーザーと世界の2つがあります)




private String ParseAndExecuteQuery(String query, HttpSession session, Context context)

{

ICoreObject rootObject = null ;



// if query starts from "user." Also check syntax

if (query.matches( "user\\.([a-zA-Z_]+(\\[[0-9]+\\])*(:[a-zA-Z_]+)*\\.{0,1})+" ))

{

rootObject = (User) session.getAttribute(CommonConstants.USER);

}

// if query starts from "world." Also check syntax

else if (query.matches( "world\\.([a-zA-Z_]+(\\[[0-9]+\\])*(:[a-zA-Z_]+)*\\.{0,1})+" ))

{

rootObject = (World)session.getServletContext().

getAttribute(CommonConstants.WORLD);

}



// Check if we have root object

if (rootObject != null )

{

// Start processing

ICoreObject result = getObject(rootObject, query, context);

if (result != null )

{

// Here we got result

JSONObject jsonObj = result.toJSON(context);

if (jsonObj != null )

{

// return it

return jsonObj.toString();

}

}

}





return "" ;

}




* This source code was highlighted with Source Code Highlighter .









private String ParseAndExecuteQuery(String query, HttpSession session, Context context)

{

ICoreObject rootObject = null ;



// if query starts from "user." Also check syntax

if (query.matches( "user\\.([a-zA-Z_]+(\\[[0-9]+\\])*(:[a-zA-Z_]+)*\\.{0,1})+" ))

{

rootObject = (User) session.getAttribute(CommonConstants.USER);

}

// if query starts from "world." Also check syntax

else if (query.matches( "world\\.([a-zA-Z_]+(\\[[0-9]+\\])*(:[a-zA-Z_]+)*\\.{0,1})+" ))

{

rootObject = (World)session.getServletContext().

getAttribute(CommonConstants.WORLD);

}



// Check if we have root object

if (rootObject != null )

{

// Start processing

ICoreObject result = getObject(rootObject, query, context);

if (result != null )

{

// Here we got result

JSONObject jsonObj = result.toJSON(context);

if (jsonObj != null )

{

// return it

return jsonObj.toString();

}

}

}





return "" ;

}




* This source code was highlighted with Source Code Highlighter .









private String ParseAndExecuteQuery(String query, HttpSession session, Context context)

{

ICoreObject rootObject = null ;



// if query starts from "user." Also check syntax

if (query.matches( "user\\.([a-zA-Z_]+(\\[[0-9]+\\])*(:[a-zA-Z_]+)*\\.{0,1})+" ))

{

rootObject = (User) session.getAttribute(CommonConstants.USER);

}

// if query starts from "world." Also check syntax

else if (query.matches( "world\\.([a-zA-Z_]+(\\[[0-9]+\\])*(:[a-zA-Z_]+)*\\.{0,1})+" ))

{

rootObject = (World)session.getServletContext().

getAttribute(CommonConstants.WORLD);

}



// Check if we have root object

if (rootObject != null )

{

// Start processing

ICoreObject result = getObject(rootObject, query, context);

if (result != null )

{

// Here we got result

JSONObject jsonObj = result.toJSON(context);

if (jsonObj != null )

{

// return it

return jsonObj.toString();

}

}

}





return "" ;

}




* This source code was highlighted with Source Code Highlighter .














3.目的のオブジェクトを見つける




private ICoreObject getObject(ICoreObject rootObject, String query, Context context)

{

ICoreObject curObject = rootObject; // current object

query = query.substring(query.indexOf( "." ) + 1) + "." ; // query



Integer dotIndex = query.indexOf( "." );

String tmpObjName = "" ; // object name

do {

String objName = query.substring(0, dotIndex); // get first object in chain



// if by index

if (objName.matches( "[a-zA-Z_]+\\[[0-9]+\\](:[a-zA-Z0-9_]+)*" ))

{

Integer index = new Integer(objName.substring(objName.indexOf( "[" ) + 1,

objName.indexOf( "]" )));

tmpObjName = objName.substring(0, objName.indexOf( "[" ));

curObject = curObject.getChild(tmpObjName, index, context);

}

else // if not by index

{

Integer semiIndex = 0;

if ((semiIndex = objName.indexOf( ":" )) > -1)

curObject = curObject.getChild(objName.substring(0, semiIndex), context);

else

curObject = curObject.getChild(objName, context);

}



// If current object in chain contains ':' - then proccess it as parameter

if (objName.matches( "[a-zA-Z_]+(\\[[0-9]+\\])*:[a-zA-Z0-9_]+" ))

{

// get parameter name

String param = objName.substring(objName.indexOf( ":" ) + 1);



return new CoreObjectParameter(param, curObject.getParameter(param, context));

}



// cut off current object name and step forward

query = query.substring(dotIndex + 1);

dotIndex = query.indexOf( "." );

} while ((dotIndex > -1) && (curObject != null ));





return curObject;

}




* This source code was highlighted with Source Code Highlighter .









private ICoreObject getObject(ICoreObject rootObject, String query, Context context)

{

ICoreObject curObject = rootObject; // current object

query = query.substring(query.indexOf( "." ) + 1) + "." ; // query



Integer dotIndex = query.indexOf( "." );

String tmpObjName = "" ; // object name

do {

String objName = query.substring(0, dotIndex); // get first object in chain



// if by index

if (objName.matches( "[a-zA-Z_]+\\[[0-9]+\\](:[a-zA-Z0-9_]+)*" ))

{

Integer index = new Integer(objName.substring(objName.indexOf( "[" ) + 1,

objName.indexOf( "]" )));

tmpObjName = objName.substring(0, objName.indexOf( "[" ));

curObject = curObject.getChild(tmpObjName, index, context);

}

else // if not by index

{

Integer semiIndex = 0;

if ((semiIndex = objName.indexOf( ":" )) > -1)

curObject = curObject.getChild(objName.substring(0, semiIndex), context);

else

curObject = curObject.getChild(objName, context);

}



// If current object in chain contains ':' - then proccess it as parameter

if (objName.matches( "[a-zA-Z_]+(\\[[0-9]+\\])*:[a-zA-Z0-9_]+" ))

{

// get parameter name

String param = objName.substring(objName.indexOf( ":" ) + 1);



return new CoreObjectParameter(param, curObject.getParameter(param, context));

}



// cut off current object name and step forward

query = query.substring(dotIndex + 1);

dotIndex = query.indexOf( "." );

} while ((dotIndex > -1) && (curObject != null ));





return curObject;

}




* This source code was highlighted with Source Code Highlighter .









private ICoreObject getObject(ICoreObject rootObject, String query, Context context)

{

ICoreObject curObject = rootObject; // current object

query = query.substring(query.indexOf( "." ) + 1) + "." ; // query



Integer dotIndex = query.indexOf( "." );

String tmpObjName = "" ; // object name

do {

String objName = query.substring(0, dotIndex); // get first object in chain



// if by index

if (objName.matches( "[a-zA-Z_]+\\[[0-9]+\\](:[a-zA-Z0-9_]+)*" ))

{

Integer index = new Integer(objName.substring(objName.indexOf( "[" ) + 1,

objName.indexOf( "]" )));

tmpObjName = objName.substring(0, objName.indexOf( "[" ));

curObject = curObject.getChild(tmpObjName, index, context);

}

else // if not by index

{

Integer semiIndex = 0;

if ((semiIndex = objName.indexOf( ":" )) > -1)

curObject = curObject.getChild(objName.substring(0, semiIndex), context);

else

curObject = curObject.getChild(objName, context);

}



// If current object in chain contains ':' - then proccess it as parameter

if (objName.matches( "[a-zA-Z_]+(\\[[0-9]+\\])*:[a-zA-Z0-9_]+" ))

{

// get parameter name

String param = objName.substring(objName.indexOf( ":" ) + 1);



return new CoreObjectParameter(param, curObject.getParameter(param, context));

}



// cut off current object name and step forward

query = query.substring(dotIndex + 1);

dotIndex = query.indexOf( "." );

} while ((dotIndex > -1) && (curObject != null ));





return curObject;

}




* This source code was highlighted with Source Code Highlighter .














オブジェクトが見つかった場合、JSONスクリプトとしてページに送信され、見つからない場合は空のオブジェクトが返されます。



メカニズムはまだベータ版です:-)ただし、これまでのところ、バグは示されていません。



All Articles