Saturday, October 26, 2013

Turning your Mac into an Ubuntu server

I have the original Mactel Pro 1,1. It has been a very trustworthy machine, even better than my MBP 8,2 which has fan issues... However, with OS X support stopping at Lion and a 32-bit EFI, the writing is on the wall. So I decided to turn it into an Ubuntu file and media server.

Linux has come a long way both in maturity and adoption since my first aborted effort with RH Linux eons ago. I love that you essentially don't need Microsoft or Apple anymore except that Apple still makes the best hardware for your money. Anyway, back to topic...

Dual-boot your Mac

The first thing you have to do is to make your Mac dual-bootable. With Macs, and with old Macs, this can be challenging. However, here is it distilled (in a Frankenstein-ish sort of way):
  1. In Mac OS, open a terminal window and type: "ioreg -l -p IODeviceTree | grep firmware-abi". If is says EFI32 like mine does, you can only install a 32-bit version of Ubuntu. I wasted a few DVD-ROMs before figuring this one out.
  2. Get Ubuntu and burn a bootable disk onto a DVD-ROM. I used 13.10 desktop. Follow these instructions to make your disk.
  3. Follow the directions here under "Dual Boot" > "Quick steps". Remember to first install rEFIt while still in Mac OS. It's brief but easy to follow. Mid-way through it becomes inaccurate. Some helpful hints here:
    • 13.x doesn't seem to have the "System" menu (or at least I couldn't find it...). Click on "Search your computer...", type "Terminal", open that, and type "sudo gparted". Helpful hint: gparted seems to only be available in the "Try Ubuntu" stage. If you want partition management after fully installing, you need to install it using "sudo apt-get install gparted"
    • When prompted, select "Something Else" then move to my next step...
  4. Once you're in gparted, the previous post breaks down quickly. Pick up the instructions here and scroll down to the first comment, which is the "accepted" answer.
  5. Ease on through the setup and when prompted to automatically download updates or sign into Ubuntu One, decline everything possible. A hang-up in any step will force you to do a hard reset and restart the installation process.
Most importantly, remember that Command-C is now Control-C. Gar.

Install Samba

I want to share my filesystem with other computers including (gag) Windows.  I typically run Windows-only software in VMWare Fusion and would like the files to be commonly accessible to all computers.

This document is a good summary of how to make that work and no re-booting is required to test it.  The limitation is that it doesn't include user-specific authentication, which is essentially part 2.

Install SSH

Of course, you will want to be able to administer a headless system.  This post describes it very succinctly.

Setup VNC

VNC is not recommended unless you are sure of your firewall, and only then, it should be between computers within your network.  If that's true, then enable "Desktop Sharing" by searching for "vino" (in Ubuntu).  A common Mac OS VNC client is Chicken of the VNC.

That's the basics!  In my case, I converted a second Mac OS hard drive to be used as a backup filesystem (since this is a file server after all...) but those details are not in the scope of this entry.

Friday, December 23, 2011

Getting started with Grails (again)

Well, it's been a while since I had looked at Grails. In addition to being busy and not having a need for it, I was worried about Grails' future given Spring Roo's existence. However, I am no longer worried (for now). Grails 2.0.0 RC3 is now available and it seems that VMWare is committing itself to both Grails and Roo with the acknowledgement that they provide solutions for different audiences.

I have been updating this post to keep the information in one place so it has grown substantially. It should be a great reference for anyone who is new to Grails and looking to create a site from scratch.

Installation

  1. Download SpringSource Tool Suite 2.8.1 if you haven't already done so. It's free! I've found that the embedded vFabric tc Server works better on Linux than on Mac OS. Not sure why...
  2. Install Groovy, Grails, and make sure you have JDK 1.6

Getting Started

  1. Follow this beginners' tutorial. It's easy to follow and is relevant. In particular, I like how he introduces BootStrap.groovy, which is a way to pre-populate your data between recompiles
  2. This is another beginners' tutorial but it's wordier and harder to follow if you have little patience
  3. When learning how to do unit testing, simply remember that the tests automatically generated for you will fail. You need to edit populateValidParams() with at least one valid record. Also, this page is a concise tutorial on unit and integration testing
  4. If you are interested in using HAML, you need to install the plugin for each Grails project. Simply type, "grails install-plugin haml". Here is some more information. If your page is normally called "list.gsp", your HAML file should be named "list.haml".
  5. Here is an HTML to HAML converter. It works well but there may be a few bugs. I found it doesn't handle the "page import" statement or ternary operators well.
  6. All things Groovy... Ever seen a closure? Did you know that Groovy has a full API doc? Also, there are a few differences between Groovy and Java but not many.

