Friday, December 19, 2008

Subversion Authorization

This is probably obvious to others, but took some figuring out for me...

We're using subversion with the svn+ssh protocol, and we need to setup a new repository which only certain users will have access to.

After reading through the manual, it seemed that I needed to configure the conf/svnserve.conf file to use a users file, and then setup the allowed users there.

Well, finally it turns out that because we're tunneling our svn, it's really just controlled by the file permissions. Since our server's hosted on linux, I:
  • Created a new group [sudo addgroup restricted]
  • Added the appropriate users to that new group
  • Set the owner on the svn repository directory [sudo chown -R svn.restricted /path/to/repository]
  • Set the file permissions on the svn repository directory [sudo chmod -R o-rwx /path/to/repository]
All good!

Thursday, December 4, 2008

I Love IntelliJ

I had some hex values for colors, e.g.:
Color c = new Color( 0xcc33cc );
What I really needed, though, was to have the colors broken out into their constituent, base-10, parts. 

Ctrl+Enter on the "Color(" brings up a context menu, "Choose Color". Up comes a dialog box. Hmmm... Click on the RGB tab (alt+G), click OK (hit enter), and voila! I've got what I need:
new Color( 204, 51, 204 )
Yeah... I love IJ :-)

Tuesday, October 28, 2008

Mouse Capture and IFrames in GWT

In our application, we have some split panels... On one side is some nice, happy GWT content, and on the other is an iframe. Well, when you move the splitter, and your mouse gets out over the iframe, the splitter stops moving. Huh?

It turns out that the split panel is capturing the mouse when you start the resize. After a bit of digging, I noticed that for we just stop getting the mouse events when the mouse moves over the iframe. Googling turns up something kinda similar: http://groups.google.com/group/Google-Web-Toolkit-Contributors/browse_thread/thread/36f70df2a52f42d2.

It was pointed out to me that if you drag a MyGWT-derived dialog box over the iframe, all is good. However, dragging a regular GWT-derived dialog box over the iframe exhibits the same problem.

Do some digging, and I find out that MyGWT is covering the entire browser window with a transparent panel. The dialog is parented to this panel. The panel adds an event preview, and only allows events to go through to the dialog.

Sounds ugly, but I give that a shot...when the split panel resize starts, create a panel, make it as big as the browser window, and then only allow events through if they're destined for the splitter:
RootPanel root = RootPanel.get();
setPixelSize( root.getOffsetWidth(), root.getOffsetHeight() );
DOMHelpers.setZIndex( getElement(), DOMHelpers.getTopmostZIndex() );
root.add( this, 0, 0 );
setVisible( true );
DOMHelpers.setZIndex( splitElem, DOMHelpers.getTopmostZIndex() );
DOM.addEventPreview( this );

Inside the onEventPreview() method for this panel:
public boolean onEventPreview( Event event ) {
  Element target = DOM.eventGetTarget(event);
   // Cancel the event if the target is not the splitter...
  return ( target == splitElem );
}


Finally, when the resizing is done, clean up:
DOM.removeEventPreview( this );
RootPanel root = RootPanel.get();
root.remove( this );
setVisible( false );

Since, of course, this is only a problem in FireFox, compile, deploy, and test it out. And, it still doesn't work. :-(

Left over from a previous attempt at solving this problem, I had changed the split panel class to implement EventPreview. Once I added code in there to duplicate the handling of Event.MOUSEMOVE and Event.MOUSEUP from the onBrowserEvent()....voila! It all works!

Tuesday, October 7, 2008

Label + Link + Label

Once again, this took way too long to figure out. Inspired by http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/953262516e9d664b?hl=en, but since I can't use GWT 1.5 (yet), I came up with another way of making this work.

The whole problem (as pointed out in that discussion thread) is that a <div> is rendered with "display:block;", thus forcing newlines... The fix is to sprinkle in a style that forces "display:inline;"...
Label prefix = new Label( "prefix " );
prefix.addStyleName( "inline-label" );

Label link = new Label( "foo bar" );
link.addStyleName( "hyperlink" );
link.addStyleName( "inline-label" );

Label suffix = new Label( " suffix" );
suffix.addStyleName( "inline-link" );

