Saturday, July 21, 2012

Dynamic Classes with AngularJS

Here's a solution someone posted: http://jsfiddle.net/rur_d/tNZAm/

Some say it's bad idea to have your controllers being aware of classes. Well it's a solution that works.

Document Ready Event When Using AngularJS With JQuery

When you are making a page out of multiple partials/fragments in AngularJS, the document ready event for JQuery seems to fire before the page is fully assembled.

The correct way to do something when the page is fully loaded in AngularJS is by using the '$viewContentLoaded' event listener, by putting the following code into your controller.
$scope.$on('$viewContentLoaded', function(){
// do something
});

Reference: http://www.aleaiactaest.ch/angular-js-and-dom-readyness-for-jquery/

AngularJS: Calling a Javascript Function in the Controller

This is done by using "ng-click".

Example assuming you already created a function in the controller called "doSomething":
<a href ng-click="doSomething()">Do It</a>

Friday, July 20, 2012

Jersey Exception Handling

Jersey offers centralized Exception handling with "ExceptionMappers". This means you can allow Exceptions to be thrown up to the framework and then you can define how to handle them. It also means you are able to "catch" and handle exceptions that occur before and after the code that you write is being run.

 Let's say you want to handle "MyWebServiceException", you can create an ExceptionMapper "MyWebServiceExceptionMapper" like this:
@Provider
public class MyWebServiceExceptionMapper implements ExceptionMapper<MyWebServiceException> {

@Override
public Response toResponse(Exception e) {
GenericEntity<String> entity = new GenericEntity<String>(
   “{\"statusCode\":\"ERR-100\",\"responseData\":\"Error Processing Web Service\"}” ){};
return Response.status(Status.OK).entity(entity).type(MediaType.APPLICATION_JSON).build();
}
}

In order for this to be registered with Jersey, you'll need to put it in a package that's being scanned by Jersey to be resources or providers, so in the web.xml, have something like this:
<init-param>
   <param-name>com.sun.jersey.config.property.packages</param-name>
   <param-value>com.myws.resource;com.myws.provider</param-value>
</init-param>

In this example, I separated the packages for resources and providers, providing 2 packages to be scanned.

To handle each exception differently, just create as many ExceptionMapper classes as you wish, and put them in the same package to be picked up and registered.

You can also use this to return a different HTTP status code for different errors, but as mentioned in the comments of an earlier POST, that's not going to work well with cross-domain Javascript REST requests.

Thursday, July 19, 2012

Jackson Polymorphism

You can handle polymorphism with Jackson using the following annotations at the class level:
j@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "accountType")
@JsonSubTypes({
   @Type(value = AdminAccount.class, name =”ADM”),
   @Type(value = NormalAccount.class, name =”NML”)
})

This will tell Jackson to map the object to the "AdminAccount" class when the "accountType" property is "ADM", and to the "NormalAccount" class when the "accountType" property is "NML".

Other options are available, such as directly using the class name.

One "gotcha" I discovered is that the "accountType" property must not be implemented in the POJO class. If there is an "accountType" property in the class, it will be null when it's time to work with it in Java. In Java-land, you'll have to use "instanceof" to know what object it is.

A article with more detailed examples: http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html

Wednesday, July 18, 2012

HTTP Status Codes for REST

For REST services, one common pattern is to use HTTP status codes as the status code for the request itself.

A good reference: http://restpatterns.org/HTTP_Status_Codes

ProGuard: Read Obfuscated Stack Traces

You'll need to run retrace.jar.
java -jar retrace.jar proguard.map stacktrace.txt
You'll also need proguard.jar in the same folder.
Link: http://proguard.sourceforge.net/index.html#manual/retrace/examples.html

Sunday, July 15, 2012

iOS: AudioQueue Get Audio Level

A very good example of this is found in the "SpeakHere" reference project provided by Apple:
Link: http://developer.apple.com/library/ios/#samplecode/SpeakHere/Introduction/Intro.html

Just some gotcha's and points to note:

You need to call AudioQueueSetProperty to enable the level metering feature in the first place:
UInt32 enableMetering = 1;
AudioQueueSetProperty(audioQueue, kAudioQueueProperty_EnableLevelMetering, &enableMetering, sizeof(UInt32));

The number returned by the AudioQueue will be a negative number with a maximum value of 0. To convert it to a number on a linear scale (i.e. gain level), use the following formula:
float level = pow(10., 0.05 * averagePower);

Where averagePower is the value returned by the AudioQueue for the audio level average power.

The rest should be pretty straight-forward from studying the example.

Links and References:

Mongo DB: Java API Get Object by ID

You'll get an error if you try to do something along the lines of "{_id: xxxxx}".

This is how it's done:
BasicDBObject searchCriteria = new BasicDBObject("_id", new ObjectId(id));
DBObject dbObj = collection.findOne(searchCriteria);

Jackson: Ignore Unrecognized Fields

By default, Jackson will throw an exception when a field in the JSON is not declared as a member variable in the class it is mapped to. To ignore these fields, add the following annotation to the POJO class:
@JsonIgnoreProperties(ignoreUnknown=true)

AngularJS: Batarang Debugging Tool

Recently, a debugging tool call Batarang was released for AngularJS. It runs as a Google Chrome extension.

Here's a blog about it:
http://blog.angularjs.org/2012/07/introducing-angularjs-batarang.html

Installation instructions:
https://github.com/angular/angularjs-batarang/blob/master/README.md

Things to note:
  1. It doesn't run on the stock Google Chrome. It runs on the "Canary" version which has experimental features for early adopters. You'll have to download, install, and run it as a separate program.
  2. Installing the extension the usual way won't work due to security restrictions. You'll have to drag the "crx" file into the extensions page (i.e. chrome://chrome/extensions/).

iOS: Making the Table Cell Background a Gradient

This is a good guide for doing it:

http://www.raywenderlich.com/2033/core-graphics-101-lines-rectangles-and-gradients

GUID Uniqueness

This is an article explaining how GUID can be almost certainly (if not totally certainly unique).

Link: http://blogs.msdn.com/b/oldnewthing/archive/2008/06/27/8659071.aspx

This is done by including the following information in the GUID:
  1. Machine ID (network card Mac address)
  2. Timestamp
  3. Counter to differentiate entries generated within the same timestamp
  4. Algorithm version identifier
This is the "Version 1" algorithm for GUID generation. There are other versions which rely more on random number generators. I'm not sure if those are as reliable as version 1 in terms of guaranteeing uniqueness, and will be the topic of future research.

MongoDB: Scaling Approach

The first step in scaling is creating Replica sets (master/slave) where the slaves are allowed to service queries. This will be helpful for read-mostly workloads.

After that, the next step is sharding, where you'll need to define a partitioning mechanism. At a very large scale, the topology would be that of multiple shards, within which contain individual replica sets.

Link: http://www.mongodb.org/display/DOCS/Sharding+Introduction

Mongo DB Object ID

It is the unique identifier for each document in a collection. Compared to UUID, it is smaller (12 vs 16 bytes) but should still be workable because the requirement is just to have uniqueness within the DB cluster.

Uniqueness is guaranteed by including the machine ID, process ID, a timestamp and a counter for entries generated within the same second.

Link: http://www.mongodb.org/display/DOCS/Object+IDs

Saturday, July 14, 2012

Git: Conflict Resolution By Choosing A Copy

Often, it is as simple as choosing either the local copy in its entirety or the remote copy in its entirety.

In this case, use the following commands:
  1. Use local copy: git checkout --ours FILENAME
  2. Use remote copy: git checkout --theirs FILENAME
Reference: http://gitready.com/advanced/2009/02/25/keep-either-file-in-merge-conflicts.html

Thursday, July 12, 2012

iOS Activity Indicator

This is how it is done (example is using WebView)
Link: http://stackoverflow.com/questions/11334247/add-activity-indicator-to-web-view

I made some further changes so the indicator is more visible (by putting it inside an alert popup):

- (void)viewDidLoad
{
    [super viewDidLoad];    
    loadingAlert = [[UIAlertView alloc] initWithTitle:@"Loading..."
                                                      message:@"\n"
                                                     delegate:self
                                            cancelButtonTitle:nil
                                            otherButtonTitles:nil, nil];

    activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    [loadingAlert addSubview:activityIndicator];
}

- (void) showLoadingAlert
{
    [loadingAlert show];    
    activityIndicator.frame = CGRectMake((x,y,w,h);
    [activityIndicator startAnimating];
}
- (void) dismissLoadingAlert
{
    [activityIndicator stopAnimating];
    [loadingAlert dismissWithClickedButtonIndex:0 animated:NO];
}

Note that I set the frame after "show". This is because if I wanted to calculate x,y,w,h relative to the size of the loading alert frame, these values will only be non-zero after show.

NSTimer Gotchas With Threads/RunLoops

Sometimes when you notice that the NSTimer isn't working (i.e. the scheduled task doesn't fire), it can be caused by runloop issues.

By default, it runs in the current run loop from where it is scheduled. If you schedule it from the wrong loop, it might not fire as the loop could be blocked somewhere else.

Which method you use to initialize the timer also makes a difference. The "scheduledTimerWithTimeInterval" creates a timer that runs in the current loop. If the current loop is not suitable for the timer to run, the timer may not fire and you have no idea why.

If you have a problem with the above, you will have to use the "timerWithTimeInterval" methods. However, you have to remember to add the timer to the run loop that you want to add on.

For example, to schedule a timer on the main loop from another loop:

NSTimer *timer = [NSTimer timerWithTimeInterval:waiTime target:self selector:@selector(fireMethod:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]

The various behaviors are documented in the class reference.

Reference: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html

Wednesday, July 11, 2012

iOS: Positioning a View Relative to Parent

This is done via the "frame" property of the View, e.g.

viewObj.frame = CGRectMake(20,20,50,40);

Tuesday, July 10, 2012

MySQL: Dumping With Users and Privileges

A gotcha when trying to clone an entire MySQL DB is that the user privileges are not completely cloned.

The following command would have resulted in users and privileges being cloned (since the "mysql" database would have been dumped), but they do not take effect until a "FLUSH PRIVILEGES" command has been issued:

mysqldump --all-databases > db.sql

This means additional manual step of issuing the "FLUSH PRIVILEGES" command is needed before the DB is usable.

In order to ensure that the "FLUSH PRIVILEGES" command is run during DB restore (so no additional steps needed to get DB up and running), include the "--flush-privileges" option during the dump.

mysqldump --all-databases --flush-privileges > db.sql