Search This Blog

Sunday, July 31, 2011

40:05

Did a little personal time trial up Roanoke Mountain from the Walnut Street bridge yesterday. It took me 40:05. It was hot and I think I can do better.

Zapped

Big storm yesterday with a lot of lightning. I happened to be watching an Orioles game and to add injury to the insulting nature of watching the O's we had a lighting strike that took out the power and as an added bonus zapped our TV. Bummer.

Thursday, July 28, 2011

Runtime

We have some systems that we run in AWS for developers to train and experiment on without breaking our core systems. It works great, but you have to be careful to make sure you shutdown these systems when done using them. To run SAP PI, you need a pretty beefy system and it costs about $1 an hour. If someone forgets to shut it down for, oh lets say three weeks, you are looking at a nice $500 bill.

I either need a tool that alerts me that they are running every day or so. Or, maybe I just go buy some AMZN stock...

Wednesday, July 27, 2011

Finally

I finally got Solution Manager to do what it promises to do and calculate the files needed for an upgrade of one of our SAP systems. Now, I'm faced with the task of actually upgrading the system. SAP seems to have a pretty nice tool for that: SAPehpi.  I went through guides and the main notes around it this morning got it running along. I'm sure the first attempt will result in failure, but I've got my backups and I'll keep my fingers crossed.

Tuesday, July 26, 2011

Complex

I've been implementing some of the functionality of SAP Solution Manager to help with system upgrades in our environment and it is incredibly complex. SAP has been having trouble getting customers to adopt Solution Manager and now I know why.

All I want to do is add my systems to a landscape and let the tool help me figure out what files need to be downloaded from SAP to get to a given service pack level. Since they now have a configuration wizard, you would think that would be about a two week task of installing and doing some configuration and then it would just work. Wrong. I've been at this for over a month and it still isn't quite there. It's been a series of patches and errors and patches and errors just to get the systems connected. There has to be a better way.

Why doesn't SAP maintain a Solution Manager lite environment at service.sap.com that we can just register our systems in and have it figure out what files we need? Why should every individual customer have to set up an on-premises tool for this? For large customers, there might be a lot of other benefits of having the system on site, but for us, it makes no sense and is just frustrating.

Sunday, July 24, 2011

SOAPy Trois

A simple change to add an EditText into the view and wire it up with the following code and we are now passing user entered text into the web service call. The only thing that took a few moments of thought was how to get a String out of an edit text since getText() returns an editable. I tried getString() and it worked. Code changes to SOAPy are below:

        buttonGoodbye.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                final EditText txt = (EditText) findViewById(R.id.editText1);
                String name = txt.getText().toString();
                if (name.length() == 0) name = "No name";

                new CallServiceTask(HelloAndroid.this).execute(
                        GOODBYE_OPERATION_NAME, name);
            }
        });
        final Button buttonHello = (Button) findViewById(R.id.button2);
        buttonHello.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                final EditText txt = (EditText) findViewById(R.id.editText1);
                String name = txt.getText().toString();
                if (name.length() == 0) name = "No name";

                new CallServiceTask(HelloAndroid.this).execute(
                        HELLO_OPERATION_NAME, name);
            }
        });


So, that was easy. On to the more complex data types.

Saturday, July 23, 2011

Secure

I enabled 2-step verification on my Google account this week. It went fairly smoothly with the only confusion coming when I had to create single use passwords for my phone and Eclipse plugin.  I'm using the Android app to generate the keys and I like that it will work whether or not I have service. I'm a little worried about what happens if I'm traveling and get all my stuff stolen (both phone and wallet containing the backup codes) and don't have ready access to call the US. I guess I'll have bigger things to worry about in that case...

Friday, July 22, 2011

SOAPy Deux

I moved my small Android test app ahead a bit by adding threading via an AsyncTask. All you need to do is subclass AsyncTask and implement a few methods and Bob is your uncle. The only things that required some real thought and trial and error was displaying dialogs and error handling.