Panel flow = new FlowPanel();
flow.add( prefix );
flow.add( link );
flow.add( suffix );

And in the CSS:
.hyperlink {
  color: blue;
  text-decoration: underline;
  cursor: pointer;
}

.inline-label {
  display: inline !important;
}



Thursday, October 2, 2008

onAttach vs onLoad

Always getting these confused...

onAttach() is invoked when the widget is attached to the document. It can be called in the following situations:
  • The widget's parent (which implements HasWidgets) is calling it's own doAttachChildren()
  • The widget's parent is being set (e.g., setParent())
The last thing that onAttach() does is to invoke onLoad().

By default, onLoad() does nothing. So, this is the best place to insert code that has to be run whenever the widget is actually hooked up to the document.

Personally, I think this might be less confusing if the names were chosen better. Perhaps, onAttach() should have been private, and the first thing it could do is call beforeAttach(), and the last thing would be to call afterAttach(). 

Oh well.

P.S.: My suggestion wouldn't quite work because of Composite...it doesn't want/need the base behavior. See, it's not simple...

GWT ScrollPanels

Urgh. Nothing's easy. I just want some widget to scroll, so I add it into a ScrollPanel. Right? Yeah, dream on.

Unless you set a specific height on the ScrollPanel (as in "150px"), you won't get the scroll bars. 

In other words, setting the height to "100%" won't work. :-(

Debugging GWT

Finally figured out this nifty little trick to help with debugging GWT apps. Since the only way to work with CSS issues is in FireBug, and GWT generates so many tables, and divs, and so forth, how can you easily map from the generated HTML back to your code?

Add styles everywhere! Name the styles similar (the same?) as the Java class, and you now know exactly which <div> corresponds to which Java class!

Monday, August 11, 2008

Setting up Subversion in a VM

I need to get a pretty basic subversion setup, so I figured I'd give it a go. (There's one pretty basic VMWare appliance available from http://www.ytechie.com/svn-vm, but it's really old (Ubuntu 6.06, older version of subversion, etc...)

So, here's what I'm after:
  • Up-to-date Ubuntu
  • NTP (to keep time synch'd)
  • Subversion 1.4 (latest stable), at least with svn+ssh access, but even better with https access
  • WebSVN
  • Webmin (so I don't have to get to the box to do stuff)
Lesson #1: Uninstall stuff you don't want before applying patches. This way, you don't wait for things like Open Office, Evolution, various games etc..., to all get updated, none of which are desired.

During setup, I noticed a common problem I (and others!) seem to always run into with linux in a VM...crazy key repeating. This post (on the linuxquestions.org) ends up with reconfiguring X. However, it seemed for me that just going to System -> Preferences -> Keyboard, and changing from "US 105 (Intl)" to "US 104" did the trick.

For setting up subversion, I'm referring to a post on the Ubuntu Help pages.

When it came time to install the certificate for Apache, another Ubuntu page came in handy.

Notes:
  • This procedure winds up creating a self-signed certificate, which may not be sufficient in all cases.
  • When you access svn, you'll be notified with an error message that starts off with, "Error validating server certificate for 'https://svn-server:443'". Go ahead and accept the certificate permanently.
Installing WebSVN: I noted above that I installed webSVN, but that was a mistake. I completely purged it, and then re-installed it. This time, the configuration was a bit better, asking me if I wanted to configure apache and where my svn repositories were. Now, when I hit https://svn-server/websvn, it works!

I did find another article at Howtoforge that gave some hints on configuring websvn. No matter what I did, though, trying to enable use of enscript doesn't want to work. Oh well, got bigger fish to fry.


Email Notifications: I installed svnmailer (from the Ubuntu repositories). The docs there pretty much tell you what to do... Testing this will have to wait until I'm in the office and the smtp server can be reached to do its thing... However, it appears that svnmailer has a bug, which causes practically unreadable diffs to be produced. Luckily, the debian bugs list suggests a work-around.

UFW: For security, I enabled ufw, and then set it to only allow ports 22 (ssh) and 443 (https).

SendMail: Well, turns out I needed to install sendmail locally. Just apt-get install, and all is good...gotta love it!

FogBugz Integration: The instructions for configuring the integration are here.


Late Breaking: Here's another site that has instructions for getting things going:Howtoforge.

Trixbox update

Gosh, after staying up til 2am trying to work out the issues with getting my Grandstream to register, I made a mistake...

I needed to use my phone, so I reset it to point directly at my VOIP provider. A few days later, I wanted to use my VOIP line via my Nokia e90, so I turned that on. Later in the day, someone from work called me...and it rang on both phones!!!

Whoo hooo!

Now, I just have to make sure my VOIP provider keeps it that way :-)

Wednesday, July 23, 2008

Installing trixbox

I grabbed the ISO from trixbox.org, and fired up the box I'm going to use as my server, a Dell Optiplex GX280 with 2 - 160GB SATA drives and 4GB RAM.

Using the Quick Install Guide (QIG), I pop in the CD, hit "Enter" to start the installation at 10:43pm... The installer asks for some very basic information and goes on its merry way... The box reboots itself at 10:53pm. There's some strange looking, uh, error? messages during the boot process, but it starts up & I log in.

Since I have my own DNS/DHCP server (using dnsmasq running in a VMWare image), I configured it to always assign the same IP address to this box. Although the box comes up with a host name of "trixbox1.localdomain", I'm not yet brave enough to change that...

I'm now logged in to the web interface. As per the QIG, I log in as "maint". I'd like to change the password, but don't know how and can't find a link to do so. I'm also a bit lost, as the QIG says to click on "Asterisk > FreePBX", but I can't find that anywhere. So, I just started clicking around :-) Finally found what I'm looking for: "PBX -> PBX Settings" from the top level menu.