Rich Internet Application

  1. A great way to incorporate user security (login/logout/authentication) is by using the Grails plugin for Spring Security. I chose to create my own User class by extending the SecUser class and Static URL rules.
  2. When you want to extend your controller output to provide XML or JSON (say you're building an API...) then this is a great tutorial. To test your controller, use curl:
    curl -v -L http://localhost:8080/Grails1/user/show/1.json
  3. As of Grails 2.0.0, the default JavaScript library is jQuery, not Prototype. This is a good tutorial on using AJAX with Grails and this post suggests the correct way to configure jQuery for Grails 2.0.0

Servers

  1. Heroku is a great way to setup a development server, and if your needs are limited, then it's free! To get started with Heroku, follow these setup directions. To deploy a Grails application, use the Grails Heroku plugin. I discovered that, for these instructions to work, you should initialize your Grails app using the command line, not by creating a "New" > "Grails Project" in STS. There is a supplemental instruction here to configure your Grails app to use a Postgres database.
  2. To publish your app to Heroku, you will need to use Git. I highly recommend Git in any case as a cheaper alternative to Perforce, SVN, and CVS. There is a learning curve but it is available out of the box if you have installed SpringSource ToolSuite (STS) on Ubuntu and there is a lot of good documentation. Here is a tutorial and a quick reference. An added bonus is that STS comes pre-installed with EGit -- the Git plugin for Eclipse.
  3. Heroku's signature database service is PostgreSQL. If you want to test your Grails application locally using the same database, this is a great beginner's tutorial to install and set up a Postgres server on your Ubuntu machine.
  4. If you want to use MySQL, install a local server using
    mysql-client-core-5.1
    Be certain to provide a root password because MySQL Workbench does not permit blank passwords. This post describes how to set up MySQL with your Grails app and this post describes how to use the ClearDB addon. Follow these instructions for your DataSource.groovy

Thursday, November 24, 2011

Android: java.lang.IllegalStateException: Target host must not be null, or set in parameters.

I must admit that I spent more than 20 minutes on this issue. Oddly enough, this exception does not occur when launching a Widget for the first time -- it only happens after you remove the widget then restore it. That is why I'm a little perplexed as to why it happens in some cases but not in others. Anyhow, this post describes the problem and the resolution accurately. After reading this blog, the issue went away in, oh... 30 seconds.

Monday, November 21, 2011

Android: INSTALL_FAILED_ALREADY_EXISTS

This was a vexing issue with a simple solution. Basically, I attempted to install an APK on a real device and received, "". Since I had never installed it previously, I was perplexed, but I tried renaming the APK, using "adb uninstall", all without success.

Then, this solution simply suggested that you install over the previous installation (as absurd as that sounds). Fortunately, it worked like a charm.

Wednesday, October 12, 2011

Using Pointers to Pointers for Linked Lists

I was reading up on Linked Lists and came across a great description on the meaning of Pointers to Pointers. As pointers and I have a love/hate relationship, I found this post very insightful and easy to understand. In the code I wrote to create and print a Linked List, I found it necessary to use a Pointer to a Pointer because the pointer to the "head" node of a singly linked list needs to be defined (and accessible) by the main() routine.
#include <iostream>
#include <cstdlib>

using namespace std;

typedef struct Node {
    int value;
    struct Node *next;
    struct Node *prev;
} NodeType;

void addNode(struct Node **head, int value);
void printList(char *listName, struct Node *head);

int main() {
    NodeType *head;
    head = (struct Node*)NULL;

    addNode(&head, 1);
    addNode(&head, 10);

    printList("myList", head);

    return 0;
}

void addNode(struct Node **head, int value) {
    NodeType *temp;
    NodeType *cur;

    temp = (NodeType*)malloc(sizeof(NodeType));
    temp->next = NULL;
    temp->prev = NULL;
    if(*head == NULL) {
        *head = temp;
        temp->value = value;
    } else {
        for(cur = *head; cur->next != NULL; cur = cur->next);
        cur->next = temp;
        temp->prev = cur;
        temp->value = value;
    }
}

void printList(char *listName, struct Node *head) {
    NodeType *temp;
    cout << listName << endl;
    for(temp = head; temp != NULL; temp = temp->next) {
        cout << temp->value << endl;
    }
    cout << "End" << endl;
}

Monday, August 15, 2011

Mac OS - Opening a new browser window from within a WebKit WebView

If you Google "createWebViewWithRequest", "WebView open new window", "decidePolicyForNewWindowAction" or check out the Apple Developer Documentation on Opening Multiple Windows using WebKit, there is a lot of chatter on the difficulty of getting such a supposedly simple thing to occur.

The objective is this: You programmatically create a WebView and load standard HTML/JavaScript/CSS into it. You want to click on a link in your WebView which launches a new browser window to any URL of your choosing.

Amazingly, I haven't seen a single post that gave a simple answer to such a simple question...

Here it is in a nutshell:
  • No, you don't need to specify the WebPolicyDelegate as follows:
    @interface MyIAppDelegate : NSObject <NSApplicationDelegate, WebPolicyDelegate> {
    Some delegate are assumed and don't need to be declared. In fact, you get a compiler error if you try
  • Create your WebView in IB, add this line to MyAppDelegate:
    @property (assign) IBOutlet WebView *webView;
    and "connect" the IBAction to IB
  • In applicationDidFinishLaunching:, add this line:
    [webView setPolicyDelegate:self];
  • Add this delegate method:
    - (void)webView:(WebView *)webView decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id < WebPolicyDecisionListener >)listener {
        [[NSWorkspace sharedWorkspace] openURL:[request URL]];
    }
  • In the HTML file, make sure your anchor tags contain 'target="_blank"'. For example:
    <a href="http://www.google.com/" target="_blank">click on this link</a>
You should be able to compile, click on a link in your WebView, and have it launch a new browser window to Google.

Tuesday, June 21, 2011

C++ static variables

This blog says it so well, that I'll just link to it. As an extension, if you define your own type, the rule also applies to your typedef. For example,
typedef map ConfigType;
ConfigType HelperUtils::config;

Thursday, June 9, 2011

Log4cpp

It is hard to find documentation for a Log4j-like utility for C++. Here is a good resource. I'll update this post with further comments on the utility (and especially portability) of this library.

Tuesday, May 24, 2011

Eclipse - Widget disposed too early

I'm using Ubuntu 10 (64-bit) and just installed Eclipse for C/C++. The first time I tried to start the application, it threw this error (plus a whole stack dump):
Widget disposed too early
This blog is the first resource that actually worked.

Wednesday, May 18, 2011

Android: updateAppWidget couldn't find any view, using error view

This was a vexing error that, according to all documentation and The Google, should not have been thrown. After a day of change code around, I stumbled on this post. The moral of the story is that you cannot change a button image; you can only change something defined in your layout XML as a <ImageView>

Wednesday, May 11, 2011

JSON-RPC from Android

There is a dearth of utilities on the Internetz that describe how to make a JSON-RPC 2.0 call from an Android device to a server somewhere. Attempts to create handy classes and posts on StackOverflow never quite seemed to do the trick. So... here it is. No fanfare.

Suppose you want to send this JSON string using HTTP using Content-type: application/json
{"jsonrpc":"2.0","method":"myMethod","params":[{"first":"A","second":"B"}],"id":"0"}

What makes this different from a regular HTTP call is the presence of an attachment and the Content-type: application/json designation. Here is the POST method:

 public HttpResponse doPost() throws JSONException, ClientProtocolException, IOException {
  HttpClient client = new DefaultHttpClient();
  
  JSONObject json = createMethodCall("myMethod", createMethodParams());
  Log.d(LOGTAG, json.toString());
    
  HttpResponse response = client.execute(createRequest(json));
  return response;
 }

I use the org.json libaries to construct my JSON object because the toString() method produces syntactically-correct JSON with no effort on my part:

 public JSONObject createMethodCall(String method, JSONArray params) throws JSONException {
  JSONObject json = new JSONObject();
  
  json.put("jsonrpc", "2.0");
  json.put("id", "0");   // we don't really use this so value is always zero
  json.put("method", method);
  json.put("params", params);

  return json;
 }
 
 public JSONArray createMethodParams() throws JSONException {
  JSONArray params = new JSONArray();
  
  // Default params that appear in all method calls
  params.put(new JSONObject().put("first", "A"));
  params.put(new JSONObject().put("second", "B"));
  
  // To add custom parameters, add to the return value rather than here, or this method becomes messy
  return params;
 }

The final trick is that HttpEntity is the Java object for MIME attachments. Therefore, attaching the JSON string as a StringEntity and declaring the content type as "application/json" is required for the server to recognize it as a valid JSON-RPC call.

 public HttpPost createRequest (JSONObject json) throws UnsupportedEncodingException {
  HttpPost request = new HttpPost(this.server + this.url);

  StringEntity entity = new StringEntity(json.toString());
  request.setEntity(entity);
  request.setHeader("Accept", "application/json");
  request.setHeader("Content-type", "application/json");
  
  return request;
 }

I suppose I could have gotten fancy and created a library that packages JSON-RPC more cleanly, but I chose to organize it as a collection of convenience methods. Here is the call from the parent code:

 RemoteCall remote = new RemoteCall();
 String response = null;
 try {
  response = remote.doPost();
 } catch (Exception e) {
  e.printStackTrace();
 }

Monday, May 9, 2011

Toggling Eclipse auto-suggest

The LogCat issue I described the other day caused a secondary problem: the auto-suggest feature in Eclipse was disabled! Well, to be fair I think I received a pop-up message about it, but who reads those anyway? So I accepted the message, and sadly, auto-suggest was gone.

To get it back, go to: Preferences > Java > Editor > Content Assist > Advanced. Make sure "Java Proposals" are enabled.

Friday, May 6, 2011

LogCat output is empty

I am using SpringSource Tool Suite which is a souped-up version of Eclipse (it comes with all kinds of plugins pre-installed as well as embedded servlet engines). The Android SDK comes with Log4J packaged, and the log output is shown in a window known as "LogCat". If this view isn't currently open, go to: Window > Show View > Other... > Android > LogCat

So.... For a few days, LogCat was producing output as expected. Then, it just went silent. Even restarting STS didn't bring back my beautiful logs. It turns out, whether coincidentally or otherwise, the MyLyn plugin causes some interaction as postulated in this post.

I did verify, on Mac OS X, that removing all JARs beginning with "org.eclipse.mylyn" causes LogCat to resume normally.

Thursday, May 5, 2011

Finding a Maven Repository

When you define a dependency in pom.xml, you are telling your compiler where to go get JARs from in the Maven archive. This way, you don't need to maintain your libraries and if they are updated, you simply change the version number in your pom.xml file.

If you know what dependency you need, for example, Apache Commons/IO, browse to a Maven mirror such as:
http://mirrors.ibiblio.org/pub/mirrors/maven2/
when you navigate down to:
http://mirrors.ibiblio.org/pub/mirrors/maven2/commons-io/commons-io/
The first and second directories represent the Group ID and the Artifact ID. For example:
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.0.1</version>
        </dependency>
In the above example, the reuse of "commons-io" makes it unclear, but the canonical form is:
http://mirrors.ibiblio.org/pub/mirrors/maven2/groupId/artifactId/

Wednesday, April 27, 2011

Creating a JSON-RPC service using Maven, Eclipse, and Tomcat

Oddly, there are very few resources for creating JSON-RPC services implemented using Java. JSON-RPC is a nice way for heterogeneous servers to communicate using a lightweight protocol. Because of the hierarchical nature of JSON plus its readiness for easy conversion to native domain objects, one would expect it to be a POJO by now.

However, that is not the case, and implementation requires download of third-party libraries such as jsonrpc4j. The site suggests that you create a Maven project to link to their JARs, write a couple of classes, and you magically have a JSON-RPC service. I beg to differ.

Setup

First, you need to create a Maven project, which is a macro available in SpringSource Tool Suite. Select File > New > Project... > Maven Project. Most importantly, you get a pom.xml and a /src/main directory with this macro. The Apache Web site specifies that directories in a Maven project are specified by convention. Therefore, to conform to Maven convention, you need to add a java/ directory under /src/main.

If you are a newbie to Spring, simply following the instructions in the site are not enough. In addition, you must add:

<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

to your web.xml. In addition, the XML file containing the properties should be named remoting-servlet.xml. Again, this is according to Spring convention.

You will need to add the following line to your interface:

import com.googlecode.jsonrpc4j.JsonRpcParamName;

and you may need to fiddle with pom.xml a little bit (I had to force Maven to use Java 1.6). In the meantime, Eclipse will likely display syntax errors but you may need to ignore them.

Compiling

The first time you attempt to compile using Maven, you should create a Run Configuration. To get the Base Directory, Browse the Workspace and select the project name. Under Goals, enter "eclipse:eclipse". Run the project once. If it succeeds, the only thing you've done is to force Eclipse to load the JARs declared in pom.xml. The syntax checker should be accurate from this point on.

Change the Goals to "clean install". As long as you don't declare new JARs, you should not need to change your Run Configuration again. Select this configuration to build your WAR file.

Deploying

Assuming you have a Tomcat instance available to you (I installed one on Ubuntu using "sudo apt-get install tomcat6"). Copy the WAR file to /var/lib/tomcat6/webapps/.

Testing

Because this is a JSON-RPC service, the most appropriate way to test is to use the following cURL command:

curl -v http://localhost:8080/projname/myServlet -d @test.json

where test.json may look like:

{
"jsonrpc": "2.0",
"method": "createUser",
"params":[
{"firstName": "Dean"}
],
"id": "0"
}

If it works, you are supposed to get a JSON response back, representing the deserialized Java object.

However, it didn't work for me. Yet.

Saturday, February 12, 2011

Access denied for user 'root'@'client machine name' (using password: YES)

I encounter this error frequently both at work and on the occasional home project. While attempting to connect to a MySQL server using say, MySQL Workbench, I get the following:

Access denied for user 'root'@'client machine name' (using password: YES)

To resolve this, there are three specific things you need to do. Please keep in mind that I'm a developer so please refer to a sys admin for more sophisticated solutions.
  1. Make sure MySQL is listening for incoming connections and that port 3306 is open
  2. Grant (remote) user privileges to your MySQL server
I'm using Ubuntu 10.10 (64-bit). I installed MySQL using

sudo apt-get install mysql-server mysql-client

and tested the installation using

mysql -u root -p
show databases;

In MySQL Workbench (I have 5.2.31 for Mac OS X), create a "New Connection" to "Start Querying", and provide the connection credentials (IP address of the MySQL server, username "root", and root password. You will likely see the error message described by the title of this blog.

Make sure MySQL is listening for incoming connections and that port 3306 is open

Perform steps 1 through 4 as described in this blog. I found that step 5 isn't necessary if you're just playing around and want to administer your own instance using the tools in Workbench.  Also, steps 6 and 7 aren't necessary because the default Ubuntu installation allows connections on all ports by default (!!!)

A simple test from your client computer is:

telnet [server ip address] 3306

You should see something meaningful but cryptic.  If you see "connection refused", then you will need to do step 6 above because it means the port has been disallowed by default (or your sys admin).

Grant (remote) user privileges to your MySQL server

Execute the following SQL query:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY 'some_pass' WITH GRANT OPTION;

Sunday, December 19, 2010

Using Cisco VPN on Snow Leopard

This is a great blog on setting up your VPN (Cisco IPsec only) on your Snow Leopard machine. Crazy, but neither Mac OS nor Cisco appear to have a supported standalone client.

Thursday, November 4, 2010

Synchronizing Tables in a MySQL Cluster

I created a table in a MySQL cluster but did not fully understand the way a Master-Master configuration operates.  I still don't.  However, it didn't take long to determine that I needed to create the table in each node of the cluster only to find out that data doesn't get synchronized automatically.  Grr.

A friendly DBA informed me that I needed to do this when creating the table:
create table tbl_name (i INT) ENGINE=NDBCLUSTER;
which specifies that this table is to be managed by the cluster. If the table has already been created (as was my case), this can be added after-the-fact:
ALTER TABLE tbl_name  ENGINE=NDBCLUSTER; FLUSH TABLES; 

Monday, May 10, 2010

Snow Leopard and VMWare Fusion 3

This past weekend I installed both, thinking, "hey, upgrades are better, right?"  I did, however, find two crippling problems.  The first pertains to Fusion 3.  When you start it up, it is slower than molasses, and the reason is that Spotlight is told to search your virtual machines.  In theory, it should do this once then be happy but reports have it that it reoccurs each time you start Fusion.  The solution is nicely stated in this post.

The second is that the Cisco VPN client doesn't work anymore.  This is because the current version of the client (4.9.x?...) is not 64-bit capable and it dies upon startup.  The solution is to use the built-in VPN client in Snow Leopard but I've heard the connection can be flaky.

Thursday, January 21, 2010

Configuring Eclipse to use GWT within a Grails project

One nice thing about Eclipse is that it sets up your environments, compile macros and build paths for you when you do, say, File > New > Grails Project. GWT has a similar setup that works just as well and in exactly the same way. However, I'm merging Grails and GWT functionality and want the benefits of code completion, etc.

As mentioned in a previous blog entry, however, the merging of GWT and Grails is not very straightforward and is subject to some idiosyncrasies, including the need to execute Grails commands from a terminal and not from within Eclipse.  For some reason, installing GWT plugins from within Eclipse does not work (my theory has to do with environment variables but I just gave up on it and went with the sure-fire way).

The net effect is that GWT auto-suggest doesn't work.  Nor does auto-creation of import statements.  Bleh.  I found that you can get the former to work fine by right-clicking on the Project name in Package Explorer, then Google > Web Toolkit Settings...  You get the following screen:



Check "Use Google Web Toolkit" then auto-complete (at least) will work.