- Cube Coffee
- Coffeebooks & Rain
- 1973 Espresso Cafe
- Coffee Lips Cafe
- Parrot Espresso Cafe
- Coffee Diem
- Oh Bella Cafe
- Coffee D
- Bon Bon Ya
- Coffee Lunatic
- Mc Cafe
- Habit Art Cafe
- Bites Cafe & Galary
- Le' Medina Patisserie
- Secret Recipes
- Coffee Lap
- Green Leaf
- Uncle Jonh
- Georgetown Cafe
- Oldtown Cafe
- Coffebean ( Coming Soon )
- Starbucks ( Coming Soon )
- Deco Cafe ( Coming Soon )
- Coffee Tiffz Gallery ( Coming Soon )
- Paper Plane Cafe ( Coming Soon )
- The Hat Cabin ( Coming Soon )
- Coffee Lips ( Comimg Soon )
Sunday, November 30, 2014
Alor Setar Cafe
Just want to keep track of these Cafe in Alor Setar. Wonder how long they will last...
Thursday, November 13, 2014
What did "cordova create" do?
Just for curiosity, I ran this command to find out.
And here we go. I expand all the sub folder in myapp1.
$ cordova create myapp1 com.otccomputing.myapp1 "My App 1"
Creating a new cordova project with name "My App 1" and id "com.otccomputing.myapp1" at location "/Users/guest/apps/myapp1"
And here we go. I expand all the sub folder in myapp1.
Now let's take a look at those files.
config.xml, used by cordova to do compile/build/plugin whatever task. Without it, it is just not a cordova project anymore.
The content in config.xml is simple and easy to digest.
id = a unique identity used to identify your app
version = as named. etc. 1.0.0, 2.0.0, 3.0.4...
description: write anything you want
author: change it to your detail - email, website
content: which file cordova will start with - don't change this one.
We now look at index.html
The most important 2 lines are:
cordova.js MUST be there. Otherwise your apps just won't work. I don't know what black magic behind it but - leave it there.
index.js is not that important, your apps may still work if it doesn't exist but lets have a look.
The main thing here is event listening. index.js listen to 'deviceready' event, which is fired by cordova after some backend initialization is ready. You might consider trigger some function in your app AFTER 'deviceready' is triggered or they may not work. Most plugin in GitHub will mention this requirement in their documentation.
the receivedEvent() implementation can be ignored or you can put in your own login here.
So for development strategy, I usually work on my HTML, JS,CSS in an IDE, test them on the browser, looks good, then move then into the www folder and do further integration.
Bottom line, as long as config.xml is there, cordova.js in included in your index.html, things will work.
Tuesday, October 14, 2014
Slim3 REST Controller Example
I was playing with AngularJS and slim3, then bum into REST. So here is an example for sharing.
At the client side I have angular code calling PUT:
One thing I found interesting about slim3 is the URL rewrite with AppRouter.java. Here is what I do (with evil smile):
I route both URL to the same Controller. So here is my Controller. My root package is "smis". (I know, I know...)
Then based on the isXXX() functions I call the handleXXXXX() accordingly. The implementation explains itself.
Some more interesting would be the asKey("my_key"), it does the same thing like:
request.getParameter("my_key") + parse it into a Key.
Very handy.
Last thing to point out is how to digest the request data:
The experiment was fun. I enjoy writing and playing with it. Hope it is the same for you too.
At the client side I have angular code calling PUT:
$http.put('organization', {name: $scope.name}).success( function(data){ alert('Success'); });the GET, POST and DELETE will be more or less the same. $http.get(), $http.post(), $http.delete().
One thing I found interesting about slim3 is the URL rewrite with AppRouter.java. Here is what I do (with evil smile):
addRouting( "/secured/{entity}", "/secured/rest?entity={entity}"); addRouting( "/secured/{entity}/{resourceId}", "/secured/rest?entity={entity}&resourceId={resourceId}");
I route both URL to the same Controller. So here is my Controller. My root package is "smis". (I know, I know...)
package smis.controller.secured; import java.io.BufferedReader; import java.lang.reflect.Method; import java.util.List; import org.apache.log4j.Logger; import org.slim3.controller.Controller; import org.slim3.controller.Navigation; import org.slim3.datastore.Datastore; import org.slim3.datastore.ModelMeta; import com.google.appengine.api.datastore.Key; public class RestController extends Controller { private Logger logger = Logger.getLogger(getClass()); @Override public Navigation run() throws Exception { String entityName = asString("entity"); String resourceId = asString("resourceId"); // hack class name. :p entityName = entityName.substring(0, 1).toUpperCase() + entityName.substring(1); Class entityClass = Class.forName("smis.model." + entityName); Class modelMetaClass = Class.forName("smis.meta." + entityName + "Meta"); Method method = modelMetaClass.getMethod("get"); Object modelMetaInstance = method.invoke(null); logger.debug(entityClass); logger.debug(modelMetaClass); logger.debug(modelMetaInstance); logger.debug("Method = " + request.getMethod()); if (isGet()) { if (resourceId == null) { return handleList((ModelMeta) modelMetaInstance); } else { return handleDetail(entityClass, (ModelMeta) modelMetaInstance); } } else if (isPost()) { return handleCreate((ModelMeta) modelMetaInstance); } else if (isPut()) { return handleCreate((ModelMeta) modelMetaInstance); } else if (isDelete()) { return handleDelete(entityClass); } return null; } private Navigation handleDelete(Class entityClass) throws Exception { Key key = asKey("resourceId"); Datastore.delete(key); Object t = Datastore.get(entityClass, key); logger.debug(t == null); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.getWriter().print(t == null); response.flushBuffer(); return null; } private Navigation handleCreate(ModelMeta modelMeta) throws Exception { StringBuffer jb = new StringBuffer(); String line = null; try { BufferedReader reader = request.getReader(); while ((line = reader.readLine()) != null) jb.append(line); } catch (Exception e) { /* report an error */ e.printStackTrace(); } String json = jb.toString(); logger.debug(json); Object t = modelMeta.jsonToModel(json); boolean isComplete = Datastore.put(t).isComplete(); logger.debug(isComplete); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); response.getWriter().print(isComplete); response.flushBuffer(); return null; } private Navigation handleDetail(Class entityClass, ModelMeta modelMeta) throws Exception { Key key = asKey("resourceId"); logger.debug(key); Object t = Datastore.get(entityClass, key); String json = modelMeta.modelToJson(t); logger.debug(json); response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); response.getWriter().print(json); response.flushBuffer(); return null; } private Navigation handleList(ModelMeta modelMeta) throws Exception { List list = Datastore.query(modelMeta).asList(); String json = modelMeta.modelsToJson(list); logger.debug(json); response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); response.getWriter().print(json); response.flushBuffer(); return null; } }Because my lazy nature, I use reflection to create the Class for my entity and also the instance of the Meta class. Thanks to how slim3 name the model and meta class. There is a high security risk here! Not recommended for production, OK?
Then based on the isXXX() functions I call the handleXXXXX() accordingly. The implementation explains itself.
Some more interesting would be the asKey("my_key"), it does the same thing like:
request.getParameter("my_key") + parse it into a Key.
Very handy.
Last thing to point out is how to digest the request data:
StringBuffer jb = new StringBuffer(); String line = null; try { BufferedReader reader = request.getReader(); while ((line = reader.readLine()) != null) jb.append(line); } catch (Exception e) { /* report an error */ e.printStackTrace(); }
The experiment was fun. I enjoy writing and playing with it. Hope it is the same for you too.
Monday, October 13, 2014
AngularJS Experiment - Dynamic Change Model Value
Experiment
This is my test page.
and the js
So the result look like this
Now I want the time to change every second
But that does not happened...
Try add this line into it
And it works.
Lets do something a little aggressive...
and the browser didn't break. So we all good. :)
This is my test page.
Try add this line into it
And it works.
Lets do something a little aggressive...
and the browser didn't break. So we all good. :)
Saturday, October 11, 2014
Friday, October 10, 2014
Custom User Account for Google App Engine - Part I
Google App Engine (GAE) is good. I like it, but...
Well, I create an app (in java), I want user to sign in, and GAE want the user to have google account. What if I don't want that, well, I can then implement my own user authentication, which is shit (cannot use request.getUserPrincipal()).
How about using OAuth... may be this can works.
I want to create 100 users to use my app but I don't want to create 100 google account.
Still a basic concept at the moment. Not sure if it will work. Will do an experiment soon.
Well, I create an app (in java), I want user to sign in, and GAE want the user to have google account. What if I don't want that, well, I can then implement my own user authentication, which is shit (cannot use request.getUserPrincipal()).
How about using OAuth... may be this can works.
I want to create 100 users to use my app but I don't want to create 100 google account.
Still a basic concept at the moment. Not sure if it will work. Will do an experiment soon.
Sunday, October 5, 2014
Setting up Slim3 Framework for Google App Engine using Eclipse Luna
Slim3, new to me, cool stuff. Official web site: https://sites.google.com/site/slim3appengine/Home
Step 1 - get eclipse for JEE (eclipse-jee-luna-SR1-win32-x86_64) downloaded, unzip, run, install Google plugin, and done.
Step 2 - File > New > Project... > Google > Web Application Project
Here I turn off GWT. Other than that, fill in your project info accordingly.
PS: If you don't see this screen, DON'T PROCEED. There is something very wrong in your setup. lol.
Step 3 - Download slim3 v 1.0.16 from here, then unzip it into a folder. It should look like this.
The structure is similar to your project structure in eclipse, only with few extra (slim3) files.
Step 4 - Copy paste.
Now highlighted are files copied from slim3-blank folder.
Also, some jar as well from WEB-INF/lib
Step 5 - Annotation Processing Factory configuration.
This setting is simple but very important. It actually help generate source code for you. You'll know what it does as you continue working on your project.
Right click your project > properties and find Java Compiler > Annotation Processing.
Enable project specific settings.
Enable annotation processing.
Click on Factory path (left panel).
Click Add JARs...
Find slim3-gen-1.0.16.jar from your project. Add it.
Move it to the top.
Click OK and we leave the settings as it is for now.
Step 6 - web.xml
The web.xml was copied from slim-blank folder, only thing need to change is the slim3.rootPackage. It should be something like "com.mycompany", but...
Anyway, step 7 - Ant build.
As you can see, there is a build.xml file copied from slim3. This file will be heavily used throughout the project. So it will be a good idea to open a Ant view to use it.
To show Ant view, go Window > Show View > Others... > Ant > Ant
Then find and click the little add buildfiles icon and add the build.xml from your project folder. And you will see display as picture above.
From slim3 tutorial, the difference is you don't need to right click the build.xml and Run As...
Just double click target in the Ant View and you are done.
Step 8 - now, let's see how the magic works. Run gen-controller (double click on the ant view). You will see a popup, key in the path to your controller.
Once you click OK, slim3 will create a few files on your project.
Let's look at each file closely.
As I entered '/admin/user/' as controller path, slim3 creates:
Step 11 - show time
Right click your project and run as google web application.
Output on the console:
Now we go to http://localhost:8888/admin/user/
Just to make sure what is happening. Edit war/admin/user/index.jsp
Yeap! We got hello world.
In short, path "/admin/user/" is handled by the controller, then the controller forward us to /war/admin/user/index.jsp. Typical mvc, right.
This is my first approach trying slim3. I believe there is a more elegant way to set it up. Any comments for improvement is welcome. Actually there is a slim3 plugin for eclipse too, I only found out after this...
My next assignment was to implement RBAC in slim3. Will post some more stuff when it is ready.
Step 1 - get eclipse for JEE (eclipse-jee-luna-SR1-win32-x86_64) downloaded, unzip, run, install Google plugin, and done.
Step 2 - File > New > Project... > Google > Web Application Project
Here I turn off GWT. Other than that, fill in your project info accordingly.
PS: If you don't see this screen, DON'T PROCEED. There is something very wrong in your setup. lol.
Step 3 - Download slim3 v 1.0.16 from here, then unzip it into a folder. It should look like this.
The structure is similar to your project structure in eclipse, only with few extra (slim3) files.
Step 4 - Copy paste.
Now highlighted are files copied from slim3-blank folder.
Also, some jar as well from WEB-INF/lib
Step 5 - Annotation Processing Factory configuration.
This setting is simple but very important. It actually help generate source code for you. You'll know what it does as you continue working on your project.
Right click your project > properties and find Java Compiler > Annotation Processing.
Enable project specific settings.
Enable annotation processing.
Click on Factory path (left panel).
Click Add JARs...
Find slim3-gen-1.0.16.jar from your project. Add it.
Move it to the top.
Click OK and we leave the settings as it is for now.
Step 6 - web.xml
The web.xml was copied from slim-blank folder, only thing need to change is the slim3.rootPackage. It should be something like "com.mycompany", but...
Anyway, step 7 - Ant build.
As you can see, there is a build.xml file copied from slim3. This file will be heavily used throughout the project. So it will be a good idea to open a Ant view to use it.
To show Ant view, go Window > Show View > Others... > Ant > Ant
Then find and click the little add buildfiles icon and add the build.xml from your project folder. And you will see display as picture above.
From slim3 tutorial, the difference is you don't need to right click the build.xml and Run As...
Just double click target in the Ant View and you are done.
Step 8 - now, let's see how the magic works. Run gen-controller (double click on the ant view). You will see a popup, key in the path to your controller.
Once you click OK, slim3 will create a few files on your project.
Let's look at each file closely.
As I entered '/admin/user/' as controller path, slim3 creates:
- IndexController.java - the controller class to handle URL http://localhost:8888/admin/user/ or http://localhost:8888/admin/user/index
- IndexControllerTest.java - test class to test the controller. I love this feature.
- war/admin/user/index.jsp - the View
In short, code generator. (for lazy developer like me)
Step 9 - let's look at the controller.
Oh No~!! We have a problem! Help!!!
Nar~! No worries. Just build path issues.
Go to WEB-INF/lib, right click slim3-1.0.16.jar and add to build path. Solved.
Step 10 - not ready to run yet.
GAE is complaining. What to do...
Go to eclipse > preference > Java > Installed JREs, add JDK 1.7 into it. Click the checkbox to make it the default. Default is only JRE. Sorry for not covering the details.
Once configured, you should see the changes on your project showing it is using JDK and the error message will be gone.
Step 11 - show time
Right click your project and run as google web application.
Output on the console:
Now we go to http://localhost:8888/admin/user/
Just to make sure what is happening. Edit war/admin/user/index.jsp
Yeap! We got hello world.
In short, path "/admin/user/" is handled by the controller, then the controller forward us to /war/admin/user/index.jsp. Typical mvc, right.
This is my first approach trying slim3. I believe there is a more elegant way to set it up. Any comments for improvement is welcome. Actually there is a slim3 plugin for eclipse too, I only found out after this...
My next assignment was to implement RBAC in slim3. Will post some more stuff when it is ready.
Embedding ActiveMQ in Spring Web Apps
Notes: I won't recommend this approach. It is for prove of concept. Run stand alone instance of your ActiveMQ. May the force be with you.
I have a process that need to do calculation on an array of data. The thing is it takes very very very long to complete the calculation. As the result, the user click on something, then they need to wait for the browser to load and think very hard before it show something back to the use, whereas the client doesn't really cares about the outcome of the calculation.
activemq-client-5.10.0.jar
activemq-spring-5.10.0.jar
javax.jms.jar
javax.management.j2ee.jar
spring-core-4.1.0.RELEASE.jar
spring-jms-4.1.0.RELEASE.jar
spring-messaging-4.1.0.RELEASE.jar
(and others... sorry, I can't list them all)
Found this somewhere online, create a embedded dummy broker with spring.
Define a queue.
Create a spring connectionFactory to be used later.
JMS Template - for sending message to the broker.
As in the comment, settings for annotated JmsMessageListener in Spring 4.1 (again, must be 4.1)
And always remember to turn it on.
And here is the java code.
After everything works, I expand the settings to include more queues and also set up a proper ActiveMQ broker running by itself (removing the tag and have pointing to my ActiveMQ url).
Problem:
I have a process that need to do calculation on an array of data. The thing is it takes very very very long to complete the calculation. As the result, the user click on something, then they need to wait for the browser to load and think very hard before it show something back to the use, whereas the client doesn't really cares about the outcome of the calculation.
Design:
I initially try make an asynchronous function call but the system requires the data been processed in sequence, one after one on an order. So I went explore if Messaging can help solve my problem.Environment:
activemq-broker-5.10.0.jaractivemq-client-5.10.0.jar
activemq-spring-5.10.0.jar
javax.jms.jar
javax.management.j2ee.jar
spring-core-4.1.0.RELEASE.jar
spring-jms-4.1.0.RELEASE.jar
spring-messaging-4.1.0.RELEASE.jar
(and others... sorry, I can't list them all)
Implementation:
In applicationContext.xml, add namespace for amq and jms.Found this somewhere online, create a embedded dummy broker with spring.
Define a queue.
Create a spring connectionFactory to be used later.
JMS Template - for sending message to the broker.
As in the comment, settings for annotated JmsMessageListener in Spring 4.1 (again, must be 4.1)
And always remember to turn it on.
And here is the java code.
After everything works, I expand the settings to include more queues and also set up a proper ActiveMQ broker running by itself (removing the
Thursday, September 25, 2014
Implementation of immutable Value Object
Was reading article about Domain Driven Design here and wrote this snippet (in Java) about immutable Value Object. By setting the parameter to final will make it immutable, which will restrict the developer to change it's value.
Hope this is what the author means :p
Hope this is what the author means :p
Subscribe to:
Posts (Atom)