Question: So am I crazy for considering doing a beta/production release on Glassfish V3 Prelude?
Since all of my content is dynamic, I'm not even thinking of bothering to set up apache in front either. Doing so complicates the setup by requiring something like AJP or mod\_jk and will not offer us much in terms of capability.

So there will be three war files on deployment.
3 JNDI data sources with about 90 connections parked, scaling up to 160 to a PGSQL datastore....

The three wars comprise a CMS system and a grails application?

Is my logic fatally flawed that I don't need to put apache in front of this setup?

Answer: 
They use the MPVolumeView, simple add it and it's makes the rest when the user touch it. Note: Doesn't work in iPhone Simulator. I think the release note also mentioned do not use it direct in Interface Builder. 

```
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(25, 378, 270, 30)];
[self.view addSubview:volumeView];
[volumeView release];

```
Here is another (complete) example of setting the hardware volume AND retrieving the volume after pressing the hardware keys:

```
// AVAudiosession Delegate Method
- (void)endInterruptionWithFlags:(NSUInteger)flags
{
    // When interruption ends - set the apps audio session active again
    [[AVAudioSession sharedInstance] setActive:YES error:nil];

    if( flags == AVAudioSessionInterruptionFlags_ShouldResume ) {
        // Resume playback of song here!!!
    }
}

// Hardware Button Volume Callback
void audioVolumeChangeListenerCallback (
                                         void                      *inUserData,
                                         AudioSessionPropertyID    inID,
                                         UInt32                    inDataSize,
                                         const void                *inData)
{
    UISlider * volumeSlider = (__bridge UISlider *) inUserData;
    Float32 newGain = *(Float32 *)inData;
    [volumeSlider setValue:newGain animated:YES];
}

// My UISlider Did Change Callback
- (IBAction)volChanged:(id)sender
{
    CGFloat oldVolume = [[MPMusicPlayerController applicationMusicPlayer] volume];
    CGFloat newVolume = ((UISlider*)sender).value;

    // Don't change the volume EVERYTIME but in discrete steps. 
    // Performance will say "THANK YOU"
    if( fabsf(newVolume - oldVolume) > 0.05 || newVolume == 0 || newVolume == 1  )
        [[MPMusicPlayerController applicationMusicPlayer] setVolume:newVolume];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Set the volume slider to the correct value on appearance of the view 
    volSlider.value = [[MPMusicPlayerController applicationMusicPlayer] volume];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    // Activate the session and set teh delegate
    [[AVAudioSession sharedInstance] setActive:YES error:nil];
    [[AVAudioSession sharedInstance] setDelegate:self];

    // Create a customizable slider and add it to the view
    volSlider = [[UISlider alloc] init];
    CGRect sliderRect = volSlider.frame;
    sliderRect.origin.y = 50;
    sliderRect.size.width = self.view.bounds.size.width;
    volSlider.frame = sliderRect;
    [volSlider addTarget:self action:@selector(volChanged:) forControlEvents:UIControlEventValueChanged];
    [self.view addSubview:volSlider];

    // Regoister the callback to receive notifications from the hardware buttons
    AudioSessionAddPropertyListener (
                                                                 kAudioSessionProperty_CurrentHardwareOutputVolume ,
                                                                 audioVolumeChangeListenerCallback,
                                                                 (__bridge void*)volSlider
                                                                 );

    [...]
}

- (void)viewDidUnload
{
    [super viewDidUnload];

    // Remove the Hardware-Button-Listener
    AudioSessionRemovePropertyListenerWithUserData(
            kAudioSessionProperty_CurrentHardwareOutputVolume, 
            audioVolumeChangeListenerCallback, 
            (__bridge void*)volSlider);
}

```