(Hey! Look! A warning that I'm using the default password! Click on that hoping to be prompted to enter a new password, but no luck...just get an expanded version of the error message...)

Now, on the right, click "Module Admin". Well, I see a bunch of modules, but no where do I see any that I can add, so we'll leave that alone for now... (The important thing, I think, is that "Ring Groups" is marked as "Enabled".)

Continuing with the deviation from QIG, I clicked on "Extensions" on the right-hand menu. On the new screen, I left the default option (Generic SIP Device) and clicked Submit. OK, a rather long form here...
  • Extension: 200
  • Display Name: "Jay"
  • Under "Device Options", set a secret
  • Voice Mail: Change to "Enabled" and set a password and email address.
I left the rest of the options alone, although things like "VmX Locator" sounds possibly interesting...

So now, according to the QIG, I have an extension setup. On to the phone setup...

I went to the admin web page of my Grandstream 2000. I don't want to lose or mess with the setup I have (it works!!!), so I just disabled Account 1, and went into Account 2 settings. Unfortunately, it doesn't seem to register :-(

Digging around, sureteq has a setup guide. Let's see... Hey! Here's how we change the passwords...have to do it from the trixbox's command line:
* Update maint password by typing ‘passwd-maint’ at the command line. Enter the password twice.
* Update AMP password by typing 'passwd-amp' at the command line. Enter the password twice.
* Update meetme password by typing 'passwd-meetme' at the command line. Enter the password twice.
In my attempt to follow directions, I switched to trying to configure an X-Lite softphone on my laptop.

The next thing I learned, is that simply hitting "Submit" isn't enough! You see the orange bar at the top (missed that, didn't ya?!). You have to click that to actually load all the changes... Whew... now my soft phone registers!

Continue on, now with the Grandstream (kinda nice the guy at sureteq also has one!). I'm nervous about changing the "Firmware Upgrade and Provisioning" so I skip that part. I configure the rest, and reboot the phone, but it doesn't register. Well, there's more steps, so before changing the firmware provisioning, I'm going to continue...

After running the setup-grandstream command, I rebooted my phone. It still doesn't register. Going into the extension manager (PBX -> Endpoint Manager from the top menu), I hit 'GO' and sure enough, my phone is found! However, after associating it with the extension and rebooting it again, still not registering.

OK... I'm going to give up, bite the bullet, and change the provisioning... I'm quite nervous, but the pohne does reboot. Uh oh...it's downloading firmware... I'm really nervous now... this is what I didn't want... Well, let's hope it isn't bricked when this is done...

Phone has now rebooted a few times, and appears to be running, but still not registered...

I went through the rest of the setup steps. I think the only thing that tripped me up was the fact that I need to connect to my VOIP provider, which is different than the examples. I discovered that SIP register string in the Trunk configuration is of the form: user_name:password@server. Once I got that right, going to the PBX -> PBX Status shows that I'm registered!

Well, gonna have to work on the Grandstream more later...

Tuesday, July 22, 2008

How to Make a Software Developer Pull His Hair Out

If you're writing any sort of software that you expect others to build off of (e.g., some sort of library), and you want to make sure that your users scream in agony and never need the services of a barber again, here's a few ways to do that:

1. Make sure you've got all the important functionality implemented, but then hide the implementation with private methods and package local classes so that developers can't extend or customize the functionality.
Real-Life Example: At work, we're using MyGWT (well, not for much longer). We have a tree table, and when the user hides (or shows) a column, that needs to be saved (duh). Turns out that for some reason, simply marking a column as hidden doesn't actually hide it. Yet, the functionality works when I click on the menu item! Well, in order to make that happen, I needed to programatically make the same method call that happens when you (un)check the box to hide (show) the column. Good news--that method is protected. Bad news: (a) it's in a class that's automagically instantiated by another class. (b) one of the arguments to that method relies on a package local field of another class. Yikes. Well, 5 silly new classes later, I can stand up and say, "Mission Accomplished".


2. Write your code as inefficiently as possible. You know...call a method (say, foo) which returns an array, find out how many elements are in the array. Then:


for ( int i = 0; i < foo().length; i++ ) {
Thing[] things = foo();
Thing thing = things[i];
}
Yeah, nice, until you peek under the hood and realize what foo() does... Whoa. That wasn't pretty...

VOIP Setup on e90

Whoa...took freakin’ FOR EVER to figure this out... Thanks to Nokia E90 Communicator Blog and the use of X-Lite 3.0 Softphone.

Here's how it goes:
  1. Install & Setup X-Lite. Don't bother with the Linux version...it didn't seem to capture the right information :-(
  2. In X-Lite, turn on all the diagnostics logging.
  3. Make a call from X-Lite. Doesn't matter where to, or even if the party answers. In fact, given the volumes of data in the log file
  4. Dig through the log file. You're looking for "username=..." and "realm=..."
  5. Now, setup the e90:
    • Profile name: (whatever name you want)
    • Service Profile: IETF
    • Default Access Point: (whatever wi-fi you want to use)
    • Public user name: "sip:phonenumber@sip_server" (where 'phonenumber' is of the form abbbcccdddd, and 'sip_server' is the fully-qualified server name or IP address of the server.
    • Use compression: No
    • Registration: Always on
    • Use security: no
    • Proxy Server:
      • Proxy server address: sip:sip_server (same as above)
      • Realm: (what you got from x-lite)
      • User name: (your phone number, same as above)
      • Allow loose routing: Yes
      • Transport type: UDP
      • Port: 5060
    • Registrar Server:
      • Registrar server address: sip:sip_server (same as above)
      • Realm: (what you got from x-lite)
      • User name: (your phone number, same as above)
      • Password: (well, I can't tell you that :-)
      • Transport type: UDP
      • Port: 5060
That's it! Of course, there's still the issue (at least for me) that my VOIP provider only allows a single phone to register at any one time... But, that's why I'm investigating trixbox...

VOIP

For the past 10 or so months, I've been using VOIP service from Avvanta. It's been an extended beta, but now it looks like they're getting ready to finally go live.

Unfortunately, the one feature I really want, doesn't appear to be coming... After a bit of reading, I've discovered that what I want is a "Ring Group". This means that a call comes in, and all of the phones assigned to that group will ring at the same time. Gosh...sounds an awful lot like what I get with zero effort from plugging an old-fashioned phone into the wall.

For example, I have a Grandstream 2000 SIP phone, and I also have a Nokia e90, which I can use with VOIP.

Well, the VOIP service is looking like it's gonna be pretty cheap ($10/month?), so if I can get the ring group, it'll be pretty nice. Who knows, perhaps I can say goodbye to Quest? (Wouldn't *that* be nice!)

So, I'm going to document my trials & tribulations setting up trixbox on a spare box here.