The ProgressDialog was very easy to use. I just took the base activity as an argument and created on in the constructor for my CallServiceTask:

        // constructor creates progress dialog on activity
        public CallServiceTask(Activity activity) {
            dialog = new ProgressDialog(activity);
        }


The error dialog was a bit more tricky. To implement exception handling, I created another class called MyResult which contains the results of the web service call (in this simple case, a String) and an Exception. I used this class to catch the exceptions:

        @Override
        protected MyResult doInBackground(String... operation) {
            MyResult result = new MyResult();
            SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
                    operation[0]);
            request.addProperty("arg0", operation[1]);
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                    SoapEnvelope.VER11);
            envelope.setOutputSoapObject(request);
            HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
            httpTransport.debug = true;

            try {
                httpTransport.call(SOAP_ACTION, envelope);
                Object response = envelope.getResponse();
                result.setAnswer(response.toString());
            } catch (Exception ex) {
                // log it, set the exception flag and return
                Log.i("L10Systems", ex.toString());
                result.setError(ex);
            }
            return result;
        }

Then when returning the results in onPostExecute, I checked for the exception. If we had an exception, I show an AlertDialog. This took me a lot of trial and error and looking around to figure out. It certainly is a bit more complex than the typical ShowDialog() method you find in most desktop development environments.

The full code is below. Next, I'm going to add user input to the web service to actually interact with it and try some more complex data types.

package com.l10systems.helloandroid;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class HelloAndroid extends Activity {
    private static final String SOAP_ACTION = "http://l10systems.appspot.com/hellosoapserver";
    private static final String GOODBYE_OPERATION_NAME = "sayGoodbye";
    private static final String HELLO_OPERATION_NAME = "sayHello";
    private static final String WSDL_TARGET_NAMESPACE = "http://hellosoap.l10systems.com/";
    private static final String SOAP_ADDRESS = "http://l10systems.appspot.com/hellosoapserver";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final Button buttonGoodbye = (Button) findViewById(R.id.button1);
        buttonGoodbye.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new CallServiceTask(HelloAndroid.this).execute(
                        GOODBYE_OPERATION_NAME, "Blargh");
            }
        });
        final Button buttonHello = (Button) findViewById(R.id.button2);
        buttonHello.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new CallServiceTask(HelloAndroid.this).execute(
                        HELLO_OPERATION_NAME, "Blargh");
            }
        });
    }

    private class CallServiceTask extends AsyncTask {
        private ProgressDialog dialog;

        // constructor creates progress dialog on activity
        public CallServiceTask(Activity activity) {
            dialog = new ProgressDialog(activity);
        }

        @Override
        protected void onPreExecute() {
            this.dialog.setMessage("Calling web service");
            this.dialog.show();
        }

        @Override
        protected MyResult doInBackground(String... operation) {
            MyResult result = new MyResult();
            SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
                    operation[0]);
            request.addProperty("arg0", operation[1]);
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                    SoapEnvelope.VER11);
            envelope.setOutputSoapObject(request);
            HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
            httpTransport.debug = true;

            try {
                httpTransport.call(SOAP_ACTION, envelope);
                Object response = envelope.getResponse();
                result.setAnswer(response.toString());
            } catch (Exception ex) {
                // log it, set the exception flag and return
                Log.i("L10Systems", ex.toString());
                result.setError(ex);
            }
            return result;
        }

        @Override
        protected void onPostExecute(MyResult result) {
            // close the progress dialog
            if (dialog.isShowing()) {
                dialog.dismiss();
            }
            // if we have an error, show a dialog
            if (result.getError() != null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(dialog
                        .getContext());
                builder.setMessage("There was a problem with the web service.")
                        .setCancelable(false).setPositiveButton("OK",
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog,
                                            int id) {
                                        dialog.cancel();
                                    }
                                });
                AlertDialog alert = builder.create();
                alert.show();
                // otherwise, set the text view with the result
            } else {
                TextView textView = (TextView) findViewById(R.id.textView1);
                textView.setText(result.getAnswer());
            }
        }
    }
}

Veinte

Nevermind was released 20 years ago. We moved to Seattle a few years later. Coincidence? I think not.

Thursday, July 21, 2011

Hammer

Tomi Ahonen drops an absolute box of hammers on Nokia's move to Windows Mobile. He is certainly right that it looked like they were onto something with the N9 and MeeGo and you can't argue with the really bad financials.

But they needed some kind of shakeup. Symbian was dragging them down and they had to get away from it. The Microsoft move was bold but they really might not make it through to the other side. They really couldn't go to Android.

At $6 USD per share, they have a valuation of $11.7B USD. Microsoft just ponied up $8.5B for Skype. Can they swallow another one?

Wednesday, July 20, 2011

Nails

Frank Chimero really nails it with his description of baseball. The pace of the game and the season mimic life - the ebb and flow of routine peppered with important moments and crises.

Tuesday, July 19, 2011

SOAPy

I've been testing the waters for some Android development. I know I'm late to the party, but we've been seeing more and more demand for mobile apps, so I want to start to get a picture of what it is like. Initial impressions are good (net of some Eclipse weirdness where it seems to forget the library settings on the build path when I restart it sometimes).

The first thing I wanted to do was call a SOAP web service from Android. Yes, SOAP is old school and doesn't make a lot of sense sometimes, but I eventually want to get this working with my SAP NetWeaver systems which speak SOAP. Anyway, the first thing to do was to get a SOAP service running where I can get to it from the Internet.

I'd tried Google App Engine some time ago and thought it was interesting but this gave me a chance to figure out how to create a SOAP web service in GAE. Luckily, there is a tutorial that makes it easy to figure out. Interesting that GAE makes you build all of the gunky plumbing to get this to work (how 2003), but it does work without a lot of trouble or weirdness. So, this code is running at http://l10systems.appspot.com/hellosoapserver. 

Next, it was a matter of figuring out how to call a SOAP web service from Android. There is a library called ksoap2 that does just the trick. It is also pretty old school and you have to take care of some of the plumbing yourself, but it works just fine. I adapted a simple example from Naveen Balani and it just worked. Here is the code:

package com.l10systems.helloandroid;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;


public class HelloAndroid extends Activity {
    private static final String SOAP_ACTION = "http://l10systems.appspot.com/hellosoapserver";
    private static final String GOODBYE_OPERATION_NAME = "sayGoodbye";
    private static final String HELLO_OPERATION_NAME = "sayHello";
    private static final String WSDL_TARGET_NAMESPACE = "http://hellosoap.l10systems.com/";
    private static final String SOAP_ADDRESS = "http://l10systems.appspot.com/hellosoapserver";
   
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final Button buttonGoodbye = (Button)findViewById(R.id.button1);
        buttonGoodbye.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                callWebService(GOODBYE_OPERATION_NAME);
            }
        });
        final Button buttonHello = (Button)findViewById(R.id.button2);
        buttonHello.setOnClickListener(new OnClickListener(){
            public void onClick(View v) {
                callWebService(HELLO_OPERATION_NAME);
            }
        });
    }
   
       private void callWebService(String operation) {
        TextView textView = (TextView)findViewById(R.id.textView1);
        //setContentView(textView);
        SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE, operation );
        request.addProperty("arg0", "Blargh!");
        SoapSerializationEnvelope envelope =
            new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.setOutputSoapObject(request);       
        HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
        httpTransport.debug = true;
       
        try {
            httpTransport.call(SOAP_ACTION, envelope);
            Object response = envelope.getResponse();
            textView.setText(response.toString());
        } catch (Exception ex){
            textView.setText(ex.toString());
        }
    }
}


This is pretty silly and limited, but it didn't take very long to go from zero to calling a SOAP service in Android. Next steps will be to get the requests running in threads and get some more complex data types moving across the wire.

Monday, July 18, 2011

Haole

We recently booked a trip to Hawaii to go to a friend's wedding. We've never been and it should be very interesting and a lot of fun. We are probably going to stay in a condo for the week leading up to the wedding and then move over to the Turtle Bay resort for the big event. It's two and a half months away and I'm already excited. I'm so haole, I don't even know I'm haole.

S3

I've thought that Amazon S3 would be an excellent backup media for a lot of businesses. But, they charged something like $0.10 USD per GB which just doesn't work when you are backing up a couple of TB of data on a regular basis.  However, they have just changed their pricing model to eliminate the fee for data transfer in. You still pay to get data out ($0.12 USD per GB out), but that is (hopefully) much more rare if you are using it for backup.

I did a quick test this morning to move a XenServer VM snapshot to S3 using the free version of S3 Browser  and it took 12 minutes to move 1.24 GB of data from our data center to S3. That is probably too slow to use for a TB of data (~200 hours assuming it is linear), but the pro version of S3 Browser will parallelize the upload and allow you to have more than 2 upload tasks at once. If it is 10x faster, then it becomes workable for a once-a-week archive.

Sunday, July 17, 2011

Wireless

My trusty old ZyXEL x-550 router started to give up the ghost so I was in the market for a new wireless router. After long and deliberate consideration consisting of reading an email blast from buy.com, I went with a TRENDnet TEW-639GR (I would put a link in but apparently, this model has been discontinued) It was $40 shipped for a Wireless N router, so I figured it was worth a try.

So far, so good. Installation was a snap. I think it took me longer to figure out where to plug in the wall wart than actually set up the router. Basically, it was unplug the old and plug in the new. I haven't tested extensively, but so far, I have a strong signal and it hasn't dropped me once even though I am all the way across the house in a place that was always a trouble spot for the x-550. The only thing that I might miss is that it doesn't support DD-WRT which I would like to experiment with.

I'm continually amazed at the sharp improvement of price to performance in wireless networking gear. I think I paid twice as much for half of the performance when I bought the X-550 about 5 years ago.

Saturday, July 16, 2011

VNC

I needed a way to get to the desktop of my Ubuntu 10.04 system from my openSuse 11.4 laptop via VNC. To get a jumpstart on this, I searched the web and found a nice outline of what to do at http://theseekersquill.wordpress.com/2010/03/16/vnc-server-ubuntu-windows/.

I already had vnc4server installed, so I started with step 3 which is to run vncpasswd to establish a password for the VNC connect. The first time I did this, I ran it as sudo and it didn't work so I had to go and delete the generated password file and do it again as my user account.

Next, I edited ~/.vnc/xstartup in vim. By default, 10.04 has the following lines commented out:

#!/bin/sh
unset SESSION_MANAGER
sh /etc/X11/xinit/xinitrc


So I uncommented them and left the rest of the file alone. That didn't work. Connecting via KRDC gave me a blank blue screen. So, I edited the file so that it contained just the lines above and I tried to connect and got through, but got a gray screen with nothing on it except a cursor with an X. Progress!

Digging into the log, I noticed that there was a permissions problem calling xintitrc. So, I ran
chmod +x /etc/X11/xinit/xinitrc, killed the server and tried again. This time it worked and all is well in linuxland.

Friday, July 15, 2011

X8

A month ago, I ran across a great deal ($159) on an unlocked Sony Xperia X8 on newegg.com. I've had an interest in trying an Android phone and this seemed like a good way to test the waters with minimum risk.


I wasn't quite sure what to expect, but I've been impressed with the phone so far. It is about two generations behind the most recent phones but it does the basics pretty well. The screen is small but sharp and responsive to gestures. I especially like the form factor which is quite small and fits in a pocket quite easily. The industrial design is simple - basic black with a minimum of frills and decor.

Probably the most disappointing aspect is that the phone is pretty underpowered compared to modern phones and can take a few seconds to respond to commands. But, for the price, you really can't beat it. I'm impressed enough with Android (I also have a rooted nook - more about that later) to put it at the top of my list for my next major phone upgrade. Blackberry, it's been nice knowing you.

Thursday, July 14, 2011

New Day Rising

I'm going to try to make some posts in this space over the next few
months. I've been distracted by 1,000,001 other things, but it's time
to get back to posting some tech stuff. Stay tuned...