# ## Posts ### [Securing Claude Code: Guardrails for AI-Assisted Development by Jim Manico](/2026/securing-claude-code-guardrails-for-ai-assisted-development-by-jim-manico/) In a presentation to OWASP London, Jim Manico, founder of Manicode Security, presents how he uses Claude Code to bootstrap projects safely using Claude Code and carefully scripted prompts and inputs. Using the approach he demos, developers won’t just vibe code sloppy, insecure software, but will set up their projects to get deterministic, high quality results. Manico begins by starting Claude and having it create a new repository on GitHub. Once the repository has been created and cloned, he ends his Claude session, then begins another from inside the newly created local directory. This allows Claude to sandbox itself to that directory. Once he has a repository, he thinks — and talks to Claude — about the architecture of the project, in this case a hypothetical llama farm, "for llama farmers and enthusisasts." To help with this, he uses a script that asks for a number of details, including: System purpose Primary use cases Runtime environment Server framework Client framework and many others. By using this script, he guarantees that certain very important questions are asked and answered every time he starts a new project. Once he has completed filling out his script, he copies and pastes the text into his Claude sessions, and Claude generates the ARCHITECTURE.md for his project. This file is then committed and pushed to the GitHub repository. Next, he talks to Claude about SECURITY.md. Like the previous, his bootstrap script asks a number of questions related to security: HTTP boundary security authentication and authorization input validation secret handling logging and error handling deployment and CI/CD safety In his prompt, he references the ARCHITECTURE.md file, as well as some prompt files that he has developed over time, covering topics like general code quality and secure API best practices. The script itself includes several other instructions, hints, restrictions, etc. on what should be included in the resulting file. Once he’s happy with the script, he copies and pastes, and Claude generates file. After a quick review, he commits and pushes this file too. For the third step, he walks Claude through setting up a GitHub issue template for requirements. The template is pretty large, and may all be appropriate for your project, but it should server as a good starting point. His template includes like ID Title Version Status Author Last Updated Priority Classification It is at this point that he suggests never letting Claude write code directly. His suggestion is that every change needed for the system should be broken down into one or more issues, using this template, which Claude will use later to generate the actual code changes. This also gives the developer a chance to review each step of a potentially large change, tweaking requirements, expectations, etc, as well as baking in logging and tracking for these changes. Using his script, he tweaks the text as needed for this project, then follows his now-familiar, copy, paste, review, commit, push cycle. Finally, his script instructs Claude to create the CLAUDE.md file, using the three files created previously as inputs. This file, of course, is the main memory file used by Claude, so getting it correct is very important. As a final step, to help reduce maintenance, token usage, etc., he instructs Claude to analyze ARCHITECTURE.md, SECURITY.md, and CLAUDE.md to find overlap, contradictions, and "low-signal content". With all of these files created, tuned, and trimmed, he then asks Claude to create an "EPIC master issue" to build the site. Claude generates a plan and breaks it down into the smaller steps, creating an issue in the GitHub tracker for each step, using the requirements template created earlier. Once the process finishes, the project has a number of issues that can be worked on by Claude (or a human), and the project has been bootstrapped in less than 45 minutes. As he mentions at the top of his talk, there are an infinite number of ways to set up and manage an AI-based development effort. This approach works for him, and might be a great place to start for you. To learn more from him, including getting access to his bootstrap script, follow him on X or visit his website. ### [Koin: The Way Object Handling Was Mint to Be](/2026/koin-the-way-object-handling-was-mint-to-be/) Table of Contents What is Koin? Adding Koin to Our Build Defining Our Modules Enabling Koin Injecting the Instances That’s it! Sharp-eyed readers of this series may have noticed something…​suboptimal: Up until this point, we’ve been creating certain objects as global variables. They’re immutable, so that may be technically OK, but those of a certain age have been taught for years how wrong that is, so technically OK or not, it just feels gross. In this post, we’re going to fix that with by implementing inversion of control with Koin. What is Koin? Koin is "[t]he pragmatic Kotlin & Kotlin Multiplatform Dependency Injection framework". If you search for Kotlin dependency injection frameworks, Koin will almost certainly be one of the top 3 (Koin, Dagger, and Hilt). Of those 3, Koin is the only one that is (currently) Kotlin Multiplatform compatible, so while the others may be fantastic, that lack of KMP compatibility helps make our decision. Fortunately, Koin is quite powerful and easy to use, so that works out great. Koin can be used either declaratively (i.e., manually building the modules via code) or via annotations. I have, for now, settled on the code approach. This does require a bit more work up front, but there’s much to be said for having an explicit and predictable set of objects for injection. Stealing the example from the Koin docs just to add some clarity, that would look something like this: class MyRepository() class MyPresenter(val repository : MyRepository) // just declare it val myModule = module { singleOf(::MyPresenter) singleOf(::MyRepository) } which could then be injected like this: class MyActivity : AppCompatActivity() { val myPresenter : MyPresenter by inject() } That’s pretty nice as it allows us, as users of DI have come to expect, to replace the implementation of MyPresenter as needed, whether it’s a new-and-improved implementation, or a mock for testing. DI decouples object instantiation and use, making our code a little less coupled and more flexible. So let’s see how we can enable that in our mobile app. Adding Koin to Our Build The first step, of course, is to make the libraries available to the app, so we need to update our build. We start with the version catalog: gradle/libs.versions.toml [versions] koin = "4.2.0-RC1" [libraries] koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-compose" } and then the application build file: composeApp/build.gradle.kts commonMain.dependencies { implementation(project.dependencies.platform(libs.koin.bom)) implementation(libs.koin.compose) // No version needed } All done. No need for plugins, etc., and we can move on to code changes. Defining Our Modules As alluded to earlier, we need to build our module(s), and then we need to start Koin itself. First up, we’ll build our module: composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/KoinModule.kt import androidx.room.RoomDatabase import androidx.sqlite.driver.bundled.BundledSQLiteDriver import com.arkivanov.decompose.router.stack.StackNavigation import com.steeplesoft.giftbook.database.AppDatabase import com.steeplesoft.giftbook.database.dao.GiftIdeaDao import com.steeplesoft.giftbook.database.dao.OccasionDao import com.steeplesoft.giftbook.database.dao.RecipientDao import com.steeplesoft.giftbook.database.loadDemoData import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO import org.koin.core.context.startKoin import org.koin.core.module.Module import org.koin.dsl.KoinAppDeclaration import org.koin.dsl.module fun initKoin(config: KoinAppDeclaration? = null) { startKoin { modules(appModule, platformModule) config?.invoke(this) } } expect val platformModule : Module val appModule = module { single<StackNavigation<NavigationConfig>> { StackNavigation() } single<AppDatabase>(createdAtStart = true) { val builder : RoomDatabase.Builder<AppDatabase> by inject() val database = builder .setDriver(BundledSQLiteDriver()) .setQueryCoroutineContext(Dispatchers.IO) .build() loadDemoData(database) database } single<GiftIdeaDao> { val db : AppDatabase by inject(); db.giftIdeaDao() } single<OccasionDao> { val db : AppDatabase by inject(); db.occasionDao() } single<RecipientDao> { val db : AppDatabase by inject(); db.recipientDao() } } At the start of the file, you’ll notice initKoin(). That’s the function that we’ll use to start Koin. We’ll come back to that in a bit. Next is expect val platformModule : Module. We have already seen, when setting up Room, how the different platforms supported by KMP sometimes need platform-specific code to perform various operations. By using the (hopefully now somewhat familiar) actual/expect mechanism, we instruct the compiler to expect a module definition in each platform to fulfill those platform-specific needs. We’ll show those in just a moment as well. Finally, we come to appModule, in which we define the objects we want to inject in our application, things like navigation and database objects. In previous versions of the app, we had, for example, val nav = StackNavigation<NavigationConfig>() at the top of RootComponent.kt. With Koin, we replace that with single<StackNavigation<NavigationConfig>> { StackNavigation() }. It’s effectively similar (immutable navigation object), but we can swap out the implementation as needed. If needed. The module then continues to create the RoomDatabase object (AppDatabase) and the related data access objects. You may notice that call to loadDemoData(database). Remember that this is there only to provide demo data for our purposes here, and is probably not something you want in a production app. Or maybe you do, but there are better ways to do it than this. :) So what does platformModule look like? Here’s the one for Android: composeApp/src/androidMain/kotlin/com/steeplesoft/giftbook/KoinModule.android.kt import androidx.room.Room import androidx.room.RoomDatabase import com.steeplesoft.giftbook.database.AppDatabase import com.steeplesoft.giftbook.database.dbFileName import org.koin.dsl.module actual val platformModule = module { single<RoomDatabase.Builder<AppDatabase>> { val context = AppContext.get() Room.databaseBuilder<AppDatabase>( context, context.getDatabasePath(dbFileName).absolutePath ) } } and iOS: composeApp/src/iosMain/kotlin/com/steeplesoft/giftbook/KoinModule.ios.kt import androidx.room.Room import androidx.room.RoomDatabase import com.steeplesoft.giftbook.database.AppDatabase import com.steeplesoft.giftbook.database.dbFileName import kotlinx.cinterop.ExperimentalForeignApi import org.koin.dsl.module import platform.Foundation.NSDocumentDirectory import platform.Foundation.NSFileManager import platform.Foundation.NSUserDomainMask actual val platformModule = module { single<RoomDatabase.Builder<AppDatabase>> { val documentDirectoryUrl = NSFileManager.defaultManager.URLForDirectory( directory = NSDocumentDirectory, inDomain = NSUserDomainMask, appropriateForURL = null, create = false, error = null, ) val documentDirectory = requireNotNull(documentDirectoryUrl?.path) Room.databaseBuilder<AppDatabase>( name = "$documentDirectory/$dbFileName", ) } } These files replace their platform’s respective AppDatabase.*.kt files. Enabling Koin Once we have our modules defined, we need to configure the app to start Koin. That is done in the platform-specific modules. For Android, we do that in our Application instance: composeApp/src/androidMain/kotlin/com/steeplesoft/giftbook/GiftBookApplication.kt import android.app.Application import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import kotlin.apply class GiftbookApplication : Application() { override fun onCreate() { super.onCreate() AppContext.apply { set(applicationContext) } initKoin { androidLogger() androidContext(this@GiftbookApplication) } } } and for iOS, it’s done in the App instance: iosApp/iosApp/iOSApp.swift import SwiftUI import ComposeApp @main struct iOSApp: App { init() { KoinModuleKt.doInitKoin() } var body: some Scene { WindowGroup { ContentView() } } } If you look at the Koin docs, you’ll see some different approaches — perhaps better approaches — but this worked for me, and, for now, that’s good enough. Let’s get to injectin'…​ Injecting the Instances Now that we have our common and platform-specific modules defined, we need to modify our code to use them. We’ll start with RootComponent. In previous entries, we created the nav variable outside the class (thus making it global), and used in our class. To change that, we will Delete the variable declaration: val nav = StackNavigation<NavigationConfig>() is deleted Add a new interface to our class: KoinComponent Add our injection site: private val nav : StackNavigation<NavigationConfig> by inject() That leaves the file looking like this: //... import org.koin.core.component.KoinComponent import org.koin.core.component.inject class RootComponent(componentContext: ComponentContext) : ComponentContext by componentContext, KoinComponent { private val nav : StackNavigation<NavigationConfig> by inject() //... } The rest of the class remains unchanged. We can make a similar change to HomeComponent: // ... import org.koin.core.component.KoinComponent import org.koin.core.component.inject class HomeComponent( componentContext: ComponentContext, var occasionId: Long? = null ) : ComponentContext by componentContext, KoinComponent { private val giftIdeaDao: GiftIdeaDao by inject() private val occasionDao: OccasionDao by inject() private val recipientDao: RecipientDao by inject() private val nav: StackNavigation<NavigationConfig> by inject() //... That’s it! There’s obviously more to DI and Koin, but for this app, that’s all we need for now. Anywhere there is a need to create a business/service object, we should at least consider adding it to the module (I hesitate to say "always", as every situation is different) and injecting it. With these changes, our app is now set up to allow us to do that. You can find the changes made in this entry in the KOIN tag of the repo. ### [Moar Data!](/2026/moar-data/) Table of Contents Setting up navigation Adding the screen Creating the Component Creating the Composable Adding the database support Conclusion In the last entry, we looked at how to read data from the device’s local database using Room and display it on the screen, but we did so using dummy data. In this entry, we’ll look at how to use Room in our components to persist user-entered data in our SQLite database. Setting up navigation Before we can attempt to add data, we need to update the UI to provide a means by which user can enter data. To do that, we’re going to add an "action button" to the screen. Compose has a built-on component, FloatingActionButton, but we’re going to wrap that a bit to make our usages a little simpler: ActionButton.kt import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.unit.dp @Composable fun ActionButton( icon: ImageVector = Icons.Filled.Add, onClick: () -> Unit ) { Box( modifier = Modifier.fillMaxSize().padding(20.dp), ) { Row(modifier = Modifier.align(Alignment.BottomEnd)) { FloatingActionButton(onClick = onClick) { Icon(icon, contentDescription = "Floating action button") } } } } Now, in HomeContent.kt, we can add this to the bottom of lambda body for AsyncLoad: ActionButton( onClick = { component.addRecipient() } ) and the function to handle the click: HomeComponent.kt fun addRecipient() { occasion?.let { nav.bringToFront(NavigationConfig.AddEditOccasionRecipient(it)) } } When the user taps the action button, rendered as a plus in the lower right corner of the screen, we’re going to navigate to a new screen, which means we need to make a series of changes: Add a new NavigationConfig entry Add support for the new entry in RootComponent.child() Create a new component in AddEditOccasionRecipientComponent.kt Create a new composable in AddEditOccasionRecipientContent.kt NavigationConfig.kt @Serializable data class AddEditOccasionRecipient(val occasion: Occasion, val recipient: Recipient? = null, val occasionRecip: OccasionRecipient? = null): NavigationConfig RootComponent.kt private fun child(config: NavigationConfig, componentContext: ComponentContext): ComponentContext { return when (config) { // ... is NavigationConfig.ViewOccasionRecipient -> ViewOccasionRecipient(componentContext, config.recipId, config.occasionId) // ... } } Adding the screen Creating the Component The next two steps are a bit more involved. Both the component and the composable have been written in a way that they can be reused to either add or edit the record. When adding a recipient for an occasion, we know the occasion ID, but, of course, not the recipient. When editing the recipient for the occasion, we know both. To support that, the constructor takes the required Occasion, and an option Recipient. For now, ignore that last parameter. :) As discussed in the last post, we register a doOnResume handler to load the data we need: If there is no recipient, We load a list of all recipients We then load all of the OccasionRecipient already set up for this occasion Finally, we filter the list of recipients to remove all that have already been added to this occasion. We’ll display this in the UI If there is a recipient, we load the appropriate OccasionRecipient Finally, we create an instance of OccasionRecipForm to help with our form handling in the UI. We’ll discuss that in the next post. Finally, to save the change, we create a new instance of OccasionRecipient, then call either updateOccasionRecip or insertOccasionRecip, depending on our need. Here’s the full component: AddEditOccasionRecipientComponent.kt import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.value.MutableValue import com.arkivanov.decompose.value.update import com.arkivanov.essenty.lifecycle.doOnResume import com.steeplesoft.camper.components.Status import com.steeplesoft.giftbook.NavigationConfig import com.steeplesoft.giftbook.database.dao.OccasionDao import com.steeplesoft.giftbook.database.dao.RecipientDao import com.steeplesoft.giftbook.form.OccasionRecipForm import com.steeplesoft.giftbook.model.Occasion import com.steeplesoft.giftbook.model.OccasionRecipient import com.steeplesoft.giftbook.model.Recipient import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO import kotlinx.coroutines.launch import org.koin.core.component.KoinComponent import org.koin.core.component.inject class AddEditOccasionRecipientComponent( val componentContext: ComponentContext, val occasion: Occasion, var recipient: Recipient? = null, var occasionRecipient: OccasionRecipient? = null ) : ComponentContext by componentContext, KoinComponent { private val nav: StackNavigation<NavigationConfig> by inject() private val occasionDao: OccasionDao by inject() private val recipientDao: RecipientDao by inject() var form = OccasionRecipForm(occasionRecipient) var requestStatus: MutableValue<Status> = MutableValue(Status.LOADING) var recipients: MutableValue<List<Recipient>> = MutableValue(emptyList()) init { componentContext.doOnResume { CoroutineScope(Dispatchers.IO).launch { if (recipient == null) { val allRecips = recipientDao.getAll() val recipsForOccasion = recipientDao.getRecipientListForOccasion(occasion.id).map { it.id } val available = allRecips.filter { !recipsForOccasion.contains(it.id) } recipients.update { available } } if (recipient != null && occasionRecipient == null) { occasionRecipient = recipientDao.getRecipientForOccasion(occasion.id, recipient!!.id) } form = OccasionRecipForm(occasionRecipient) requestStatus.update { Status.SUCCESS } } } } fun save() { CoroutineScope(Dispatchers.Main).launch { if (recipient != null) { val or = OccasionRecipient( occasionId = occasion.id, recipientId = recipient!!.id, targetCost = form.cost.state.value ?: 0, targetCount = form.count.state.value ?: 0 ) if (occasionRecipient != null) { occasionDao.updateOccasionRecip(or) } else { occasionDao.insertOccasionRecip(or) } nav.pop() } } } fun cancel() { CoroutineScope(Dispatchers.Main).launch { nav.pop() } } } Creating the Composable To finish creating the view, we create the associated @Composable. Like the component, this can be used to add or edit, with the UI changing based on the presence of a recipient value. If it’s null, the user is presented with a combo box. If it’s not, the user is shown the recipient’s name. That composable looks like this: AddEditOccasionRecipient.kt import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.arkivanov.decompose.extensions.compose.subscribeAsState import com.steeplesoft.camper.components.AsyncLoad import com.steeplesoft.camper.components.ComboBox import com.steeplesoft.camper.fields.IntegerField import com.steeplesoft.giftbook.model.Recipient @Composable fun AddEditOccasionRecipient( component: AddEditOccasionRecipientComponent, modifier: Modifier ) { Column( modifier = modifier, verticalArrangement = Arrangement.spacedBy(16.dp) ) { val status by component.requestStatus.subscribeAsState() AsyncLoad(status) { val form = component.form Text( buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { append("Occasion: ") } append(component.occasion.name) }, fontSize = 20.sp, ) if (component.recipient != null) { Text( buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { append("Recipient: ") } append(component.recipient!!.name) }, fontSize = 20.sp, ) } else { val recipients by component.recipients.subscribeAsState() val current: Recipient? by remember { mutableStateOf(component.recipient) } ComboBox(label = "Recipient", selected = current, onChange = { newValue -> component.recipient = newValue }, items = recipients, itemLabel = { recip -> recip?.name ?: "--" } ) } IntegerField( label = "Target Count", form = form, fieldState = form.count, ).Field() IntegerField( label = "Target Cost", form = form, fieldState = form.cost, ).Field() Row(modifier = Modifier.padding(top = 5.dp).fillMaxWidth()) { Button( onClick = { component.save() }, modifier = Modifier.padding(end = 3.dp) .fillMaxWidth(0.5f) ) { Text("Save") } Button( onClick = { component.cancel() }, modifier = Modifier.padding(start = 3.dp) .fillMaxWidth() ) { Text("Cancel") } } } } } The references to IntegerField we’ll cover in the next post. Other than that, this is a pretty basic Compose usage. To return briefly to the component, it’s important to note that, in the save() function, database access must be done off the UI thread. Here, we use the Main dispatcher: CoroutineScope(Dispatchers.Main).launch { // .. } Adding the database support The Room API makes inserting and updating data effortless. If you need a review of setting up Room, please refer back to Make Room for Some Data. We’ll start by showing the new OccasionRecipient model (Recipient is not that interesting, so we’ll not show it here): import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index import kotlinx.serialization.Serializable @Entity( // 1 primaryKeys = ["occasionId", "recipientId"], // 2 foreignKeys = [ ForeignKey(entity = Occasion::class, parentColumns = ["id"], childColumns = ["occasionId"], onDelete = ForeignKey.CASCADE), ForeignKey(entity = Recipient::class, parentColumns = ["id"], childColumns = ["recipientId"], onDelete = ForeignKey.CASCADE) ], // 3 indices =[ Index(value = ["recipientId"]), Index(value = ["occasionId"]), ] ) @Serializable data class OccasionRecipient ( val occasionId: Long, val recipientId: Long, val targetCount: Int, val targetCost: Int ) This is a touch more complex than the entities we’ve looked at before, but if you’ve used Hibernate, JPA, etc., it shouldn’t be completely unfamiliar. The class itself is unremarkable. The annotation, and its parameters, are doing the heavy lifting here. primaryKeys is a list of fields on the entity that make up the primary key foreignKeys is a list of ForeignKey objects that define everything need to create the foreign key entity - the parent entity parentColumns - a list of fields in the parent entity to include in the key childColumns - a list of fields in the child entity. The order in this list must match the order in parentColumns so that the fields are matched correctly onDelete - the action to perform when the parent record is deleted onUpdate - the action to perform when the parent record is updated (not shown here) indices - a list of indexes to be created in the database. When Room creates the database, these annotations will help control what database objects (tables, keys, indexes, etc.) are created. Remember to update the RoomDatabase definition: AppDatabase.kt @Database( entities = [Occasion::class, GiftIdea::class, Recipient::class, OccasionRecipient::class], version = 1 ) @TypeConverters(LocalDateConverter::class) @ConstructedBy(AppDatabaseConstructor::class) abstract class AppDatabase : RoomDatabase() { // ... } Finally, we can add the update and insert methods to OccasionDao: OccasionDao.kt @Insert @Transaction suspend fun insertOccasionRecip(occasion: OccasionRecipient) @Update @Transaction suspend fun updateOccasionRecip(occasion: OccasionRecipient) Room is smart enough to know how to create the SQL statements based on our @Entity, so that’s all we need to do. Conclusion We are now a bit closer to a complete application. As usual some details have been left out to attempt to keep this small. You can see more details in the Git repo. It’s not a complete, runnable application, but we’re getting there! ### [Decompose and Data. Let's See What You Got](/2026/decompose-and-data-let-s-see-what-you-got/) Table of Contents A Real Custom Screen Scaffold: Prettier Page Decorations The Home Screen The newly renovated HomeComponent Dummy Data In the last post — months ago (and, yes, I hand typed the em dash, not some soulless AI :) — we added support for the Room database API, so now we can store data, but we have no way of seeing what we’ve saved. We also have no way of giving it data to save. In this post, we’ll tackle the first part by creating views to show what we have, then loading the database with demo data. Let’s dive in. A Real Custom Screen Currently, our application has just the demo screen from the generator plus our dummy screen used to demonstrate navigation. Our first step will be to fix that. Let’s start by moving RootComponent and RootContent to the package com.steeplesoft.giftbook.ui.root, and deleting DummyComponent, DummyContent, GreeterComponent, and GreeterContent. This breaks our app, of course, but we’ll clean that up as we go. Next, let’s create a new component in the package com.steeplesoft.giftbook.ui.home. You are free to organize your classes how you’d like, so if you feel this is overkill, feel free to adjust as needed. HomeComponent.kt import com.arkivanov.decompose.ComponentContext class HomeComponent( componentContext: ComponentContext, var occasionId: Long? = null ) : ComponentContext by componentContext { } HomeContent.kt import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @Composable fun Home( component: HomeComponent, modifier: Modifier = Modifier ) { Text(text = "Hello") } And now let’s fix our build: RootComponent // ... private fun child(config: NavigationConfig, componentContext: ComponentContext): ComponentContext { return when (config) { is NavigationConfig.Home -> HomeComponent(componentContext) } } RootContent // ... when (val component = it.instance) { is HomeComponent -> Home(component, childModifier) } and, finally NavigationConfig @Serializable sealed interface NavigationConfig { @Serializable data object Home : NavigationConfig } It’s not pretty, but it’s an honest start. :) What we want this screen to something like this: We’ll not get there completely in this post, but this shows you where we’re heading. Let’s start with page decorations. Scaffold: Prettier Page Decorations In the screenshot above, the page has a header and a footer. Those are added in RootContent, as this allows all of our screens to have the same decorations. We’ll do that be replacing this: Column(modifier = modifier) { Children( stack = component.stack, modifier = modifier.padding(5.dp), animation = stackAnimation(slide()), ) { with this: Scaffold( modifier = Modifier.fillMaxSize(), topBar = { TopAppBar( colors = TopAppBarDefaults.centerAlignedTopAppBarColors( containerColor = MaterialTheme.colorScheme.primary, ), title = { Text( text = stringResource(Res.string.app_name), color = MaterialTheme.colorScheme.onPrimary ) } ) } ) { innerPadding -> Children( stack = component.stack, modifier = modifier.padding(innerPadding).padding(5.dp), animation = stackAnimation(slide()), ) { // ... I won’t pretend I understand everything about the Scaffold, so I’ll quote the official docs: The Scaffold composable provides a straightforward API you can use to quickly assemble your app’s structure according to Material Design guidelines. Scaffold accepts several composables as parameters. Among these are the following: topBar: The app bar across the top of the screen. bottomBar: The app bar across the bottom of the screen. floatingActionButton: A button that hovers over the bottom-right corner of the screen that you can use to expose key actions. Our top bar is pretty basic. We use the Material3 component, TopAppBar, and add a single Text child component that holds the app name. For the record, Res.string.app_name is defined in composeApp/src/commonMain/composeResources/values/strings.xml (you will likely need to create the directory and file): <resources> <string name="app_name">Giftbook</string> </resources> The bottom bar is a little more complicated, so we’ll skip that for now. The Home Screen If you run the app now, you should have a screen with a purple header (I know. Hideous.) with the text "Giftbook", and a plain 'Hello' just below it. Let’s replace Home with the following: @Composable fun Home( component: HomeComponent, modifier: Modifier = Modifier ) { val status by component.requestStatus.subscribeAsState() val occasionProgress by component.occasionProgress.subscribeAsState() Column( modifier = modifier, verticalArrangement = Arrangement.spacedBy(16.dp) ) { AsyncLoad(status) { val occasions by component.occasions.subscribeAsState() val current: Occasion? by remember { mutableStateOf(component.occasion) } ComboBox( label = "Current Occasion", selected = current, onChange = { newValue -> component.onOccasionChange(newValue!!) }, items = occasions, itemLabel = { item -> item?.name ?: "--" } ) LazyColumn(modifier = Modifier.testTag("recipientList")) { items(occasionProgress) { ElevatedCard( elevation = CardDefaults.cardElevation(defaultElevation = 6.dp), modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp) ) { Column(modifier = Modifier.padding(15.dp)) { Text(it.recipient.name, fontSize = 18.sp) } } } } } } } There’s a lot of red after that, but, for now, make note of the following: We have two subscribeAsState() calls. These will allow our screen to react implicitly when data changes in the component. We’ll see that shortly. The AsyncLoad component will allow us to display a "loading" screen while we query the database. Admittedly, that’s going to happen really quickly, but it’s a necessary step, or we’ll get really odd errors trying to read data that’s not available yet on the initial screen draw. Inside AsyncLoad, we have a remember { mutableStateOf() } call. This will help us remember (har har) the current state of the UI during "configuration changes" or, in plain English, screen rotations. :P We make use of LazyColumn, which is a component that allows us to make a list of components as a column. Rather than drawing every item in the list every time, though, LazyColumn will only draw the items that are visible at the moment, and will reuse components (if I understand correctly), to reduce memory and increase rendering speed. For all of this to work, we need to update the component. The newly renovated HomeComponent To make the compiler happy — and to make our app work — we need to make HomeComponent look something like this: // ... import androidx.compose.runtime.getValue // ... class HomeComponent( componentContext: ComponentContext, var occasionId: Long? = null ) : ComponentContext by componentContext { private val giftIdeaDao = db.giftIdeaDao() private val occasionDao = db.occasionDao() private val recipientDao = db.recipientDao() var occasions = MutableValue(listOf<Occasion>()) var requestStatus = MutableValue(Status.LOADING) var occasionProgress: MutableValue<List<OccasionProgress>> = MutableValue(mutableListOf()) var occasion: Occasion? = null init { componentContext.doOnResume { CoroutineScope(Dispatchers.IO).launch { requestStatus.update { Status.LOADING } val list = occasionDao.getFutureOccasions() occasion = if (occasionId != null) occasionDao.getOccasion(occasionId!!) else list.firstOrNull() occasions.update { list } occasion?.let { onOccasionChange(it) } requestStatus.update { Status.SUCCESS } } } } fun onOccasionChange(newValue: Occasion) { CoroutineScope(Dispatchers.IO).launch { occasion = newValue val list = recipientDao.getRecipientsForOccasion(newValue.id).map { val ideas = giftIdeaDao.lookupIdeasByRecipAndOccasion(it.recipientId, newValue.id) OccasionProgress( recipientDao.getRecipient(it.recipientId), newValue.id, targetCount = it.targetCount, actualCount = ideas.filter { idea -> idea.occasionId != null }.size, actualCost = ideas.sumOf { idea -> idea.actualCost ?: 0 }, targetCost = it.targetCost ) } occasionProgress.update { list } } } } There’s an awful lot of red in this, but there are several classes that you need to add. Most of these, while interesting and necessary, are a bit of a distraction here, so I’ll leave it as an exercise for the reader to get it from the Git repo. Having said that, let’s break down the changes: We use an init block to register a lifecycle callback, specifically doOnResume. This function will be called when the component is initially created, as well as after the screen/page/view is recreated on rotation, etc. In this function, we load data from the database, but we can’t do it on the UI thread, so we start a coroutine using the IO dispatcher. The first thing we do is set requestStatus to LOADING. If you look at the AsyncLoad usage in HomeContent, you should see that we declared val status by component.requestStatus.subscribeAsState(), and then pass status to AsyncLoad. By doing this, when we update HomeComponent.requestStatus, AsyncLoad will automatically rerender if needed. We’ll make use of that shortly. For now, a value of LOADING gets us a nice spinning loading screen. Next, we call occasionDao.getFutureOccasions() to get all the upcoming occasions defined in the app (see the Git repo if you’d like to see the implementation for that. It’s a pretty simple SQL query). Following that, we get the currently selected Occasion. On initial load, occasionId is null, so we just grab the first occasion in the list. However, if we have navigated to this page (something we haven’t seen yet), occasionId is not null, so we query for that occasion. We could simply filter list, but it’s possible that the user has requested a past occasion (again, via functionality we haven’t seen yet), so, to be safe, we just query the database. It’s all local on the device, so the performance hit is not noticeable. Once we have our Occasion, we call occasions.update, which updates the MutableValue variable, and triggers, potentially, rerenders in the view. If occasion is null, we call onOccasionChange, which will load the details (recipients, etc) for the occasion. That function (shown above) uses similar logic to what we have here, so I’ll not walk through that one. This post is long enough as it is. :) Finally, we call requestStatus.update { Status.SUCCESS }, which will trigger AsyncLoad to rerender, and our actual view is displayed on the screen. Dummy Data You should be able to run the app now, but there’s nothing to show. Unfortunately, if my understanding is correct, there is currently no way to ship a pre-populated Room database on Android, so we’ll use a bit of a hack to load some data when the app is installed. In AppDatabase.kt, we need to modify getRoomDatabase() like this: fun getRoomDatabase(builder: RoomDatabase.Builder<AppDatabase>): AppDatabase { val database = builder .setDriver(BundledSQLiteDriver()) .setQueryCoroutineContext(Dispatchers.IO) .build() loadDemoData(database) return database } Then, in composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/database/DemoData.kt, add this: val mutex = Mutex() fun loadDemoData(database: AppDatabase) { CoroutineScope(Dispatchers.IO).launch { mutex.withLock { loadRecipients(database) loadOccasions(database) loadGiftIdes(database) } } } // See Git repo for complete implementation private suspend fun loadGiftIdes(database: AppDatabase) { val dao = database.giftIdeaDao() if (dao.getAll().isEmpty()) { // ... } } private suspend fun loadOccasions(database: AppDatabase) { val dao = database.occasionDao() if (dao.getAll().isEmpty()) { // ... } } private suspend fun loadRecipients(database: AppDatabase) { val dao = database.recipientDao() if (dao.getAll().isEmpty()) { // ... } } These methods check to see if their respective table is empty, then load data if needed. Once you’ve added that and rerun the application, you should see something like this: And that’s basic data-to-screen logic. I breezed over a bit in this for brevity’s sake, so be sure you check out the Git repo for the complete source. In the next few posts, we’ll add the ability to create occasions, recipients, etc., and then we’ll take a look at dependency injection to see how we can clean up that object instantiation. If you have any questions, comments, corrections, or complaints, you can find me on X or LinkedIn. Until next time…​ ### [Make Room for Some Data](/2025/make-room-for-some-data/) Table of Contents Android Room The Data Model Entity: Occasion Type Converter: LocalDateConverter Type Converter: EventTypeConverter The Data Access Object Creating the RoomDatabase Getting the Builder: common Getting the Builder: iOS Getting the Builder: Android So far, we have a runnable application that has two screens. We can navigate between those screens, but the app doesn’t really do anything. In this post, we’ll start to fix that. We’ll lay out the data model for the application, then introduce the library, Android Room, we’ll use to access it. Android Room Android Room allows us to write Kotlin data classes as the representations for our data, providing an abstraction over an SQLite database. Developers familiar with Hibernate, JPA, Spring Data, etc. should be quite comfortable with Room. With a combination of annotations and compiler plugins, we can create a fairly robust data layer with very little effort. We’ll take a look at how that works, but, first, let’s look at our data model. The Data Model Since we discussed the gist of the application in the first entry in this series, I’ll not rehash that here. If you’re coming into the series in the middle, it might be helpful to visit the first post in the links above. That said, we are going to need three basic entities: occasions, recipients, and ideas. We’ll also need some relationships, but we’ll get to those later. Entity: Occasion One of the fundamental ideas (no pun intended) in a gift-tracking application is that of an occasion: when am I giving something? Our occasion entity will be, at least for now, pretty simple, consisting of a name, a date, and a type. The Kotlin data class will look something like this: import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey import androidx.room.TypeConverter import androidx.room.TypeConverters import com.steeplesoft.giftbook.database.LocalDateConverter import kotlinx.datetime.LocalDate import kotlinx.serialization.Serializable @Entity // 1 @Serializable data class Occasion ( @PrimaryKey(autoGenerate = true) // 2 var id: Long = 0, @ColumnInfo(name = "name") // 3 var name: String, @field:TypeConverters(LocalDateConverter::class) // 4 @ColumnInfo(name="eventDate", typeAffinity = ColumnInfo.TEXT) var eventDate: LocalDate, @field:TypeConverters(EventTypeConverter::class) // 5 @ColumnInfo(name="eventType", typeAffinity = ColumnInfo.INTEGER) var eventType: EventType = EventType.OTHER ) Let’s break this down: Every Room entity object is annotated with androidx.room.Entity as well as kotlinx.serialization.Serializable This identifies the primary key of our entity. We also instruct Room to autogenerate the value for us. If the value is 0, which we’ve specified as the default value, then Room generates the key’s value for us. Each column in the database needs to be annotated with @ColumnInfo. This also allows us to specify a table column name for those situations where we need to conform to an existing or externally-managed schema, or if we just really care about the column names. This column is tricky. We want to store a LocalDate (more on that in a minute), but Room doesn’t understand how to do that natively, so we specify a TypeConverter that will do the work for us. We’ll take a look at that below as well. This is another tricky field, for basically the same reason: Room doesn’t know how to handle enum classes, so we specify the TypeConverter for this as well. We’ll look at both converters together. Type Converter: LocalDateConverter This field is tricky for a couple of reasons. One is the aforementioned lack of support from Room. The second is the lack of direct support for modern Java date/time types across the platform supported by Kotlin Multiplatform. You might notice, then, in the imports that we’re using kotlinx.datetime.LocalDate and company. This is a library provided by Jetbrains that does provide the cross-platform support we need. gradle/libs.version.toml kotlinxDatetime = "0.7.1" # ... [libraries] kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } composeApp/build.gradle.kts // ... kotlin { // ... sourceSets { // ... commonMain.dependencies { // ... implementation(libs.kotlinx.datetime) // ... } } } Once our build is updated, we can write our converter: import androidx.room.TypeConverter import kotlinx.datetime.LocalDate import kotlinx.datetime.format class LocalDateConverter { @TypeConverter fun toLocalDate(days: String): LocalDate { return LocalDate.parse(days) } @TypeConverter fun fromLocalDate(date: LocalDate): String { return date.format(LocalDate.Formats.ISO) } } A detail I didn’t point out on our type declaration is another attribute on our annotation: @ColumnInfo(name="eventDate", typeAffinity = ColumnInfo.TEXT) Since SQLite doesn’t support a "real" datetime type, we tell Room to model this field as a TEXT field. In our converter, as you can see above, we convert to and from a ISO-8601 format. For the performance-conscious, this is not the fastest data type one might use (a Long, for example, might be better), but I chose this so that if I’m looking at the database, I can easily read the value. That’s kind of a dumb not-good-for-production reason, but the volume of data in this app will be small enough that I have some room (har har) for silliness like this. You can, of course, make different decisions. Type Converter: EventTypeConverter This converter is, in principle, the same, but we’re dealing with an enum class now, so there’s a little more work. First, the converter: import androidx.room.TypeConverter class EventTypeConverter { @TypeConverter fun toEventType(type: Int): EventType { return EventType.of(type) } @TypeConverter fun fromEventType(type: EventType): Int { return type.code } } This looks very similar to LocalDateConverter, but the part of interest now is toEventType. Note the .of function. That’s a function we will write, to convert an Int to EventType: import giftbook.composeapp.generated.resources.Res import giftbook.composeapp.generated.resources.anniversary import giftbook.composeapp.generated.resources.cake import giftbook.composeapp.generated.resources.gift import giftbook.composeapp.generated.resources.graduation import giftbook.composeapp.generated.resources.tree import giftbook.composeapp.generated.resources.valentines import org.jetbrains.compose.resources.DrawableResource enum class EventType( val code: Int, val label: String, val image: DrawableResource ) { BIRTHDAY(0, "Birthday", Res.drawable.cake), CHRISTMAS(1, "Christmas", Res.drawable.tree), ANNIVERSARY(2, "Anniversary", Res.drawable.anniversary), GRADUATION(3, "Graduation", Res.drawable.graduation), VALENTINES(4, "Valentine's Day", Res.drawable.valentines), OTHER(999, "Other", Res.drawable.gift); companion object { fun of(code: Int): EventType { return when (code) { 0 -> BIRTHDAY 1 -> CHRISTMAS 2 -> ANNIVERSARY 3 -> GRADUATION 4 -> VALENTINES 999 -> OTHER else -> throw RuntimeException("Unknown event type") } } } } This is a basic Kotlin enum class, providing a code, which is what is stored in the database, a label that provides the on-screen text, and an image that provides an icon for the event. The of function we mentioned above can be seen here, which handles the Int to EventType conversion. In my experience, this is a pretty common approach for conversion from a primitive to an enum type, but maybe it’s new to you. If so, you’re welcome. If you hate it, then you can blame Larry. #Gatto The Data Access Object Room uses the Data Access Object (or DAO) pattern for accessing and mutating data. To create the DAO, you: Declare an interface, annotated with androidx.room.Dao Add functions to the interface to perform any operations you may need (e.g., get, insert, update, delete, etc) If you want asynchronous queries (and you probably do so that you’re not causing your app to block), each function should be a suspend function. Annotate your operations with the appropriate annotation from android.room.* (e.g., @Query, @Insert, etc). For any mutation methods, remember to add @Transactional. For any operation beyond the basics (e.g., getFutureOccasions), use @Query and provide the required SQL as the value for the annotation. That said, here is our occasion DAO: import androidx.room.Dao import androidx.room.Delete import androidx.room.Insert import androidx.room.Query import androidx.room.Transaction import androidx.room.Update import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone import kotlinx.datetime.format import kotlinx.datetime.toLocalDateTime import kotlin.time.Clock import kotlin.time.ExperimentalTime @Dao interface OccasionDao { @Transaction @Query("SELECT * FROM Occasion") suspend fun getAll(): List<Occasion> @Query("SELECT * FROM Occasion WHERE id = :occasionId") suspend fun getOccasion(occasionId: Long): Occasion @Transaction @Query("SELECT * from Occasion where eventDate >= :limit order by eventDate") suspend fun getFutureOccasions(limit: String = LocalDate.now().format(LocalDate.Formats.ISO)): List<Occasion> @Insert @Transaction suspend fun insert(occasion: Occasion) : Long @Update @Transaction suspend fun update(occasion: Occasion) @Delete @Transaction suspend fun delete(occasion: Occasion) } @OptIn(ExperimentalTime::class) fun LocalDate.Companion.now() = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date As you can see, we have a mix of basic CRUD operations (@Insert, @Update, and @Delete). There is not, however, say, a @Get. Retrieval operations are annotated with @Query, and we have to pass the retrieval query. With those annotations in place, though, Room handles all the marshalling and unmarshalling for us, so we can deal with our data — mostly — in an object-oriented manner. Again, if you’re a Hibernate, JPA, or Spring Data user, you should be right at home. One final note: Notice that last line? For some reason, kotlinx-datetime doesn’t have a now() function on LocalDate, and I find that very useful, so we’ve cobbled one on here. Kotlin extension functions for the win! Creating the RoomDatabase With our model and DAO defined, we now need to create the actual Room database. Unfortunately, we can’t just @Inject an EntityManager configured by some XML. No, we’re going to have to write some less-than-pretty code. :) import androidx.room.ConstructedBy import androidx.room.Database import androidx.room.RoomDatabase import androidx.room.RoomDatabaseConstructor import androidx.room.TypeConverters @Database( entities = [Occasion::class], version = 1 ) @TypeConverters(LocalDateConverter::class) @ConstructedBy(AppDatabaseConstructor::class) abstract class AppDatabase : RoomDatabase() { abstract fun occasionDao(): OccasionDao } // The Room compiler generates the `actual` implementations. @Suppress("KotlinNoActualForExpect") expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase> { override fun initialize(): AppDatabase } There’s a lot going on there, so let’s break it down. First up, we need to create our own RoomDatabase instance. It’s via this child class that we can add our application’s data model, etc., so we: Create an abstract class that extends RoomDatabase Add an abstract function that returns our DAO, OccasionDao Annotate the class with @Database and list the entites the database will support Add a @TypeConverters annotation to register the converter Add a @ConstructedBy annotation, which will enable Room to wire together generated code required to produce our database instance Now, that’s a lot, but, as Ron Popeil used to say on TV, "Wait! There’s more!" Each platform supported by Kotlin Multiplatform has its own way of accessing the filesystem, which will be required for creating the actual, physical database file, so we need to provide that code: Android fun getDatabaseBuilder(context: Context): RoomDatabase.Builder<AppDatabase> { val appContext = context.applicationContext val dbFile = appContext.getDatabasePath("giftbook.db") return Room.databaseBuilder<AppDatabase>( context = appContext, name = dbFile.absolutePath ) } iOS import androidx.room.Room import androidx.room.RoomDatabase import kotlinx.cinterop.ExperimentalForeignApi import platform.Foundation.NSDocumentDirectory import platform.Foundation.NSFileManager import platform.Foundation.NSUserDomainMask @OptIn(ExperimentalForeignApi::class) fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> { val documentDirectoryUrl = NSFileManager.defaultManager.URLForDirectory( directory = NSDocumentDirectory, inDomain = NSUserDomainMask, appropriateForURL = null, create = false, error = null, ) val documentDirectory = requireNotNull(documentDirectoryUrl?.path) return Room.databaseBuilder<AppDatabase>( name = "$documentDirectory/giftbook.db", ) } And, finally, to get our AppDatabase instance, we call: fun getRoomDatabase(builder: RoomDatabase.Builder<AppDatabase>): AppDatabase { return builder .setDriver(BundledSQLiteDriver()) .setQueryCoroutineContext(Dispatchers.IO) .build() } If you’re following along in your IDE, you’ve noticed two things. This post has gotten incredibly long, and trying to call getRoomDatabase() leaves us with a problem: how do I get the RoomDatabase.Builder<> the function needs? To answer that question, we’re going to back to expect/actual. And this will take some doing, so strap in. Getting the Builder: common To set up the platform-specific calls, we’ll add this to AppDatabase.kt: expect fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> The IDE should complain, but we’ll fix that right now. Getting the Builder: iOS We’ll start with the iOS implementation, as it’s pretty simple. In fact, we’re just going to modify existing code a bit: actual fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> { // ... } We just added the actual keyword to our existing function. And we’re done. Getting the Builder: Android Things are a bit more complicated for Android, as the function we have above requires a Context (e.g., ApplicationContext). At no point in our code, though, will we have easy access to that, so we’re going hack together a solution. Judge all you want, but sometimes you do what you have to do, and I just haven’t spent the time to find a nicer way. This is the price you pay for coming along on this journey with me. :) First, let’s add a new object: object AppContext { private var value: WeakReference<Context?>? = null fun set(context: Context) { value = WeakReference(context) } internal fun get(): Context { return value?.get() ?: throw kotlin.RuntimeException("Context Error") } } This object will hold the reference to our ApplicationContext for us. Now, let’s set that value. To do that, we’ll need another class, a child of android.app.Application: class GiftbookApplication : Application() { override fun onCreate() { super.onCreate() AppContext.apply { set(applicationContext) } } } This provides an explicit Application class for Android to use (as opposed to the implicit one that lives magically somewhere :), but we have to tell the system to use it: composeApp/src/androidMain/AndroidManifest.xml <application android:name=".GiftbookApplication" Now, we should be able to get our instance: composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/database/AppDatabase.kt val db by lazy { getRoomDatabase(getDatabaseBuilder()) } If all goes as planned, when we reference db here in a moment, it will be lazily initiated, and all of these functions we’ve put together will work in peace and harmony to produce a database instance. :P Let’s see if we’re lucky! We’re not going to mess with any real data just yet, but we will make a dummy call to make sure we’ve wired things up correctly. So, in RootComponent, we’ll add some throw-away code: class RootComponent(componentContext: ComponentContext) : ComponentContext by componentContext { init { val dao = db.occasionDao() AppLogger.i("The dao is $dao") } } Let’s run our application and check Logcat: 2025-08-26 17:13:25.905 26593-26593 lesoft.giftbook com.steeplesoft.giftbook W Verification of kotlin.Unit com.steeplesoft.giftbook.MainActivity.onCreate$lambda$0(com.steeplesoft.giftbook.ui.RootComponent, androidx.compose.runtime.Composer, int) took 185.007ms (302.69 bytecodes/s) (3456B approximate peak alloc) 2025-08-26 17:13:26.002 26593-26593 CompatChangeReporter com.steeplesoft.giftbook D Compat change id reported: 309578419; UID 10234; state: ENABLED 2025-08-26 17:13:36.957 26593-26593 GIFTBOOK com.steeplesoft.giftbook I The dao is com.steeplesoft.giftbook.database.OccasionDao_Impl@aa93cab And it works! It’s not super pretty, which I’m sure you’re tired of me saying, but we’ll clean it up a bit when we integrate dependency injection. For now, play with that and see what you can do. In the next post, we’ll look at putting data on the screen. If you’d like more details on Room, including data migrations and other more advanced/detailed topics, you can find those here. ### [Decompose Navigation: Let's Add a Screen](/2025/decompose-navigation-let-s-add-a-screen/) Table of Contents The Needed Pieces The Component The Content NavigationConfig Child Factory support Child content support 2, 4, 6, 8! It’s time for us to navigate! In the last post, we added the various pieces to make navigation possible and stopped JUST short of the goal line. In this post, we’ll finish up our navigation discussion by adding a new screen and seeing navigation in action. The Needed Pieces Each screen/page in our app will need several changes: A component class A content function A NavigationConfig entry Child factory support in RootComponent.child Child content support in RootContent() The Component For demo purposes, we’re just going to add a very simple screen (that we fully intend to throw away later). We could create a screen our app will actually use later, but I don’t want to muddy the details here by introducing our app’s business logic. That said, here’s our dummy component: import com.arkivanov.decompose.ComponentContext class DummyComponent(componentContext: ComponentContext) : ComponentContext by componentContext { fun saySomething() : String { return "I'm another screen!" } } The Content The content is, of course, a @Composable function. Technically, it can reside anywhere you want, but I tend to like Decompose’s example, so we’ll put this in DummyContent.kt: import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @Composable fun dummy( component: DummyComponent, modifier: Modifier = Modifier ) { Column( modifier = modifier .safeContentPadding() .fillMaxSize() ) { Text(text = component.saySomething()) } } NavigationConfig Our new screen doesn’t need any data, so we can simply add a data object: import kotlinx.serialization.Serializable @Serializable sealed interface NavigationConfig { @Serializable data object Home : NavigationConfig @Serializable data object Dummy : NavigationConfig } Child Factory support Now we need to update the child factory function to take in the NavigationConfig and return the associated component: private fun child(config: NavigationConfig, componentContext: ComponentContext): ComponentContext { return when (config) { is NavigationConfig.Home -> GreeterComponent(componentContext) is NavigationConfig.Dummy -> DummyComponent(componentContext) } } Child content support And, finally, we need to tell Compose what to render: Children( stack = component.stack, modifier = modifier.padding(5.dp), animation = stackAnimation(slide()), ) { val childModifier = modifier.fillMaxWidth().padding(10.dp) when (val component = it.instance) { is GreeterComponent -> greeter(component, childModifier) is DummyComponent -> dummy(component, childModifier) } } 2, 4, 6, 8! It’s time for us to navigate! We have all the pieces in place, so now we just need to add a way for the user to cause the app to navigate. To do that, we’re going to add a button to our "home" screen. Let’s start with the content: @Composable fun greeter( component: GreeterComponent, modifier: Modifier = Modifier ) { var showContent by remember { mutableStateOf(false) } Column( modifier = Modifier .safeContentPadding() .fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { Button(onClick = { showContent = !showContent }) { Text("Click me!") } AnimatedVisibility(showContent) { val greeting = remember { component.greet() } // !!! Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { Image(painterResource(Res.drawable.compose_multiplatform), null) Text("Compose: $greeting") } } Button(onClick = { component.dummy() }) { Text("Dummy") } } } Note the Button we added to the bottom of the content. That button will call a function we’ll now add to GreeterComponent: fun dummy() { nav.pushToFront(NavigationConfig.Dummy) } And now we run the app. You should see a gem like this: And if you click on Dummy, you’ll be presented with this gem: It’s super ugly, but it works, and that’s the important part. In the next entry in the series, we’ll start working on our business logic and introducing some data-driven screens. ### [Decompose Navigation and the Root Component](/2025/decompose-navigation-and-the-root-component/) Table of Contents RootComponent RootContent NavigationConfig Build Updates Enable the RootComponent So far, we have an app that runs but has only one "screen". Decompose makes adding more screens — and navigating between them — pretty simple. In this post, we’ll start to see how that’s done. If you remember from our discussion in Compose Multiplatform with Decompose, we had a class called GreeterComponent. We even told Decompose that this was our root component: val rootComponent = GreeterComponent(defaultComponentContext()) That’s certainly valid, but what we want to do is provide another component as our root that will provide for navigation, as well as a "host" for displaying GreeterComponent. If you read the official Decompose docs, it will suggest to you a code organization that I have chosen not to follow: an interface that defines the…​ interface for the component (e.g., FooComponent), a default implementation (DefaultFooComponent), and the content file (FooContent) which holds our composable. The separation of the component into an interface and an implementation is probably a good idea, as it makes swapping out the implementation (e.g., for testing) much simpler. Generally, I agree with that approach, but (and I know this might bite me eventually), I don’t like it much here as it adds a lot of noise. Feel free to use that approach if you like, but for the code here, we’ll just provide a class (FooComponent) and the content (FooContent.kt). RootComponent That said, let’s create our root component. To do that, we will follow some coding conventions from the Decompose docs and call ours RootComponent: import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.router.stack.ChildStack import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.childStack import com.arkivanov.decompose.value.Value import com.steeplesoft.giftbook.ui.drawer.NavigationConfig val nav = StackNavigation<NavigationConfig>() // 1 class RootComponent(componentContext: ComponentContext) : ComponentContext by componentContext { // 2 val stack: Value<ChildStack<*, ComponentContext>> = childStack( source = nav, serializer = NavigationConfig.serializer(), initialConfiguration = NavigationConfig.Home, handleBackButton = true, childFactory = ::child, // 3a ) // 3b private fun child(config: NavigationConfig, componentContext: ComponentContext): ComponentContext { // 4 return when (config) { is NavigationConfig.Home -> GreeterComponent(componentContext) } } } Here’s a quick rundown of what’s happening here: We’re defining a navigation object that we’ll use to navigate from page to page. Yes, it’s global, and, yes, it’s ugly, but it will work for now, and we’ll clean that up later when we introduce dependency injection. The ChildStack here is the heart of Decompose navigation. Using the nav object, we can push "component configurations" onto this stack, and code from 3 and 4 will do the needful. Here, we’re defining a factory that will take the component configurations and return the appropriate component. This configuration/component separation feels a bit noisy like the interface/impl separation discussed above, but I think this makes sense: screens can push a configuration on the stack that’s appropriate for a given user interaction, then, in a single place, the component is created and configured outside the context of any UI or business logic. We’ll see what these configurations look like shortly. The heart of the child function is a when block that converts, so to speak, the configuration to a component. That’s a pretty high-level, but I hope you get the gist. To see the other side of this (and how the nav actually works), let’s look at the @Composable: Remember when I said to create a new class called FooContent then replace its contents? I do that because I’m lazy efficient. If I create a new Kotlin file, I’ll get and empty FooContent.kt, and then I have to manually add the package (to keep our compiled code tidy). If, however, I create a class FooContent, it generates the package statement for me. Not a big deal, but that’s how I roll, in case that helps anyone. :) RootContent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.arkivanov.decompose.extensions.compose.stack.Children import com.arkivanov.decompose.extensions.compose.stack.animation.slide import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation @Composable fun RootContent( component: RootComponent, modifier: Modifier = Modifier ) { Column(modifier = modifier) { Children( stack = component.stack, // 1 modifier = modifier.padding(5.dp), animation = stackAnimation(slide()), ) { val childModifier = modifier.fillMaxWidth().padding(10.dp) when (val component = it.instance) { is GreeterComponent -> greeter(component, childModifier) } } } } Thanks to genius of Compose, when the value of stack changes, the Children component will rerender itself. In the block of code we see (which is a lambda passed to Children), there is a when block that looks at the component returned by RootComponent.child and calls the related Composable function. This component-to-composable mapping must be maintained by hand (i.e., there are no fancy annotations or compiler tricks to do this for us), so, if you’re copying and pasting as you add screens, take some care here. We’re now almost ready to run our application. If you’re playing along in your IDE, you’ll probably see it complaining about NavigationConfig, so let’s fix that. In a nutshell, it’s sealed interface that provides child classes or objects to help us abstract our navigation. Here again, I deviate from the recommended Decompose pattern (because I know better than the framework author, of course. Or something ;). In the docs, you will see a sealed interface called RootComponent.Child that defines classes that wrap the components, etc. I have not found this useful, so I’ve slimmed it down a bit. Again, like the interface discussion above, I may hate myself for it someday, but I did it, and that’s how I’ll present it here. NavigationConfig So, NavigationConfig: import kotlinx.serialization.Serializable @Serializable sealed interface NavigationConfig { @Serializable data class Foo(val bar: String? = null) : NavigationConfig @Serializable data object Home : NavigationConfig } I’ve included two configs, though we only need one at the moment, to show a couple of options. If you need to pass data as you navigate, the first option is the one you want: when you create the config, you pass the data you need, and it can be accessed in the child function. If don’t need to pass data for a given configuration, then a data object is what you need, as a data class requires at least one primary constructor parameter. Build Updates There are a couple more steps we need before we can run our application. First, we need to add the Kotlin serialization plugin to the build. To do that, we need to modify a few files: gradle/libs.version.toml [plugins] kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } build.gradle.kts plugins { alias(libs.plugins.kotlinSerialization) apply false } composeApp/build.gradle.kts plugins { alias(libs.plugins.kotlinSerialization) } Once you refresh the IDE’s view of the Gradle files (why it won’t do that automatically is beyond me), the line serializer = NavigationConfig.serializer() should no longer show an error. Enable the RootComponent The last step is to change the root component we’re passing into our application. In composeApp/src/androidMain/kotlin/com/steeplesoft/giftbook/MainActivity.kt, we need to change our root component declaration to this: val rootComponent = RootComponent(defaultComponentContext()) Likewise, in composeApp/src/iosMain/kotlin/com/steeplesoft/giftbook/MainViewController.kt, we need to make a similar change: val rootComponent = remember { RootComponent(DefaultComponentContext(ApplicationLifecycle())) } And, finally, in composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/App.kt, we need to update the function to take a RootComponent: fun App(component: RootComponent) { MaterialTheme { RootContent(component) } } Now, we can run our application (either Android or iOS) and see…​ nothing new. :) Visually, it’s underwhelming, and I know you want to see more, but this post has gone on long enough, and I’d like to keep these bite-sized as much as possible, so we’ll add a new screen in my next post…​ ### [What's Up with expect/actual?](/2025/what-s-up-with-expect-actual/) In the last post, we saw — and then ignored — a couple of interesting keywords: expect and actual. In this short post, I’ll give what I hope is enough of an explanation to satisfy the mildly curious. To recap, the code in question looks like this: composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/Platform.kt interface Platform { val name: String } expect fun getPlatform(): Platform So…​ what is that? Quoting from the official docs, Expected and actual declarations allow you to access platform-specific APIs from Kotlin Multiplatform modules. You can provide platform-agnostic APIs in the common code. — Kotlin Multiplatform Documentation In a nutshell, this will allow us to declare a function, property, class, interface, enumeration, or annotation in our common source set, and then implement it, using the actual keyword, in a platform-specific source set using APIs for that platform. composeApp/src/androidMain/kotlin/com/steeplesoft/giftbook/Platform.android.kt import android.os.Build class AndroidPlatform : Platform { override val name: String = "Android $\{Build.VERSION.SDK_INT}" } actual fun getPlatform(): Platform = AndroidPlatform() or composeApp/src/iosMain/kotlin/com/steeplesoft/giftbook/Platform.ios.kt import platform.UIKit.UIDevice class IOSPlatform: Platform { override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion } actual fun getPlatform(): Platform = IOSPlatform() This code, straight from the Compose Multiplatform wizard, offers a pretty simple demonstration. Here, we want to display the name of the platform, but how one gets that information will involve different APIs for each of the mobile platforms. It’s like a cross-platform interface declaration. :) Let’s try another, more practical example: logging. Both Android and iOS provide their own logging framework, but we can’t have platform-specific APIs in our shared code, so we can leverage expect and actual to hide those details. Let’s start with the logging API wrapper: composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/logger/AppLogger.kt expect object AppLogger { fun e(message: String, throwable: Throwable? = null) fun d(message: String) fun i(message: String) } Nothing fancy here, just a small interface providing error, debug, and info logging functions. For the Android implementation, we might have something like this: composeApp/src/androidMain/kotlin/com/steeplesoft/giftbook/logger/AppLogger.kt import android.util.Log actual object AppLogger { actual fun e(message: String, throwable: Throwable?) { if (throwable != null) { Log.e(TAG, message, throwable) } else { Log.e(TAG, message) } } actual fun d(message: String) { Log.d(TAG, message) } actual fun i(message: String) { Log.i(TAG, message) } } and for iOS: composeApp/src/iosMain/kotlin/com/steeplesoft/giftbook/logger/AppLogger.kt import platform.Foundation.NSLog actual object AppLogger { actual fun e(message: String, throwable: Throwable?) { if (throwable != null) { NSLog("ERROR: [$TAG] $message. Throwable: $throwable CAUSE $\{throwable.cause}") } else { NSLog("ERROR: [$TAG] $message") } } actual fun d(message: String) { NSLog("DEBUG: [$TAG] $message") } actual fun i(message: String) { NSLog("INFO: [$TAG] $message") } } Clearly, the implementation details are pretty different, but from our shared code, we can simply call AppLogger.d("hello"), and the KMP build process handles the details. Note that the implementations are actual object, so we create a singleton instance of AppLogger that we can simply reference. And that’s it in a nutshell. There’s more to it, of course, but that should do for our purposes here for now. For more information, see the aforementioned docs. ### [Compose Multiplatform with Decompose](/2025/compose-multiplatform-with-decompose/) Table of Contents What is Decompose? Why Decompose? How to use Decompose Build Changes The Pieces GreeterComponent GreeterContent Platform Entry Points Is That It? In this installation in my Mobile App Development series, I’m going to introduce our next architectural layer, Decompose. We’ll look at what it is, why you might want it, and how to get started. What is Decompose? Decompose, other than sporting one heckuva punny name, is "Kotlin Multiplatform library for breaking down your code into lifecycle-aware business logic components (aka BLoC), with routing functionality and pluggable UI (Compose, Android Views, SwiftUI, Kotlin/React, etc.)" It is the brainchild of Arkadii Ivanov, who describes himself as a Senior Android Engineer at X and former Googler. Developed from Ivanov’s experience, it hides/simplifies some the complexities involved in writing Compose applications. Why Decompose? But what does it offer? Quoting straight from its website, Decompose draws clear boundaries between UI and non-UI code, which gives the following benefits: Better separation of concerns Pluggable platform-specific UI (Compose, SwiftUI, Kotlin/React, etc.) Business logic code is testable with pure multiplatform unit tests Proper dependency injection (DI) and inversion of control (IoC) via constructor, including but not limited to type-safe arguments. Shared navigation logic Lifecycle-aware components Components in the back stack are not destroyed, they continue working in background without UI Components and UI state preservation (mostly useful in Android) Instances retaining (aka ViewModels) over configuration changes (mostly useful in Android) That’s a pretty decent overview. If you’re interested in more, please visit the Decompose site. How to use Decompose That’s all great, but how do we use it? Let’s start with some terms. Decompose, as I understand it, at least, relies pretty heavily on the concept of a Component, which wraps your business logic. The UI is handled (in a separate file) in what the Decompose docs typically refer to as *Content. For example, if have a screen that lists users, you might have two files, UserListComponent and UserListContent. This provides a clean separation for business and UI logic, while logically grouping/ordering related files. What might those look like? Let’s convert the standard CMP demo app for a quick and easy example. Build Changes The first step, of course, is adding Decompose to our project. First, we’ll define the dependencies in our library, then modify the Gradle build as needed: gradle/libs.versions.toml [versions] decompose = "3.3.0" essenty = "2.5.0" //... [libraries] decompose = { module = "com.arkivanov.decompose:decompose", version.ref = "decompose" } decompose-extensions = { module = "com.arkivanov.decompose:extensions-compose", version.ref = "decompose" } essenty-lifecycle = { module = "com.arkivanov.essenty:lifecycle", version.ref = "essenty" } essenty-statekeeper = { module = "com.arkivanov.essenty:state-keeper", version.ref = "essenty" } composeApp/build.gradle.kts kotlin { listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.compilations { val main by getting { } } iosTarget.binaries.framework { baseName = "ComposeApp" isStatic = true // Decompose export(libs.decompose) export(libs.decompose.extensions) export(libs.essenty.lifecycle) export(libs.essenty.statekeeper) // Decompose } } sourceSets { commonMain.dependencies { // Decompose implementation(libs.decompose) implementation(libs.decompose.extensions) // Decompose } //... val iosX64Main by getting val iosArm64Main by getting val iosSimulatorArm64Main by getting iosMain.dependencies { // Decompose api(libs.decompose) api(libs.decompose.extensions) api(libs.essenty.lifecycle) api(libs.essenty.statekeeper) // Decompose } } } Those better versed in Gradle build magic might have a better (or at least different) way of handling dependencies, but this works for me. Once you’ve updated your build files, make sure you tell Android Studio to reload the build files. In my experience, it is usually sufficient to click the reload button, but, for some changes, it seems some wires get crossed, requiring me to restart the editor. YMMV. The Pieces GreeterComponent The demo app delivers most of the demo in the App class. This is the entry point into the CMP code from the platform-specific wrappers, which we’ll take another look at later. With our build fixed up, we need to break this apart, so we start by renaming Greeting to GreeterComponent, and modify as follows: class GreeterComponent(componentContext: ComponentContext) : ComponentContext by componentContext { private val platform = getPlatform() fun greet(): String { return "Hello, ${platform.name}!" } } Every Decompose component needs a ComponentContext, which allows the framework to do the things we’re asking of it (lifecycles, etc). The class itself implements ComponentContext, which is an interface with a lot of methods on it, but the by keyword (for those that are curious) tells the compiler that the instance of componentContext will handle the functions declared by the interface, so (if I understand correctly) the compiler generates the delegation code for us, which is kinda cool. :) GreeterContent Next, we need to create the view, which is basically a file with a @Composable function in it. I do, though, like to put functions in a package, so I tell Android Studio to create a new class (GreeterContent in this case), then replace the class definition with this: import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.safeContentPadding import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import giftbook.composeapp.generated.resources.Res import giftbook.composeapp.generated.resources.compose_multiplatform import org.jetbrains.compose.resources.painterResource @Composable fun greeter( component: GreeterComponent, modifier: Modifier = Modifier ) { var showContent by remember { mutableStateOf(false) } Column( modifier = Modifier .safeContentPadding() .fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { Button(onClick = { showContent = !showContent }) { Text("Click me!") } AnimatedVisibility(showContent) { val greeting = remember { component.greet() } // !!! Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { Image(painterResource(Res.drawable.compose_multiplatform), null) Text("Compose: $greeting") } } } } The body of this function is basically the body of the original App function, though we need replace the Greeter construction with a reference to the GreetingComponent instance, component. We still don’t have a runnable application, though, so let’s fix that now. Platform Entry Points While Compose Multiplatform lets us mostly avoid platform-specific concerns, there are obvious exceptions. The most pressing concern, of course, is bootstrapping the application, but there are others, particularly around some hardware interactions, but we won’t discuss those in this series. Probably. To start, let’s look at the Android MainActivity: import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import com.arkivanov.decompose.defaultComponentContext class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) // Always create the root component outside Compose on the main thread val rootComponent = GreeterComponent(defaultComponentContext()) setContent { App(rootComponent) } } } And the iOS MainViewController: import androidx.compose.runtime.remember import androidx.compose.ui.window.ComposeUIViewController import com.arkivanov.decompose.DefaultComponentContext import com.arkivanov.essenty.lifecycle.ApplicationLifecycle fun MainViewController() = ComposeUIViewController { val rootComponent = remember { GreeterComponent(DefaultComponentContext(ApplicationLifecycle())) } App(rootComponent) } You’ve probably noticed the req squiglly on the App() invocations. We need to fix up that function now: fun App(component: GreeterComponent) { AppTheme { greeter(component) } } With those changes in place, you should now be able to run either the ` composeApp` or iosApp configurations and see the changes in action. Visually, you should look identical to the non-Decompose version. Is That It? Yes, that’s it for now. There is, of course, much more to cover, such as that odd expect fun getPlatform(): Platform found in Platform.kt, and there’s the ever important topic of navigation, but that’s enough for this slice. Next, we’ll take a quick look at expect/actual, and then we’ll take a look at how Decompose supports navigation. If you’re brave enough, you can read the documentation and work it out yourself, of course. Until next time…​ ### [Getting Started with Compose Multiplatform](/2025/getting-started-with-compose-multiplatform/) Table of Contents What Is It? Getting Started Running the Android Emulator Running the iOS Emulator In this installation in my Mobile App Development series, we’ll take a look at the most foundational piece of the puzzle, Compose Multiplatform. We’ll see what it is and how to use it. What Is It? Quoting from its homepage, Compose Multiplatform is "[a]n open-source, declarative framework for sharing stunning UIs across multiple platforms." It builds on two technologies: Kotlin Multiplatform, and Jetpack Compose. Quoting from its homepage, Kotlin Multiplatform "is a technology that allows you to create applications for various platforms and efficiently reuse code across them while retaining the benefits of native programming. Your applications will run on iOS, Android, macOS, Windows, Linux, and more." Kotlin Multiplatform (or KMP) encompasses a number of technologies that manage the compilation of (mostly) Kotlin-based code into native builds for a given platform. It also allows for integration with platform-specific code in instances where a lower-level integration is required (think system integration). Jetpack Compose, on the other hand, is "Android’s recommended modern toolkit for building native UI". It replaced Android’s older, XML- and Java-based solution from its earlier days. It provides a lighter, more modern approach to application development that is faster on the device, and easier to maintain. It requires Kotlin, rather than Java, so it’s quite a sea change for seasoned Android developers. Put together, mobile developers can now (mostly) write a single codebase with a single, shared architecture. The resulting source code is compiled to a native application, which will provide a near-native experience (in both user experience and performance) on the intended target. As I understand things, a purely Swift-based application will probably perform slightly better, but only just. With each CMP release, though, performance continues to improve, so I think most developers should be well-served by CMP, given all that it offers. If you’re interested in who is using CMP, you can visit its case studies page. Getting Started Armed with all of that knowledge, how does one get started? Fortunately, the good folks at JetBrains provide two options, The Kotlin Multiplatform IDE plugin for IntelliJ IDEA (or Android Studio), or the KMP Wizard. If you’d like to use the IDE, you can follow the instructions here. To make things simpler, we’ll use the web wizard. Once you open the web wizard, you will be asked for the project name, package, and target platforms. By default, all platforms are checked. What is not checked is the Server option at the bottom. If your application needs a backend and you’d like to write it using JetBrain’s Ktor framework (personally, I’m more of a Quarkus guy), you can check that box. In our case, though, we just want to target Android and iOS, so we can uncheck everything but those two. To make things even simpler, we can switch to the Templates Gallery tab at the top and click Download to get a zip file containing a basic project targeting Android and iOS. The only issue with this approach is that it leaves you updating the project information manually, and that can be trickier than you might expect, so I’d suggest using the wizard. Since we’re going to build an application together, using the wizard, we’ll configure our project like this. Feel free to use your own package name. :) Once you download and extract the zip, open it Android Studio. When you first open the project, you need to be prepared to wait a bit as the IDE imports the project, generates run targets, etc. When it completes, you should see a project layout that looks like this: There’s a lot going on, so I won’t try to cover it all here (we should cover most of it as we walk through the process), but a brief overview of the directories would be prudent: composeApp/src/commonMain: Most of our application’s code will live here. composeApp/src/androidMain: Any Android-specific code lives here composeApp/src/iosMain: Any iOS-specific code lives here composeApp/src/commonTest: Unit/integration tests go here iosApp/iosApp: The iOS wrapper code lives here. Here be dragons, and by that I mean Swift code. 🤪 Running the Android Emulator While it’s not much right now, we actually have a runnable application. To run it, though, we’ll need to create a virtual device. To do that, go to Tools | Device Manager. This will open a panel on the right. At the top, there will be a plus sign. Click that and select Create Virtual Device. Select Phone on the left and the device of your choice on the right, click Next, then Finish. There’s a chance I’m missing some details as I have this already set up, so if it goes haywire, consult the Android Studio documentation. With the device created, we can now run our application using the toolbar at the top: When you click the Run button (the green triangle), after some time, you will see the emulator appear: Running the iOS Emulator If you’re on a Mac, you can run the iOS version of the application. To do so, you must first install XCode (the details of which I’ll skip here. This post is long enough as it is :) and then install the iOS platform: $ xcodebuild -downloadPlatform iOS That will take a while, and you may need to restart Android Studio for it to pick up the target (again, my environment is already set up, so I’m having to guess a bit here). At any rate, Android Studio should now offer these options: Again, clicking the Run button (and waiting a good long while, as the initial iOS build takes a while), we see this: Kinda wild that it looks exactly like the Android version, right? 😛 It doesn’t do much that’s interesting yet, but we do have a working Compose Multiplatform application. In the next installment, we’ll add what will be (for the architecture we’re using), a core library: Decompose. Until next time…​ ### [Mobile App Development Series Introduction](/2025/mobile-app-development-series-introduction/) In recent years, I’ve found myself needing to build a mobile app here or there, and it has been, at times, a bit of a struggle as the landscape — and opinions about it — are wide and varied. There are debates about native, hybrid, and cross-platform approaches, and once you’ve made that decision, you have to wade through a lot of opinions on what library to use. This is especially true for the non-native approaches. What I’d like to do, then, is provide a how-to on the approach I have settled on, with a complete, working application to help someone else get started. What will follow here on my site is a series of posts that will describe how to get started with each architectural piece (that I’ll outline below). In the process of this series, we’ll build a gift-tracking application (if you attended my https://okcjug/org presentation in March of this year, you’ve seen some of this already). Since I’m a sucker for bad puns, we’re going to riff on "Facebook" and call this "GiftBook". The premise is pretty simple: You need to track gifts for multiple people You will want to track multiple gift-giving occasions Each person may have a target quantity or cost for each gift-giving occasion For each person, you will want to track a list of gift ideas Gift ideas used for one occasion will no longer be suggested for other occasions On the home screen, you can select an occasion and see each recipient for that occasion, as well as a progress bar indicating how close to you are to being finished for that recipient And so on. As with just about every project, there will likely be additional features pop up as we proceed, and we’ll either implement those or file them away for a future version. For the architecture, we’ll use the following items: Compose Multiplatform Decompose Android Room Koin KMP Form While we (likely) won’t use these in this application, I also plan to cover Datastore Ktor Coil A final note: I’m a big believer in sharing what you know, even as you’re learning it. There are parts of this application that will change over time as I continue to learn and refine, so you can expect some changes in already-published posts. Or maybe a follow-up. At any rate, if you’re interested in mobile application development and are looking for a place to start, I hope this will be a good one. Let get started. ### [This Blog Now Roqs. I mean... it always has, of course, but now it REALLY does](/2025/this-blog-now-roqs-i-mean-it-always-has-of-course-but-now-it-really-does/) Table of Contents Getting Started The layout/theme Blog Posts Embedding Source Code Site Data Template Extensions Miscellaneous Years ago, I started this blog on WordPress, then moved to awestruct, then to JBake, then to Jekyll. I’ve not done that because I like to change things, though I must admit I’ve enjoyed doing it each time, but because I’m looking for something that best suits my needs. I need to be able to post source code. It would be nice to be able to change theming — especially for source code — globally and easily. A static site would be nice for both performance and security. And as icing on the cake, being able to extend the build tool would be amazing. By chance in the past week or so, I was introduced to a new tool, Roq, which is built in Java, and based on Quarkus. A whole lot of boxes were suddenly checked. Now, less than two weeks later, I’ve converted three sites, including this one. In this post, I’ll walk you through building your own static site that…​ Roqs. :P Roq, of course, has its own documentation, which helped me immensely. However, as all docs go, there were some use cases that weren’t covered as thoroughly as I needed (or I’m slower than I like to think), so I thought I’d add my own voice, as they say, and maybe it will help you (and maybe help beef up the official docs. Andy, Roq’s author, has been super helpful and eager for feedback). Getting Started I’ve been using Roq in anger for less than a week, so I’ve much left to learn. What I’m sharing here is what I’ve learned and how I’ve gotten things to work for me. I can’t guarantee that it’s correct, but it does seem to work. Caveat emptor. :) The easiest way to start is with the Quarkus CLI (I’ll leave it as an exercise for the reader on how to install that). With that tool installed, it’s as simple as this: $ quarkus create app my-blog -x=io.quarkiverse.roq:quarkus-roq ... $ cd my-blog $ quarkus dev And your site is ready to go. As an added bonus, you get Quarkus' live reload for free, so there’s no need to restart or rebuild. In fact, if you wait just a second or two, you’ll see your updates appear in your browser. The layout/theme In converting the three sites that I have, the hardest part for me (poor, simple backend engineer that I am) was the theme. Luckily, I had existing sources for the sites I was converting, so it was a matter of copying the Jekyll/Liquid sources and migrating them to the Qute syntax. This seems like a good time to mention that Roq uses Qute as its templating language. If you’ve used Liquid, Thyme, Freemarker, etc., you should feel right at home with Qute. If and when you need help, you can take a look at the Qute reference. It seems pretty through. I took my Liquid sources, then, and put them where Roq wants them: templates/layouts. Themes are HTML-based, which should be no surprise, but you can still use — indeed must use — Qute markup in. For example, your main layout could be as simple as this: <body> {#insert /} </body> That tag marks the point at which each rendered page will be inserted into your template. Templates can also extend other templates: --- layout: base --- <body> {#insert /} </body> Blog Posts Blog posts are pretty simple. As a post, they make up a Roq collection, over which you can iterate. First, a post, in, say content/post/2025/2025-03-20-blog-post-demo.adoc: --- title: Blog post demo description: Blog post description date: 2052-03-20 author: jlee --- This is a blog post! And to create your site’s index, in content/index.html (yes, you can use Markdown, but why would you? :) : --- title: Home paginate: posts --- {#include partials/pagination.html/} <ul> {#for post in site.collections.posts.paginated(page.paginator)} <li><a href={post.url}</li> {/for} </ul> You’ll obviously want something more appealing, but that’ll get the job done. Embedding Source Code Again, the official docs, plus the Roq blog, cover this, but I’m going to try to condense this here. First up, we need to make sure the dependencies are available: <dependency> <groupId>org.mvnpm</groupId> <artifactId>highlight.js</artifactId> <version>11.11.1</version> <scope>provided</scope> </dependency> Using the transitively-included io.quarkiverse.web-bundler:quarkus-web-bundler, Highlight.js is made available to your site. It does take a bit of extra wiring, though, to put the resources in your template. First, in src/main/resources/web/app, create main.js: import hljs from 'highlight.js'; import 'highlight.js/scss/agate.scss'; hljs.highlightAll(); The scss import is where you’ll select your theme. You can see them all in action here. Finally, in your template, add this to your <head> section: {#bundle /} Site Data While your site may be static, it will likely have some data associated with it. For example, you have a list of authors or speakers, a site menu, or just generic site data such as an associated X or GitHub account. To support this, Roq offers data support in data/foo.yml. The filename, of course, will hopefully have a meaningful, and it will be the means by which you access the data in your page. For example, if you have data/info.yml: x_username: jasondlee github_username: jasondlee in a page or post, you can reference it this way: You can find me on https://x.com/{cdi:info.x_username}[X] or https://github.com/{cdi:info.github_username}[GitHub] Via the markup {cdi:info}, you get a JsonObject you can query, which works fine, but what if you have more complex data, like a collection of speakers (if I may be so bold as to "steal" an example from my local JUG)? - id: jason-lee name: Jason Lee image: speakers/jason-lee.jpg bio: > Jason Lee is a software developer living in the middle of Oklahoma. He has been a professional developer since 1997, using a variety of languages, including Java, Kotlin, Javascript, PHP, Python, Delphi, and even a bit of C#. He currently works for Red Hat on the WildFly/EAP team, where, among other things, he maintains integrations for some MicroProfile specs, OpenTelemetry, Micrometer, Jakarta Faces, and Bean Validation. (<a href="https://jasondl.ee/resume">Resume</a>, <a href="https://www.linkedin.com/in/jasondlee">LinkedIn</a>) He is the president of the Oklahoma City JUG, an occasional speaker there, as well as at a variety of technical conferences, and a <a href="https://amzn.to/2FD2XAo">book author</a>. <p/> On the personal side, he is active in his church, and enjoys bass guitar, running, fishing, and a variety of martial arts. He is also married to a beautiful woman, and has two boys, who, thankfully, look like their mother. Dealing with a single entry as a JsonObject can be tedious, and dealing with the whole collection is much, much worse. Fortunately, Roq allows us to create typesafe means of access. For this example, we would create src/main/java/com/foo/Speakers.java: import java.util.List; import io.quarkiverse.roq.data.runtime.annotations.DataMapping; @DataMapping(value = "speakers", parentArray = true) public record Speakers(List<Speaker> list) { public record Speaker(String id, String name, String bio, String image) {} public Speaker get(String id) { return list.stream().filter(s -> s.id.equals(id)).findFirst() .orElse(new Speaker("", "No speaker", "No Speaker", "logo-notext.png")); } } Now, lets say we have a post about an event that has a speaker: --- title: "2025 March Meeting" date: 2025-02-18 layout: post status: published author: jdlee location: starspace speaker: jason-lee --- and we’d like to look up information about this amazing and engaging speaker: {#let id = post.data("speaker").or("")} {#let speaker = cdi:speakers.get(id) } <div class="row" style="padding: 0 0 1em 0"> <div class="col"> <a class="post-link" href="{post.url}" title="{post.title}" data-toggle="tooltip"> {post.title} </a> </div> </div> <div class="row"> <div class="col"> <b>{post.data('when')}</b> </div> </div> <div class="row"> <div class="col"> {#if speaker} <img src="/img/{speaker.image}" class="speaker-img"/> {/if} </div> </div> First, we can extract the speaker key from the post by {#let id = post.data("speaker").or("")}. Then, using the get() method we defined on our Speakers class, we can get a Speaker: {#let speaker = cdi:speakers.get(id) }. Now, in our template, we can use references like {speaker.image} or {speaker.bio}. An important note, variables defined/assigned in a {#let} directive only exist until the closing {/let}. They’re not defined from the first left until the end of the page, so be aware of that. See here for more details. You can also make more than one assignment in the {#let} block, but I chose not too. Knowing a bit more now, I may revisit that. We’ll see how the mood strikes. :) Template Extensions Another really cool feature is the ability to define template extension functions. If you’re familiar with Kotlin extension functions, you should feel right at home with this. Basically, you create a class annotated with @TemplateExtension, then add public static methods to it. The first parameter specifies the type of variable the method can be applied to. For example, for this blog, I mark the "read more" section using // more, so I have a template function that looks like this: public static String excerpt(String text) { int index = text.indexOf("// more"); return (index == -1) ? text : text.substring(0, index); } Then in my index.html, I can do this: {post.rawContent.excerpt.convert.raw} There’s actually quite a bit going on there, so let me break it down: post.rawContent gets me access to the page source .excerpt gives me the subset of the source I want .convert is another template function that converts the raw page source from Asciidoc to HTML .raw instructs Qute not to escape the HTML markup this expression returns. Without this, there would be a lot of encoded HTML shown and not properly rendered. Is there a smarter, better way to do it? Perhaps, but, again: I’m learing and this is working for now. :) Miscellaneous There’s so much more I could cover in detail, this is already longer than I’d planned, but there’s SEO: {#seo page site /} RSS feeds: {#include fm/rss.html} Sitemaps: {#include fm/sitemap.xml} Easy GitHub Pages deployment and more. If you’ve made it this far, kudos to you, and my apologies. It kinda got away from me. However, there’s so much cool stuff you can do with this (as a bonus, the time it takes for the GitHub Action to publish my updates went from about 6 minutes with Jekyll to just over 1 minute). It’s good stuff all the way down. Now quit reading and go migrate your own site. I don’t think you’ll regret it! ### [A Recap of my night at the Oklahoma City JUG](/2025/a-recap-of-my-night-at-the-oklahoma-city-jug/) Last night, I had the opportunity to present at my local jug, the Oklahoma City Java User Group. My topic was building applications Kotlin/Compose Multiplatform. For the most part, it was awesome. More on that in a moment. The presentation was an introduction to the technologies that I’ve found helpful in building cross-platform applications. I tried to be clear that what I was presenting is my current architecture and that things might change, and that I was learning some of these things as I go. I find it helpful to present on things that I’m learning, as it helps solidify things in my own mind, and it might be useful for others to travel along with me, so to speak. I won’t recap here everything in the presentation, so if you’d like details, you can flip through the slides. The demo app is one I’ve called (because I’m a sucker for puns), "Giftbook" — like "Facebook", but for gifts. The inspiration for the app (which is in part intended to serve as an architectural reference app for my younger son as he builds a mobile app for a high school class, as well as for a project my wife and I are working on together) came from my wife. She typically handles the bulk of our gift shopping, and she uses an app to help keep track of that. The app is great and helpful, but it has shortcomings, and in the course of discussing those, we did what any good geek would do: we decided to build our own. It’s still a work in progress, but you can follow along (and contribute if you want) over at GitHub. I said the meeting was awesome "for the most part" earlier. I had hoped to have a video of the presentation to post the OKC JUG YouTube channel, but…​ there were problems. Since I was presenting, I couldn’t run the recording device, so I conscripted my beautiful and brilliant wife to do handle that, and she did great, but the forces against us were greater. :) A big part of the problem is OBS. I spent part of the morning yesterday making sure everything was set up and working, but when we got to the venue, OBS had forgotten input devices, microphone levels were messed up, etc., so we had to hastily try to reconfigure things moments before the session started. Neither of us know OBS well, and we mostly got it working, but the audio in the video we ended up actually getting was great, then silent, then really low. Not sure what was going on there. The coup de grâce for the recording, though, happened when the laptop died. :P What we didn’t notice was that the power strip was not turned on, so the laptop was running on battery until it wasn’t. We did manage to record about two-thirds of the presentation before things completely fell over, but the audio is next to useless, making the video a bit of a waste. I learned (or had reinforced) a few things, though: I need to learn OBS better (or find a simpler replacement), and I need to conscript more dedicated help. I had a million plates spinning last night, and I wouldn’t have been able to pull of the meeting if it hadn’t been for my amazing wife (I’ve said this directly to her, but I’ll say it again here: A HUGE thanks for the help. You’re awesome. :) Given all of that, there’s a chance I’ll make a recording of the presentation from my office so I can have something to upload. I need to tweak the presentation a bit (including replacing that super dumb and boring title, something my wife and older son have been helping me brainstorm), so if I can find some time, I’ll make those changes and try to put a recording. Despite the technical woes, I had a great time seeing old friends at the JUG, and even got to meet a few new people, which is always great. Having part of my family there was a big bonus, as well. ### [Coil AsyncImage with Authentication](/2025/coil-asyncimage-with-authentication/) I’ve been working on a side project that includes both a backend (Quarkus-based, of course) and a mobile app (I’m using Kotlin Multiplatform, but that’s a topic for another time). In this project, I need to display an image (think profile picture), but the link is secured, meaning I need to authenticate with the server to get it. I couldn’t find anything in the Coil docs explaining directly how to do that, but I was finally able to piece it together, and I’d like to share that here in case it helps someone else. I’m going to forego adding Coil to your project — there are plenty of examples on doing that — and jump right to the example. To start, we’ll show the usage in my composable: @Composable fun ProtectedPhoto(photo: Photo, modifier: Modifier) { AsyncImage( model = photo, placeholder = painterResource(Res.drawable.broken_image), contentDescription = "Image Description", modifier = modifier, contentScale = ContentScale.Crop ) } The only thing of note here is the model we’re passing to AsyncImage. In this case, it’s a model object that encapsulates a protected photo in the system. The real trick is telling Coil how to handle models of this type, and that’s done via a Fetcher: import coil3.ImageLoader import coil3.decode.DataSource import coil3.decode.ImageSource import coil3.fetch.FetchResult import coil3.fetch.Fetcher import coil3.fetch.SourceFetchResult import coil3.request.Options import okio.Buffer import org.koin.core.component.KoinComponent import org.koin.core.component.inject import kotlin.io.encoding.Base64 import kotlin.io.encoding.ExperimentalEncodingApi class CustomImageFetcher( private val data: Photo, private val options: Options ) : Fetcher, KoinComponent { private val repository: CustomRepository by inject() // 1 class Factory : Fetcher.Factory<Photo> { override fun create( data: Photo, options: Options, imageLoader: ImageLoader ): Fetcher { return CustomImageFetcher(data, options) } } @OptIn(ExperimentalEncodingApi::class) override suspend fun fetch(): FetchResult { val photo = repository.getPicture(data.id) // 2 return SourceFetchResult( source = ImageSource( source = Buffer().apply { write(Base64.decode(photo)) }, fileSystem = options.fileSystem ), mimeType = "image/jpg", dataSource = DataSource.DISK ) } } Once this class is registered (see below), Coil will know how to handle AsyncImage instances with a Photo model. When it identifies such a case, it automagically creates the Fetcher via the Fetcher.Factory. An important part of the puzzle here is that part of the job of Fetcher implementations is that they "translate data (e.g. URL, URI, File, etc.) into either an ImageSource or an Image." In the scenario here, the images are stored as a Base64-encoded string. For $REASONS, we’ve opted to decode that into its equivalent binary format in the client (feel free to implement server-side decoding, for example, if that’s better for your use case). To do that, we create an Okio Buffer, decode the string we’ve just received [2], and write the bytes to the array backing the Buffer. We pass that Buffer to the ImageSource constructor, and we’ve fulfilled the Fetcher contract. I am using Koin here [1] to fetch my repository where the network code resides. Your app may require or use some other approach, but this works great here if you’re looking for a solution. The last part remaining is telling Coil about our implementation. If you read the documentation, the Coil team suggests that you register a single ImageLoader for your application, so that’s what we’ll do. In App.kt, we find the composable that serves as the entry point for our application (i.e., where the multiplatform part takes over from the Android Activity or iOS UIViewController that bootstrap the running application): import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import coil3.ImageLoader import coil3.PlatformContext import coil3.compose.setSingletonImageLoaderFactory import coil3.memory.MemoryCache import coil3.request.CachePolicy import coil3.request.crossfade import coil3.util.DebugLogger @Composable fun App() { MaterialTheme { setSingletonImageLoaderFactory { context -> getAsyncImageLoader(context) } // ... } } fun getAsyncImageLoader(context: PlatformContext) = ImageLoader.Builder(context) .components { add(CustomImageFetcher.Factory()) } .memoryCachePolicy(CachePolicy.ENABLED).memoryCache { MemoryCache.Builder() .maxSizePercent(context, 0.3) .strongReferencesEnabled(true).build() } .crossfade(true) .build() In App(), prior to do any actual UI work, we set the ImageLoader factory with a call to getAsyncImageLoader. The relevant part is the call to components(builder: ComponentRegistry.Builder.() → Unit) where we pass a lambda that registers our Fetcher.Factory. At this point you’re all ready to go. Once last fun nugget, though. Note the call to memoryCachePolicy. Coil supports image caching of various kinds to help reduce network traffic. By enabling this here, we can save calls from our mobile to our backend. To see that in action, you can set a breakpoint in the client code that makes that actual network call for the image. The first time a specific image is requested, the breakpoint will trip, obviously. If the app requests that image again (e.g., you navigate away and then back), the image is displayed, but the breakpoint does not trip. That’s pretty cool, but, of course, you have to be aware of the specifics of your use case (e.g., number and size of the images) and choose a caching strategy (or none) as is appropriate. I’m using that in my project, so I thought I’d toss in an extra at the end. :) And that’s it! This took me a bit of digging, but, in the end, it’s a pretty simple and elegant solution. Hopefully this will save someone else some time. Enjoy! ### [Christmas 2024 - Human and Divine](/2024/christmas-2024-human-and-divine/) This year was a very light year in blogging for me — even by my recent standards —  for a lot of reasons that probably aren’t of much interest to others. That said, I want to close the year out as I have for years with a Christmas post. I realize that many of you may not celebrate Christmas, and for others it’s just another holiday plus lights and gifts and family. I would be remiss, though, if I didn’t close the year sharing the real, historical meaning of Christmas: the birth of a baby sent to atone for the sins of the world. There’s a lot of theology there that I won’t unpack here, but, if you’d like to hear more — or try to convince me that I’m wrong :) — I’m here for you. Here’s a beautiful setting from Evan Wickham of some of that theology. I hope it blesses you as it did me. Merry Christmas! Breaking heaven’s silence we heard a human cry Light into our darkness the Savior has arrived Healing all the broken and teaching us to love The Son of heaven’s glory now clothed in flesh and blood Begotten not created from the Father before time Virgin born Messiah both human and divine Crucified and risen forever You will reign We join with all the church from every age Singing worthy is Lamb that was slain ### [Inter-container Communications with Testcontainers](/2024/inter-container-communications-with-testcontainers/) I recently found myself in need of having two different Testcontainers communicate with each other. To someone more familiar with Docker, the solution might have been more obvious, but, alas, I am not that man. :P After asking in the Testcontainer Slack, I got a pointer, so I thought I’d share it here in case it might help someone else. To be specific, I needed to have the OpenTelemetry Collector pushing trace data to Jaeger so that I could more easily test some WildFly changes. (There might be a better way, but this is working for now, and incremental improvement is the name of the game ;). The trick is to create a Network that the two containers will share. Fortunately, Testcontainers has a network defined for use already: Network.SHARED. In my case, I don’t need anything fancy, so I can just use this. If you have more complicated needs, the Javadoc should help you with that. With the Network defined, I just need to configure each container. In this scenario, I need to set up the Jaeger container with both the Network as well as a network alias, or host name, by which the Otel Collector can address it. For example: new JaegerContainer() .withNetwork(Network.SHARED) // <---- This .withNetworkAliases("jaeger"); (See below for the full class) Now, for the collector: new OpenTelemetryCollectorContainer() .withNetwork(Network.SHARED) // <---- This .withCopyToContainer(MountableFile.forClasspathResource( "org/wildfly/test/integration/observability/container/otel-collector-config.yaml"), OpenTelemetryCollectorContainer.OTEL_COLLECTOR_CONFIG_YAML) .withCommand("--config " + OpenTelemetryCollectorContainer.OTEL_COLLECTOR_CONFIG_YAML); (Full class also below) The config file is a classpath resource, the looks something like this: ... exporters: otlp: endpoint: http://jaeger:4317 tls: insecure: true ... Notice in the otlp exporter, I simply refer to the other container by the configured hostname, and the Docker network figures everthing else out. Note also that I don’t have to use the mapped port from the Testcontainer, as connection will use the exposed port configured (4317) inside the Docker network, so there’s no chance of conflicts with the host machine. And, fundamentally, that’s all there is to it. I can now have my WildFly instance push traces to the OpenTelemetryCollectorContainer, which forwards those traces, via OTLP, to the JaegerContainer, and I can view those traces via the Jaeger UI (or the undocumented REST API, which is what I’m actually using in my tests. Sssh…​ Don’t tell anyone :). Hope that helps! JaegerContainer.java import java.util.List; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.WebTarget; import org.junit.Assert; import org.testcontainers.containers.Network; import org.testcontainers.containers.wait.strategy.Wait; import org.wildfly.common.annotation.NotNull; import org.wildfly.test.integration.observability.opentelemetry.jaeger.JaegerResponse; import org.wildfly.test.integration.observability.opentelemetry.jaeger.JaegerTrace; /* * This class is really intended to be called ONLY from OpenTelemetryCollectorContainer. Any test working with * tracing data should be passing through the otel collector and any methods on its Container. */ class JaegerContainer extends BaseContainer<JaegerContainer> { private static JaegerContainer INSTANCE = null; public static final int PORT_JAEGER_QUERY = 16686; public static final int PORT_JAEGER_OTLP = 4317; private String jaegerEndpoint; private JaegerContainer() { super("Jaeger", "jaegertracing/all-in-one", "latest", List.of(PORT_JAEGER_QUERY, PORT_JAEGER_OTLP), List.of(Wait.forHttp("/").forPort(PORT_JAEGER_QUERY))); } @NotNull public static synchronized JaegerContainer getInstance() { if (INSTANCE == null) { INSTANCE = new JaegerContainer() .withNetwork(Network.SHARED) .withNetworkAliases("jaeger") .withEnv("JAEGER_DISABLED", "true"); INSTANCE.start(); } return INSTANCE; } @Override public void start() { super.start(); jaegerEndpoint = "http://localhost:" + getMappedPort(PORT_JAEGER_QUERY); } @Override public synchronized void stop() { INSTANCE = null; super.stop(); } List<JaegerTrace> getTraces(String serviceName) throws InterruptedException { try (Client client = ClientBuilder.newClient()) { waitForDataToAppear(serviceName); String jaegerUrl = jaegerEndpoint + "/api/traces?service=" + serviceName; JaegerResponse jaegerResponse = client.target(jaegerUrl).request().get().readEntity(JaegerResponse.class); return jaegerResponse.getData(); } } private void waitForDataToAppear(String serviceName) { try (Client client = ClientBuilder.newClient()) { String uri = jaegerEndpoint + "/api/services"; WebTarget target = client.target(uri); boolean found = false; int count = 0; while (count < 10) { String response = target.request().get().readEntity(String.class); if (response.contains(serviceName)) { found = true; break; } count++; try { Thread.sleep(500); } catch (InterruptedException e) { // } } Assert.assertTrue("Expected service name not found", found); } } } OpenTelemetryCollectorContainer.java import java.util.Collections; import java.util.List; import org.testcontainers.containers.Network; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.MountableFile; import org.wildfly.common.annotation.NotNull; import org.wildfly.test.integration.observability.opentelemetry.jaeger.JaegerTrace; public class OpenTelemetryCollectorContainer extends BaseContainer<OpenTelemetryCollectorContainer> { private static OpenTelemetryCollectorContainer INSTANCE = null; private static JaegerContainer jaegerContainer; public static final int OTLP_GRPC_PORT = 4317; public static final int OTLP_HTTP_PORT = 4318; public static final int PROMETHEUS_PORT = 49152; public static final int HEALTH_CHECK_PORT = 13133; public static final String OTEL_COLLECTOR_CONFIG_YAML = "/etc/otel-collector-config.yaml"; private String otlpGrpcEndpoint; private String otlpHttpEndpoint; private String prometheusUrl; private OpenTelemetryCollectorContainer() { super("OpenTelemetryCollector", "otel/opentelemetry-collector", "0.93.0", List.of(OTLP_GRPC_PORT, OTLP_HTTP_PORT, HEALTH_CHECK_PORT, PROMETHEUS_PORT), List.of(Wait.forHttp("/").forPort(HEALTH_CHECK_PORT))); } @NotNull public static synchronized OpenTelemetryCollectorContainer getInstance() { if (INSTANCE == null) { jaegerContainer = JaegerContainer.getInstance(); INSTANCE = new OpenTelemetryCollectorContainer() .withNetwork(Network.SHARED) .withCopyToContainer(MountableFile.forClasspathResource( "org/wildfly/test/integration/observability/container/otel-collector-config.yaml"), OpenTelemetryCollectorContainer.OTEL_COLLECTOR_CONFIG_YAML) .withCommand("--config " + OpenTelemetryCollectorContainer.OTEL_COLLECTOR_CONFIG_YAML); INSTANCE.start(); } return INSTANCE; } @Override public void start() { super.start(); otlpGrpcEndpoint = "http://localhost:" + getMappedPort(OTLP_GRPC_PORT); otlpHttpEndpoint = "http://localhost:" + getMappedPort(OTLP_HTTP_PORT); prometheusUrl = "http://localhost:" + getMappedPort(PROMETHEUS_PORT) + "/metrics"; } @Override public synchronized void stop() { if (jaegerContainer != null) { jaegerContainer.stop(); } INSTANCE = null; super.stop(); } public String getOtlpGrpcEndpoint() { return otlpGrpcEndpoint; } public String getOtlpHttpEndpoint() { return otlpHttpEndpoint; } public String getPrometheusUrl() { return prometheusUrl; } public List<JaegerTrace> getTraces(String serviceName) throws InterruptedException { return (jaegerContainer != null ? jaegerContainer.getTraces(serviceName) : Collections.emptyList()); } } ### [Christmas 2023 - I Heard the Bells on Christmas Day](/2023/christmas-2023-i-heard-the-bells-on-christmas-day/) As 2023 comes to a close, I want to take a slightly different approach to my Christmas greetings. I’d like to share with you a Christmas carol, and the story behind it. The poem, written by Henry Wadsworth Longfellow, explores the contrasting despair in his heart against the hope of Christmas. Having lost his wife to a fire, and having his son critically wounded in the Civil War, Longfellow struggled with his faith which spoke of "peace on earth, goodwill to man" while he watched the injustice and violence in the country at war around him. At the end of the poem, written on Christmas day in 1863, he concludes with the confession that, while things seem bleak,“God is not dead, nor doth He sleep; The Wrong shall fail,The Right prevail, With peace on earth, good-will to men.” With wars and violence all over the globe, that statement is still true today. One day two thousand years ago, Jesus became a human, in the form of a tiny infant, as the final step in righting wrongs and prevailing over evil finally and fully. Christmas, then, points to Easter, and should serve as a reminder that, while evil does seem prevalent now, the day is coming when God finally says "Enough!" and declares judgment. My prayer, as it is every Christmas season (and, indeed, every day) is that this year will be the year you see Christmas as more than a chance for time off and getting and receiving gifts, but as the offering of the greatest gift of all: salvation through Jesus Christ. Merry Christmas! ### [Quarkus for Frontend Devs](/2023/quarkus-for-frontend-devs/) A friend of mine is a very good Angular developer. For a project he’s been asked to help with, though, he finds himself needing to do some backend work. Since that’s a bit outside his wheelhouse, he asked me for advice. In this post, I’ll write up what I told him in case it might be of use to someone else. Executive Summary In my opinion, the "best" starting point is this stack: Quarkus for the framework Java for the language Maven for the build Terms to know (to search for help) Jakarta REST (previously known as JAX-RS) Contexts and Dependency Injection (CDI) Java Persistence API (JPA) Hibernate Panache The Framework The first question is, of course, "What do I use?" One of the great strengths of the Java ecosystem is the plethora of options. I gave him four. :) Spring Boot Quarkus Micronaut Helidon Spring Boot is, of course, the dominant option in that last. It has a lot of documentation, examples, community resources, conference sessions/speakers, etc. It’s extremely well-supported. My take on it, though, is that it is heavier — both on disk and in memory — than the other options. Additionally, while benchmarks can be finicky and sometimes misleading, it seems that Spring Boot is also slower at runtime than the others (yes, much of that depends on your workload and a thousand other things, so if your case proves me wrong in this, I’m happy for you. No need to "well akshually" me. I get it. :) Long story short, I suggested Quarkus (Yes, I work at Red Hat, but my use of Quarkus pre-dates my little fedora, so it’s not just company loyalty). On the technical side, it’s small and super easy to get started. At runtime, it has fast startup and excellent performance (yes, again, workloads affect these things). It’s cloud-native, and has native compilation (i.e., Graal VM) baked in. Perhaps most importantly for my friend, I can provide actual help with it. :) The "Stack" The next set of questions were about the technologies used. For this, I started at the build. Build Tool Much like the JavaScript world, Java developers have a variety of options for build tools. The two primary, though, are Gradle and Maven. Both tools are functionally similar, but have a number of significant differences. Trying to avoid going too deep, I summarized the difference this way: Maven The build file is XML-based. Polyglot Maven exists but does not appear to be stable yet It is highly opinionated. Projects, in general, have a very quickly and easily understood structure The XML files tend to be more verbose Gradle The build file is primarily Groovy-based, though Kotlin seems to be gaining prominence. The build file is more of a script, so projects can be very free-form. Understanding project structure and build capabilities takes (IME) more time and reading to fully understand Groovy/Kotlin can be much more terse. Ultimately, the build tool is mostly a personal preference, but my (strong) preference is Maven, which is what I suggested. REST Endpoints Once the framework has been chosen, and we’re created a project, it’s time to write the actual API endpoints. Generally speaking, we use REST for that, which means Jakarta REST, which Quarkus supports out of the box. There are alternatives such as gRPC or GraphQL, but those are a bit more complicated, and, for the project in mind here, overkill. My advice for my friend was to follow the Quarkus guides, which are numerous and thorough. For a quick start on Java REST development with Quarkus, this guide provides a nice, simple example. From the docs: import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @Path("/hello") public class GreetingResource { @GET @Produces(MediaType.TEXT_PLAIN) public String hello() { return "Hello from RESTEasy Reactive"; } } Dependency Injection Java, much like Angular, supports dependency injection (or inversion of control). The most common DI framework, at least in my corner of the world, is CDI. Again, while much can said about the many advanced features of CDI, a simple example should suffice to get one started. import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; @Path("/hello") public class GreetingResource { @Inject GreetingService service; // ... } Data Access For a frontend developer, database access may be a foreign concept, so my advice here is to go as simple as you can until/unless you need something more. Quarkus again offers a nice tool, Panache. Panache builds on top of JPA, providing a number of common database operations without any existing code. For example (taken from the docs), here is an entity using the Active Record pattern: import java.time.LocalDate; import java.util.List; import jakarta.persistence.Entity; import io.quarkus.hibernate.orm.panache.PanacheEntity; @Entity public class Person extends PanacheEntity { public String name; public LocalDate birth; public Status status; public static Person findByName(String name){ return find("name", name).firstResult(); } public static List<Person> findAlive(){ return list("status", Status.Alive); } public static void deleteStefs(){ delete("name", "Stef"); } } This defines an entity, Person which inherits operations such as find, list, and delete. Some people may not like having such operations defined in the entity, so Panache also supports the repository pattern: @Entity public class Person { @Id @GeneratedValue private Long id; private String name; private LocalDate birth; private Status status; // ... } @ApplicationScoped public class PersonRepository implements PanacheRepository<Person> { public Person findByName(String name){ return find("name", name).firstResult(); } public List<Person> findAlive(){ return list("status", Status.Alive); } public void deleteStefs(){ delete("name", "Stef"); } } The same methods available via the Active Record pattern above are now exposed on the PersonRepository class. Which you use is personal preference, but for someone getting started with Java persistence, either approach offers a very easy starting point. Getting Started Finally, there’s how to create a project. This may seem a bit backwards, but as you’ll see, we need to know what technologies we’re going to be using as we’re about to asked for them. Quarkus provides a "Start coding" page that helps you bootstrap a project. On this page, the developer can specify the groupId and artifactId of the project, select a build tool, and a JDK version, as well selecting which Quarkus extensions to use for the project. To build a project that will expose REST endpoints and use Panache to access a MySQL database, we would: Search for "panache" and select "REST resources for Hibernate ORM with Panache" Search for MySQL and select "JDBC Driver - MySQL" Once those have been check, you’re ready to click Generate your application (alt + ⏎) and download the ZIP file. Extract the zip and open the project in the IDE of your choice, and you’re off to the races. Conclusion Obviously, there is much that has been glossed over. The hope, though, is that if you are a JavaScript developer who finds the need to do backend work, this brief guide will give you enough information to get started, and enough knowledge to know how to search when you run into trouble. As always, if you have questions or comments, feel free to find me on Twitter (or whatever it’s called these days) ### [Incorporating preview/experimental features in WildFly](/2023/incorporating-preview-experimental-features-in-wildfly/) One of the toughest challenges facing a mature product like WildFly is adding features without breaking existing users. It’s especially difficult when that project serves as the foundation for a commercial product downstream that requires a higher degree of stability. While WildFly is a wholly independent project, it’s not completely immune to concerns that EAP may have with regard to API stability, long term support, etc. That has made it difficult at times to change WildFly, though efforts like WildFly Preview have certainly helped. With that in mind, I’d like to draw your attention to a project WildFly/EAP engineer extraordinaire, Paul Ferraro recently announced on the wildfly-dev email list. You can click through to the list archive, or read a more nicely-formatted copy of the email below. Either way, we would greatly value any feedback you might provide. This is Paul’s email (and, thus, none of my work and all credit to him) copied, pasted, and slightly reformatted here for convenience. We have long wanted the ability to easily give users opt-in access to less-than-stable features within WildFly. To this end, WildFly currently includes a preview feature pack that facilitates the delivery of preview features to WildFly users. This gives us the ability to include new or alternate versions of modules not included in our default feature pack. However, this mechanism is not well utilized, as evident by the large number of feature proposals sitting the pull request queue, largely because the vast majority of "features" do not naturally arrive via a new module (or different version of an existing module), but rather via changes to existing modules usually residing within the WildFly codebase. For the purpose of this proposal, I am mostly concerned with "features" as defined as new runtime behavior enabled via configuration within a new or existing subsystem. Usually, development of a new feature not only involves the feature code itself, which may be bundled with the wildfly codebase, or via an external component; but also changes to the management model of the corresponding subsystem otherwise required to enable the feature. This might be a new subsystem, but more typically, a new resource within an existing subsystem, or a new attribute of an existing resource, etc. Rather than only being able to control the set of available features via controlling the modules of a given feature pack, it would be more useful, I think, to allow existing modules to enable features by filtering a subsystem’s management model, thus exposing/restricting the configuration needed to enable feature’s runtime behavior. Several months ago, I created https://issues.redhat.com/browse/WFCORE-6221 which proposes to formalize the concept of a "feature stream" within the WildFly kernel. We currently only support the inclusion of stable, well-tested features, which generally requires a new subsystem management model version. Let’s call this the STABLE feature stream, where a "feature stream" is a set of features with specific stability guarantees, e.g. STABLE, PREVIEW, EXPERIMENTAL, etc. By associating incoming features with a non-STABLE "feature stream", e.g. PREVIEW, EXPERIMENTAL, we can more quickly include new features into WildFly, allowing users access to them via a simple opt-in mechanism. This way we can more quickly evolve WildFly while still retaining the same testing standards required for a feature to be deemed STABLE. While we can complicate things later, let’s assume for now that feature streams are a nested hierarchy. i.e. a server configured with the STABLE feature stream will only contain STABLE features, not PREVIEW nor EXPERIMENTAL features a server configured with the PREVIEW feature stream will contain STABLE and PREVIEW features, but not EXPERIMENTAL features. a server configured with the EXPERIMENTAL feature stream will contain all features. WFCORE-6221 proposes that the features exposed by a given subsystem are defined, not just by its management model, but also the feature stream of the server. To achieve this, WFCORE-6221 proposes the following changes to WildFly core: Add the ability to start WildFly with a specific "feature stream" This takes inspiration from JEP 12, which introduced "preview features" to OpenJDK (https://openjdk.org/jeps/12) e.g. ./standalone.sh --feature-stream=experimental ./domain.sh --feature-stream=experimental Add the ability to manipulate management model registration based on the "feature stream" of the server Add support for "feature stream"-specific subsystem XML namespaces A WildFly server instance is assigned a "feature stream" at startup, either via the command line (for the standalone use case), or via its host controller (for the managed domain use case). By default, a server will use the STABLE feature stream. Let’s look at a few different use cases, and explore how each might be handled. Forgive me in advance if all of my examples are clustering-related…​ :) In general, I will show 2 approaches: one using programmatic filtering, and the other using auto-filtering. I expect most users would use the auto-filtering approach. Introducing an experimental feature enabled via a new subsystem e.g. https://issues.redhat.com/browse/WFLY-14953 The module containing the extension for an experimental subsystem needs to be made available within the target feature pack. However, an experimental subsystem simply skips registration if the current feature stream does not support EXPERIMENTAL features. e.g. public class FooExtension implements Extension { @Override public void initialize(ExtensionContext context) { if (context.enables(FeatureStream.EXPERIMENTAL)) { SubsystemRegistration subsystem = context.registerSubsystem("foo", FooSubsystemModel.VERSION_1_0.getVersion()); // ... } } // ... } To promote this feature to the PREVIEW stream, we simply change our logic accordingly: Promotion to the STABLE stream can remove the condition entirely, since context.enables(FeatureStream.STABLE) always return true. However, promotion to STABLE will likely involve incrementing the management model version, so existing processes for stable features will apply. Alternatively, if the subsystem is self-contained within its own extension (as opposed to an existing extension), we can simply associate the extension with a specific feature stream. e.g. public class FooExtension implements Extension { // ... @Override public FeatureStream getFeatureStream() { return FeatureStream.EXPERIMENTAL; } } When the server loads the extension, it will automatically skip initialization of any extensions not enabled by the current feature stream of the server. Introducing an experimental feature enabled via a new resource of an existing subsystem e.g. https://issues.redhat.com/browse/WFLY-16345 Similar to the above, we need to skip registration of the experimental resource definition if the current feature stream does not support EXPERIMENTAL features. If the experimental resource is never registered, it never installs the services required to enable the experimental feature. e.g. @Override public void registerChildren(ManagementResourceRegistration parent) { if (parent.enables(FeatureStream.EXPERIMENTAL)) { parent.registerSubModel(new FooResourceDefinition(...)); } } Alternatively, we can simply associate the ResourceDefinition with a specific feature stream. e.g. class FooResourceDefinition extends SimpleResourceDefinition { // ... @Override public FeatureStream getFeatureStream() { return FeatureStream.EXPERIMENTAL; } } When registering this resource via ManagementResourceRegistration.registerSubModel(new FooResourceDefinition(…​)), the server will omit registration if the feature stream associated with the ResourceDefinition is not enabled by the server. N.B. Care must be taken when using this approach, as the registerSubModel(…​) method will return null if registration was skipped. Introducing an experimental feature enabled via a new attribute of an existing subsystem resource https://issues.redhat.com/browse/WFLY-18000 Similar to the above, we need to skip registration of the experimental attribute if the current feature stream does not support EXPERIMENTAL features.e.g. class FooResourceDefinition extends SimpleResourceDefinition { static final AttributeDefinition BAR = ...; // Our new attribute that enables the new experimental feature // ... @Override public void registerAttributes(ManagementResourceRegistration registration) { if (registration.enables(FeatureStream.EXPERIMENTAL)) { registration.registerReadWriteAttribute(BAR, null, new ReloadRequiredWriteAttributeHandler(FOO); } } } Unfortunately, the current registration mechanism available in wildfly-core, which registers the OperationDefinition parameters of the add operation parameters independently from resource attributes (via different ResourceDefinition.registerXXX(…​) `methods), makes this awkward. Additionally, resource add operation handlers and write-attribute operation handlers are constructed with a separately defined set of parameters (rather than using the parameters of the corresponding `OperationDefinition). For this reason, I submitted https://issues.redhat.com/browse/WFCORE-6407 (WIP https://github.com/wildfly/wildfly-core/pull/5563) which eliminates the need to construct add resource operation handlers or write-attribute operation handlers using a set of attributes. Until that change is in place, most resource definitions for most subsystems (i.e. those not using the registration mechanics from wildfly-clustering-common) will require separate logic to exclude the EXPERIMENTAL attributes from its add operation handler independently from the resource’s attributes. Consequently, until WFCORE-6407 is complete, add operation parameter handling will be very awkward: e.g. class FooResourceDefinition extends SimpleResourceDefinition { static final AttributeDefinition ATTRIBUTE = //... an existing attribute // Our new experimental attribute static final AttributeDefinition BAR = new SimpleAttributeDefinitionBuilder("bar", ModelType.STRING); // N.B. FeatureStream.complete(...) is a convenience method that returns a full map of feature-per stream // e.g. will auto-map FeatureStream.PREVIEW to the FeatureStream.STABLE value // In this way, the addition of a new feature stream will not affect existing usage static final Map<FeatureStream, Collection<AttributeDefinition>> ATTRIBUTES = FeatureStream.complete(Map.of(FeatureStream.STABLE, List.of(ATTRIBUTE), FeatureStream.EXPERIMENTAL, List.of(List.of(ATTRIBUTE, BAR))); // ... public FooResourceDefinition(ManagementResourceRegistration parent) { super(new Parameters(PATH, DESCRIPTION_RESOLVER).setAddHandler(new ReloadRequiredAddStepHandler(ATTRIBUTES.get(parent.getFeatureStream())))); } // ... } W.R.T. runtime, if the experimental attribute is never registered, it will not be allowed within our resource’s add operation, and thus will always resolve to its default value. Alternatively, once WFCORE-6407 is complete, we can associate an AttributeDefinition with a FeatureStream and perform the conditional registration automatically. e.g. static final AttributeDefinition BAR = new SimpleAttributeDefinitionBuilder("bar", ModelType.STRING) .setRequired(false) .setValidator(new EnumValidator<>(EnumSet.allOf(Baz.class)) .setFeatureStream(FeatureStream.EXPERIMENTAL) .build(); The attribute registration methods of ManagementResourceRegistration will omit registration of an attribute its associated feature stream is not enabled by the server. Similarly, the OperationDefinition of the add operation of the containing ResourceDefinition will omit this attribute from its allowed parameters if the feature stream associated with the AttributeDefinition is not enabled by the server. Introducing an experimental feature enabled via a new value of an existing subsystem resource attribute. e.g. https://issues.redhat.com/browse/WFLY-13904 Typically, this would involve adding a new value to an existing enum. Here we need to conditionally register a ParameterValidator specific to the current FeatureStream. As with the previous example, selecting the appropriate validator for a given "feature stream" is also awkward due to the way that resource attributes vs resource add operation parameters are handled. With the existing limitations, a "feature stream"-specific validator can be registered using logic such as: e.g. Using our AttributeDefinition BAR from the above example, which specifies a value enumerated by the enum Baz. Our experimental feature involves a newly added QUX value to our Baz enum. static final Map<FeatureStream, Set<Baz>> BAZ_VALUES = FeatureStream.complete(Map.of(FeatureStream.STABLE, Enum.complementOf(EnumSet.of(Baz.QUX)), FeatureStream.EXPERIMENTAL, EnumSet.allOf(FeatureStream.class))); During attribute registration, we specify the validator specific to the current stream. e.g. @Override public void registerAttributes(ManagementResourceRegistration registration) { ParameterValidator bazValidator = new EnumValidator<>(BAZ_VALUES.get(registration.getFeatureStream())); // Copy attribute and apply correct validator AttributeDefinition attribute = SimpleAttributeDefinitionBuilder.create(BAR).setValidator(bazValidator).build(); registration.registerReadWriteAttribute(attribute, null, new ReloadRequiredWriteAttributeHandler(attribute)); } Not so pleasant…​ Due to the same limitation of the current registration mechanics as described previously, a similar hack will be needed to ensure that the AttributeDefinition provided to the constructor of the add OperationStepHandler has the correct validator applied. Again, this limitation will be addressed via WFCORE-6407. Alternatively, with some minor changes to the ParameterValidator interface, and once WFCORE-6407 is complete, we can associate a ParameterValidator with an AttributeDefinition per feature stream and perform the selection automatically wherever necessary, e.g. via the base OperationStepHandler implementations. I have not completely thought this through, but my current thinking is something like: e.g. static final AttributeDefinition BAR = new SimpleAttributeDefinitionBuilder("bar", ModelType.STRING) .setRequired(false) .setValidator(new FeatureStreamValidator(Map.of(FeatureStream.STABLE, new EnumValidator<>(Enum.complementOf(EnumSet.of(Baz.QUX))), FeatureStream.EXPERIMENTAL, new EnumValidator<>(Enum.allOf(Baz.class))))) .build(); where FeatureStreamValidator is a composite ParameterValidator implementation that delegates to a specific ParameterValidator depending on the feature-stream of the server. Subsystem XML parsing Just as the feature stream is a new dimension to a subsystem’s management model version - so too is the feature stream an optional dimension of a subsystem configuration XML namespace. Say the current version of an existing subsystem uses the XML namespace urn:wildfly:foo:2.1. Implementing a new experimental feature would involve a new XML namespace urn:wildfly:foo:experimental:2.1. If/when this feature is promoted to STABLE, we would need to increment the schema version itself, e.g. urn:wildfly:foo:2.2. If instead, a new stable feature is added, and the experimental feature remains experimental, we would increment the version for both the stable and experimental schemas. e.g. urn:wildfly:foo:2.2, urn:wildfly:foo:experimental:2.2. W.R.T. XML parsing, filtering attributes/resource by stream must be done inline with existing filtering by version. e.g. Consider the following set of subsystem namespaces: public enum FooSubsystemSchema implements PersistentSubsystemSchema<FooSubsystemSchema> { VERSION_1_0(1), VERSION_2_0(2), VERSION_2_0_EXPERIMENTAL(2, FeatureStream.EXPERIMENTAL), // We added a new experimental attribute ; private final VersionedNamespace<IntVersion, ExperimentalSubsystemSchema> namespace; ExperimentalSubsystemSchema(int major) { this(major, FeatureStream.DEFAULT); } ExperimentalSubsystemSchema(int major, FeatureStream stream) { this.namespace = SubsystemSchema.createSubsystemURN(FooSubsystemResourceDefinition.SUBSYSTEM_NAME, new IntVersion(major), stream); } @Override public VersionedNamespace<IntVersion, ExperimentalSubsystemSchema> getNamespace() { return this.namespace; } @Override public PersistentResourceXMLDescription getXMLDescription() { PersistentResourceXMLBuilder builder = builder(FooSubsystemResourceDefinition.PATH, this.namespace); if (this.namespace.since(VERSION_2_0)) { // BAR is new since version 2.0, but only for specific feature streams builder.addAttributes(FooSubsystemResourceDefinition.ATTRIBUTES.stream().filter(this::enables)); } else { // BAR does not exist prior to version 2.0 builder.addAttributes(FooSubsystemResourceDefinition.ATTRIBUTES.stream().filter(Predicates.not(BAR))); } return builder.build(); } } Registering subsystem parsers should generally look the same as it does now, since the server can skip registration of schemas associated with a feature stream not supported by the server. e.g. @Override public void initializeParsers(ExtensionParsingContext context) { // This will skip registration of FooSubsystemSchema.VERSION_2_0_EXPERIMENTAL // if the server does not support it context.setSubsystemXmlMappings(FooSubsystemResourceDefinition.SUBSYSTEM_NAME, EnumSet.allOf(FooSubsystemSchema.class)); } Subsystem extensions will also need to register the appropriate writer based on the feature stream of the server. // The "current" schema will depend on the feature stream of the server static final Map<FeatureStream, FooSubsystemSchema> CURRENT_SCHEMAS = FeatureStream.complete( Map.of(FeatureStream.STABLE, VERSION_2_0, FeatureStream.EXPERIMENTAL, VERSION_2_0_EXPERIMENTAL)); @Override public void initialize(ExtensionContext context) { SubsystemRegistration subsystem = context.registerSubsystem( FooSubsystemResourceDefinition.SUBSYSTEM_NAME, FooSubsystemModel.VERSION_2_0.getVersion()); // ... subsystem.registerXMLElementWriter( new PersistentResourceXMLDescriptionWriter( CURRENT_SCHEMAS.get(context.getFeatureStream()))); } Misc concerns Subsystem model transformers for mixed-domains I anticipate that we would restrict the use of mixed-domains to the STABLE feature stream. That means that only STABLE features need to be concerned with subsystem model transformations. Experimental/preview wildfly kernel features The above mechanisms should work for any features configured by a ResourceDefinition/AttributeDefinition, even if they have no corresponding subsystem Anything else would need to conditionally enable based on the feature stream of the controller That’s about all I have for now. Again, I think this approach should cover the bulk of feature development use cases in WildFly. Let me know if anything was particularly unclear, confusing, or requires elaboration; or if there are any major use cases that I have missed. STATUS: I have a pull request open for WFCORE-6221 [1] that implements most of the above. It is still a work in progress - and needs to be rebased on my WFCORE-6407 branch (once that is complete). Please browse my topic branch [2], and leave any comments on the PR [3]. A good place to start is the integration tests [4], which validates this against a sample subsystem demonstrating several of the above use cases. For any design-related discussion, either reply to this thread or to the WFCORE-6221 jira itself. Paul Ferraro [1] https://issues.redhat.com/browse/WFCORE-6221 [2] https://github.com/pferraro/wildfly-core/tree/ [3] https://github.com/wildfly/wildfly-core/pull/5413 [4] https://github.com/pferraro/wildfly-core/tree/WFCORE-6221/subsystem-test/tests/src/test/java/org/jboss/as/subsystem/test/experimental ### [MyFaces 4 on WildFly](/2023/myfaces-4-on-wildfly/) For several years now, WildFly has supported the ability to install and use different Jakarta Faces (Faces) implementations, either across every application deployed to the server, or for a specific application only. We supported running either Mojarra and MyFaces, with versions running all the way back to 1.2. With the move to Jakarta EE 10, however, that feature was temporarily broken simply because there was not a 4.0-compliant version of MyFaces available by the time we were ready to ship. That has changed now, though, as has the manner in which we support changing the implementations. In this short post, I’ll show you how that works starting in WildFly 29. Before going too far, it’s very important to note that we only support the mechanism by which one can install and use a Faces implementation other than what WildFly ships (as of WildFly 29, that is 4.0.2). That said, if you’re willing to debug any MyFaces-specific issues that may arise, read on. :) There are two major changes to Jakarta Faces support that will come with WildFly 29. The first is really a practical matter: any Faces implementation that is not 4.0-compliant is simply not permitted. This is due to the namespace change that came in Jakarta EE 9/10. Those older libraries are just not binary compatible. The other change, and probably the most important, is that, while the mechanism for changing implementations ships in WildFly, the actual implementation change code and configuration is now shipped in an external feature pack. To explain all of this, you’re about to get a bit of a dive into WildFly internals. I have no hard data on this, but I would imagine the many, if not most, WildFly users install the application server using a downloaded archive. If I’m right, the concept of a feature pack might be unfamiliar to many users. While a full discussion is outside our scope here, a feature is, roughly, …​ a pack that contains a feature. :) It’s an archive that includes code, configuration, etc. and instructions for the tooling on how to install the feature. WildFly itself is actually built using feature packs. We just package up the output of that process in the zip and tar downloads you see on the site. It is possible, however, to build your very own stripped-down server using the same tool we do: Galleon. Again, I won’t dive too deep here, but to build a server that exposes Jakarta REST endpoints, but doesn’t include, say, EJB, you could execute something like this: $ galleon.sh install wildfly:current \ --dir=my-wildfly-server \ --layers=jaxrs-server $ my-wildfly-server/bin/standalone.sh Pretty cool, but why is this important? Well, prior to WildFly 29, in order to install a given feature pack, you had to provision your server using Galleon. Perhaps not a very big deal, but if you have an existing server, then discover a feature pack you’d like to try, you had to provision a new server, migrate configs, etc. Not a lot of fun, though I could be overstating that. Regardless, as of 29, you can now install a given feature pack into an exising WildFly installation. To demonstrate that, we’ll install MyFaces support into an existing provisioning of WildFly 29. To demo this, we’ll use the just released WildFly 29 Beta: $ wget https://github.com/wildfly/wildfly/releases/download/29.0.0.Beta1/wildfly-29.0.0.Beta1.zip $ unzip wildfly-29.0.0.Beta1.zip $ galleon.sh install org.wildfly:wildfly-myfaces-feature-pack:1.0.0-SNAPSHOT \ --dir=wildfly-29.0.0.Beta1 \ --config=standalone.xml \ --layers=myfaces $ grep myfaces wildfly-29.0.0.Beta1/standalone/configuration/standalone.xml <subsystem xmlns="urn:jboss:domain:jsf:1.1" default-jsf-impl-slot="myfaces"/> $ wildfly-29.0.0.Beta1/bin/standalone.sh We can now deploy any Jakarta Faces application, and you should see something like this: [org.apache.myfaces.webapp.FacesInitializerImpl] (ServerService Thread Pool -- 84) MyFaces Core has started, it took [218] ms. And there you have it. A quick introduction to a couple of new changes coming WildFly soon, and a very brief introduction to a very powerful related tool. If you’re a MyFaces user, please try out the feature pack and let us know if you have any issues with the integration! ### [WildFly, Micrometer, and OpenTelemetry](/2023/wildfly-micrometer-and-opentelemetry/) With the release of WildFly 28, we’ve made a few changes to our supported telemetry libraries that are worth noting. In this post, I’ll give a quick overview of those changes. Perhaps the more pressing/disruptive is that we’ve removed support for MicroProfile OpenTracing and MicroProfile Metrics. MP OT itself has been deprecated/replaced by the working group with MicroProfile Telemetry. MP Metrics, though, continues to evolve in ways to which Red Hat objects, so support for that specification has been removed completely. The more interesting changes are the addition (or modification) of two other libraries: Micrometer and OpenTelemetry (both of which I’ve written about before here and here). Both of these new subsystems are disabled by default (to avoid any unwanted potential performance impacts), so I’ll show how to enable them: Micrometer $ jboss-cli.sh -c <<EOF if (outcome != success) of /extension=org.wildfly.extension.micrometer:read-resource /extension=org.wildfly.extension.micrometer:add end-if if (outcome != success) of /subsystem=micrometer:read-resource /subsystem=micrometer:add(endpoint="http://localhost:4318/v1/metrics") reload end-if EOF OpenTelemetry $ jboss-cli.sh -c <<EOF if (outcome != success) of /extension=org.wildfly.extension.opentelemetry:read-resource /extension=org.wildfly.extension.opentelemetry:add() end-if if (outcome != success) of /subsystem=opentelemetry:read-resource /subsystem=opentelemetry:add() reload end-if EOF Both of these scripts will safely add both the extension and then the subsystem only if needed, and reload the server (if needed). Once the server is up, you’re ready to deploy your application using either or both of these libraries. One related technology worth noting is MicroProfile Telemetry. This new spec, which replaced MicroProfile OpenTracing, is enabled by default in the various MicroProfile configurations shipped with WildFly, so all you need to do is start the server with one of thse configurations: standalone.sh -c standalone-microprofile.xml. A very important note, though, is that enabling MicroProfile Telemetry (either by default or explicitly) changes the default behavior of the OpenTelemetry subsystem. The MP Telemetry spec dictates that the OpenTelemetry functionality be disabled unless explicitly enabled. To address that, make sure you add otel.sdk.disabled=false to one of your MicroProfile Config sources. If you want more information on getting started with Micrometer and/or OpenTelemetry with WildFly, keep an eye on the WildFly Quickstarts for updates. ### [WildFly, Arquillian, Testcontainers, and Kafka](/2022/wildfly-arquillian-testcontainers-and-kafka/) Back again with another Testcontainers example. This time, though, the environment is a bit different. We’ll be looking at a Jakarta EE application using WildFly and MicroProfile Reactive Messaging (MP RM), and we’re going to test it using Arquillian and Testcontainers. Let’s get to it. :) The Application To make things simple, we’ll develop a really simple application. It will have one endpoint that takes an entity, then publishes it to a Kafka stream. It’s not a very interesting app, but should be enough for demonstration purposes. While you can see the entire application in the repo, for completeness' sake, let’s show the pieces, starting with the code: MyResource.java @Path("/") @RequestScoped public class MyResource { @Inject private MyService service; @POST public Response create(MyModel model) { return Response.ok(service.sendModel(model)) .build(); } } This just takes a MyModel instance, passes it to the service, the passing along to the client what the service returns. MyService.java @RequestScoped public class MyService { @Inject @Channel("model") Emitter<MyModel> emitter; public MyModel sendModel(MyModel model) { emitter.send(model); return model; } } In the service, we @Inject a MicroProfile Reactive Messaging Emitter, which is annotated with the name of the channel to which MyModel instances will be emitted. With that in hand, we send the model, and return the value. The real magic, if you can call it that, is in MessageService: MessageService.java @Dependent public class MessageService { @Incoming("model") @Outgoing("model-event") public Message<String> sendToKafka(MyModel model) { String data = JsonbBuilder.create().toJson(model); Message<String> m = Message.of(data); // Create Metadata containing the Kafka key OutgoingKafkaRecordMetadata<String> md = OutgoingKafkaRecordMetadata .<String>builder().withKey(model.getId().toString()) .build(); // The returned message will have the metadata added return KafkaMetadataUtil.writeOutgoingKafkaMetadata(m, md); } } Things to note: The method sendToKafka() is annotated with @Incoming("channel"). Thanks to the magic of Reactive Messaging, any time a MyModel is emitted to that channel, this method will be called with that MyModel instance. The method is also annotated with @Outgoing("model-event"). Whatever this method returns will be published to the model-event stream. Notice that we use some Kafka APIs to add some metadata to the object before writing. Now we need to set up the MP RM wiring for Kafka, which we do via MicroProfile Config: META-INF/microprofile-config.properties mp.messaging.connector.smallrye-kafka.bootstrap.servers=localhost:9092 mp.messaging.connector.smallrye-kafka.group.id="watkdemo" mp.messaging.outgoing.model-event.connector=smallrye-kafka mp.messaging.outgoing.model-event.topic=ModelEvent mp.messaging.outgoing.model-event.key.serializer=org.apache.kafka.common.serialization.StringSerializer mp.messaging.outgoing.model-event.value.serializer=org.apache.kafka.common.serialization.StringSerializer In theory, once you start up Kafka and WildFly (as described in the README), you should be able to deploy and test the application: $ mvn package wildfly:deploy $ http -v POST :8080/wildfly-arq-testcontainers-kafka-1.0-SNAPSHOT \ foo=blah bar=49152 POST /wildfly-arq-testcontainers-kafka-1.0-SNAPSHOT HTTP/1.1 Accept: application/json, */*;q=0.5 Accept-Encoding: gzip, deflate, br Connection: keep-alive Content-Length: 31 Content-Type: application/json Host: localhost:8080 User-Agent: HTTPie/3.2.1 { "bar": "49152", "foo": "blah" } HTTP/1.1 200 OK Connection: keep-alive Content-Length: 70 Content-Type: application/json Date: Tue, 23 Aug 2022 21:54:02 GMT { "bar": 49152, "foo": "blah", "id": "f76acba6-08fd-4ff1-a357-c9d23d471154" } Voilà! Now how do we test it? The Test I’ve skipped looking at the Maven POM so far, as it’s pretty run-of-the-mill for the application part, but to get a test set up, we’re going to need peel back the covers on it. Let’s start at the top: pom.xml <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <version.arquillian>1.6.0.Final</version.arquillian> <version.failsafe.plugin>$\{version.surefire.plugin}</version.failsafe.plugin> <version.surefire.plugin>2.22.2</version.surefire.plugin> <version.testcontainers>1.17.3</version.testcontainers> <version.wildfly.maven.plugin>3.0.2.Final</version.wildfly.maven.plugin> <version.wildfly>26.1.1.Final</version.wildfly> <wildfly.dir>$\{project.basedir}/target/wildfly-$\{version.wildfly}</wildfly.dir> </properties> The interesting portion here is the version definitions. Feel free use Java 17 or later if you like. :) The integration test profile First step, let’s set up our integration tests in a profile. This allows us to have normal unit testing as part of the build and save the integration tests for CI or an explicit manual run for faster feedback and build loops: <profiles> <profile> <!-- An optional Arquillian testing profile that executes tests in your JBoss EAP instance. This profile will start a new JBoss EAP instance, and execute the test, shutting it down when done. Run with: mvn clean verify -Parq-managed --> <id>arq-managed</id> <build> <defaultGoal>verify</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>$\{version.failsafe.plugin}</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> <configuration> <systemPropertyVariables> <arquillian.launch>jboss</arquillian.launch> <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> <jboss.home>$\{wildfly.dir}</jboss.home> <kafka.server>$\{kafka.server}</kafka.server> </systemPropertyVariables> <redirectTestOutputToFile>false</redirectTestOutputToFile> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> Here we’re simply configuring the maven-failsafe-plugin, and setting the default goal to verify should this profile be activated (via -Parq-managed on the Maven command line). We’re also setting some system properties, the most notable of which is the Arquillian config we want to launch (arquillian.launch), and the location of the WildFly (jboss.home) and Kafka (kafka.server) servers. We’ll fill in those details shortly. Arquillian Config To configure Arquillian, we need an arquillian.xml config file: src/test/resources/arquillian.xml <?xml version="1.0" encoding="UTF-8"?> <arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd"> <engine> <property name="deploymentExportPath">target/deployments</property> </engine> <container qualifier="jboss" default="true"> <configuration> <property name="allowConnectingToRunningServer">true</property> </configuration> </container> </arquillian> I’m a big fan of holding on the deployment archives that are created for Arquillian testing, so we configure that in the engine section. In order to test on WildFly, we’ll need a WildFly instance. Arquillian supports a few different operating modes for the test server, but we’re interested in managed, which means Arquillian will start and stop the server as needed. The WildFly connector for Arquillian, though, is going to require that it be pointed at a local installation (and not a zip). Downloading and extracting zips via Maven isn’t very pretty (IMO), but, fortunately, the WildFly Maven Plugin lets us build the exact server we want, so let’s do that. The Test WildFly Instance First, we’ll define a version in the pluginManagement section of the build. Declaring this in the main build allows us to use it deploy the application, as well as to provision a test server. <build> <pluginManagement> <plugins> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>$\{version.wildfly.maven.plugin}</version> </plugin> </plugins> </pluginManagement> </build> Next, in our arq-managed profile, we configure a use of the plugin to provision our server: pom.xml <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <executions> <execution> <id>provision-server</id> <phase>pre-integration-test</phase> <goals> <goal>provision</goal> </goals> <configuration> <recordProvisioningState>true</recordProvisioningState> <feature-packs> <feature-pack> <location> org.wildfly:wildfly-cloud-legacy-galleon-pack:$\{version.wildfly} </location> </feature-pack> </feature-packs> <layers> <layer>jaxrs-server</layer> <layer>microprofile-reactive-messaging</layer> <layer>microprofile-reactive-messaging-kafka</layer> </layers> </configuration> </execution> </executions> <configuration> <provisioning-dir>$\{wildfly.dir}</provisioning-dir> </configuration> </plugin> When the plugin executes, it will build a server based on version $\{version.wildfly}, and add support for only JAX-RS and MicroProfile Reactive Messaging with Kafka support (and any needed dependencies). This gives us a thinner, smaller server to work with. This works great for testing, but you can also use this approach (via the Galleon command line utility), to build slimmed down server for production deployments, but that’s a topic for another day. :) The generated server is put in $\{project.basedir}/target via provisioning-dir (and the property defined above) so we can easily clean up after ourselves. Note that we use value to set jboss.home above in the maven-failsafe-pugin configuration so Arquillian can find the server. That’s a lot of steps already, but we’re still not quite ready to write tests yet. We need a Kafka server. The Test Kafka Instance We’re going to use Testcontainers to manage our Kafka instance. If you read my 'Quarkus Dev Services, jOOQ, Flyway, and Testcontainers: A Full Example' post, this approach will be familiar to you. We’ll use the groovy-maven-plugin to create a Testcontainer-based Kafka instance, and pass the relevant information to the test via system properties. pom.xml <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>groovy-maven-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <id>kafka</id> <phase>pre-integration-test</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> def image = org.testcontainers.utility.DockerImageName.parse("confluentinc/cp-kafka").withTag("7.2.1") def kafka = new org.testcontainers.containers.KafkaContainer(image) kafka.start() project.properties.setProperty('kafka.server', kafka.bootstrapServers) </source> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>org.testcontainers</groupId> <artifactId>kafka</artifactId> <version>$\{version.testcontainers}</version> </dependency> </dependencies> </plugin> There’s nothing particularly interesting here if you’re familiar with Testcontainers, but here’s a summary We parse an image name (confluentinc/cp-kafka:7.2.1) We create an instance of KafkaContainer, using that image We start the server We get the bootstrapServers value, and assign that to a build property In the maven-failsafe-plugin config above, we set a system property using this build property As the build finishes and the JVM exits, the container is shut down and cleaned up. It’s really pretty slick. Take a deep breath — and maybe a coffee break — as we’re in the home stretch. It’s actually time to write a test. :) The Test. For Real. Here’s (most of) the test class: MyServiceIT.java @RunWith(Arquillian.class) public class MyServiceIT { @ArquillianResource private URL url; @Deployment public static Archive getDeployment() throws IOException { String config = Files.readString(Path.of("src/main/resources/META-INF/microprofile-config.properties")); config = config.replaceAll("localhost:9092", System.getProperty("kafka.server")); return ShrinkWrap.create(WebArchive.class, "test.war") .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml") // Warning: This breaks in EE 10 .addAsResource(new StringAsset(config), "META-INF/microprofile-config.properties") .addPackages(true, MyService.class.getPackage().getName()); } @Test @RunAsClient public void sendMessage() throws Exception { int count = 0; boolean found = false; sendRestRequest(); KafkaConsumer<String, String> consumer = getConsumer(); consumer.subscribe(Collections.singleton("ModelEvent")); while (!found && count < 10) { consumer.seekToBeginning(consumer.assignment()); ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); count++; for (ConsumerRecord<String, String> r : records) { found = true; System.out.println("***** Message received: " + r.value()); } } assertTrue("Message not found in stream", found); } } I don’t want to spend too much time on Arquillian specifics, so we’ll move fast here: We annotate the class with @RunWith(Arquillian.class) to make this an Arquillian test. This class will be wrapped up and deployed to the server, so we can @Inject the class we want to test (MyService) We do, though, need to define what to deploy, so we have an @Deployment. To make things simpler, I’m simply adding everything under the package com.steeplesoft.watkdemo I’m also reading the MP Config file and changing the value for the Kafka server to point to our test containers. There are probably smarter ways of doing this, but they eluded me long enough that I went with the sledgehammer. :P The test is where things get interesting. We’re going to do an end-to-end test (thus "integration test"), from REST request to Kafka stream, so we make this test as @RunAsClient. In it, send the REST request (see below), then we connect to our test Kafka server and poll it until either we find our message, or we time out. I’m not a Kafka expert, so please be kind. :) If you know a better way to do this, then please feel free. You can also find me and clue me in. :P To send the request, we have this method, using Java 11’s HttpClient: private void sendRestRequest() throws Exception { HttpRequest request = HttpRequest.newBuilder(url.toURI()) .header("Accept", MediaType.APPLICATION_JSON) .header("Content-type", MediaType.APPLICATION_JSON) .POST(HttpRequest.BodyPublishers.ofString( new ObjectMapper().writeValueAsString(new MyModel("foo", 49152)))) .build(); HttpResponse<String> response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(response.statusCode(), 200); } We should have all the pieces in place, so let’s run the test. You should see something like this: $ mvn -Parq-managed verify ... [INFO] Checking the system... [INFO] ✔︎ Docker server version should be at least 1.6.0 [INFO] Creating container for image: confluentinc/cp-kafka:7.2.1 [INFO] Creating container for image: testcontainers/ryuk:0.3.3 [INFO] Container testcontainers/ryuk:0.3.3 is starting: 41c8a0373fe07619232a748df3e39d2ef40425b43bc203f3188a5b24260c3113 [INFO] Container testcontainers/ryuk:0.3.3 started in PT0.414602S [INFO] Container confluentinc/cp-kafka:7.2.1 is starting: 5ec0656459ece52dbf69e9cb99f0f7c8cfabc81686fbed8036c25500289da31b [INFO] Container confluentinc/cp-kafka:7.2.1 started in PT4.465336S ... INFO] Running com.steeplesoft.watkdemo.MyServiceIT Aug 24, 2022 12:49:20 PM org.jboss.threads.Version <clinit> INFO: JBoss Threads version 2.3.0.Beta2 Aug 24, 2022 12:49:20 PM org.jboss.as.arquillian.container.CommonManagedDeployableContainer startInternal ... 12:49:23,413 INFO [org.jboss.as.server.deployment] (MSC service thread 1-2) WFLYSRV0027: Starting deployment of "test.war" (runtime-name: "test.war") 12:49:23,830 INFO [org.jboss.weld.deployer] (MSC service thread 1-4) WFLYWELD0003: Processing weld deployment test.war ... 12:49:26,073 INFO [org.apache.kafka.clients.Metadata] (kafka-producer-network-thread | kafka-producer-model-event) [Producer clientId=kafka-producer-model-event] Resetting the last seen epoch of partition ModelEvent-0 to 0 since the associated topicId changed from null to oOHfjaIyR-S-gvivnsnGYg ***** Message received: {"bar":49152,"foo":"foo","id":"2b66b9c4-3de5-40a4-91b6-e7b511f5233b"} 12:49:26,866 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 15) WFLYUT0022: Unregistered web context: '/test' from server 'default-server' 12:49:26,871 INFO [org.apache.kafka.clients.producer.KafkaProducer] (smallrye-kafka-producer-thread-0) [Producer clientId=kafka-producer-model-event] Closing the Kafka producer with timeoutMillis = 10000 ms. ... [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 6.426 s - in com.steeplesoft.watkdemo.MyServiceIT In that brief log excerpt, we can see The test container spinning up WildFly starting The output from our test when we find the message And the most important part: Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 We’re Done! While the application under test is pretty simple, hopefully this example will give you enough to test your application if you have a similar architectural stack. If you have questions, comments, concerns, etc., you can find me on Twitter. :) ### [Quarkus Dev Services, jOOQ, Flyway, and Testcontainers: A Full Example](/2022/quarkus-dev-services-jooq-flyway-and-testcontainers-a-full-example/) I have written a few posts about using Quarkus with Testcontainers, Flyway, and jOOQ. Since posting those, I’ve learned some new tricks that have changed how I integrate the various tools. In this post, I’d like to share a complete example that shows how use Quarkus, Quarkus Dev Services, Testcontainers, and Flyway together for a zero (ish) local config setup. Introduction To state things more clearly, the project developed here will have the following features: No need for a locally-installed database A Flyway-managed database schema Maven-driven jOOQ code generation A database instance using Quarkus Dev Services for use when running the Quarkus app in dev and test mode Testcontainers-based testing Buckle up. This is going to be a long one. :) Basic Project Setup Let’s start with the Maven setup. I won’t show the entire pom here. For that, please see the GitHub repo. We’ll start by setting up dependencyManagement to make handling Quarkus dependencies easier: <properties> <version.build-helper>3.2.0</version.build-helper> <version.compiler-plugin>3.8.1</version.compiler-plugin> <version.flyway>8.4.1</version.flyway> <version.jooq>3.16.6</version.jooq> <version.junit-jupiter>5.8.2</version.junit-jupiter> <version.pgsql-jdbc>42.3.3</version.pgsql-jdbc> <version.quarkus>2.8.1.Final</version.quarkus> <version.rest-assured>5.0.1</version.rest-assured> <version.surefire>2.22.2</version.surefire> <version.testcontainers>1.17.1</version.testcontainers> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-bom</artifactId> <version>$\{version.quarkus}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Next, let’s add the dependencies for the various tools we’ll be using: <dependencies> <!-- Quarkus --> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-flyway</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-agroal</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-jdbc-postgresql</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-arc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <!-- Quarkus --> <!-- jOOQ --> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>$\{version.jooq}</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-meta</artifactId> <version>$\{version.jooq}</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-codegen</artifactId> <version>$\{version.jooq}</version> </dependency> <!-- jOOQ --> <!-- JUnit --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>$\{version.junit-jupiter}</version> <scope>test</scope> </dependency> <!-- RestAssured --> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>$\{version.rest-assured}</version> <scope>test</scope> </dependency> <!-- RestAssured --> </dependencies> There will be more changes, but we’ll add those in the following sections. Flyway Setup Flyway, as you may already know, is a tool that we can use to manage database changes more easily. What we will do then, is set up our project to use Flyway to manage our database for both production and test usage. We’ll start by setting up the input files. We’ll put those in src/main/resources/db/migration (as required by the quarkus-flyway extension), starting with the base schema file, V0001_schema.sql: CREATE TABLE authors ( id INT PRIMARY KEY, last_name TEXT, first_name TEXT ); CREATE TABLE books ( id INT PRIMARY KEY, title TEXT, description TEXT, published_year INT, author_id INT NULL REFERENCES authors (id) ); When Flyway runs, it will check the database to see if this file has already been processed. It does so by checking a metadata table it creates for just this purpose. If the database is persistent (as it would be in production), this file will be skipped. We’ll see, though, that our database will be ephemeral, so it will always be run. That, though, is simply a 'feature' of this demo. :) I also like to have a file that loads dummy data so that I have something to test with, as well as to work with in dev mode while I’m working on the application (which I move/remove when getting ready for production, of course). To do that, I use a repeatable migration. Our example here is src/main/resources/db/migration/R__dummy_data.sql: DELETE FROM books; DELETE FROM authors; INSERT INTO authors (id, last_name, first_name) VALUES (1, 'Tolkien', 'J.R.R.'), (2, 'Lewis', 'C.S'), (3, 'Sanderson', 'Brandon'), (4, 'Tom', 'Clancy'); INSERT INTO books (id, title, description, published_year, author_id) VALUES -- Source: https://www.tolkiensociety.org/actorModel/books-by-tolkien/ (1, 'Sir Gawain & The Green Knight', 'A modern translation of the Middle English romance from the stories of King Arthur.', 1925, 1), (2, 'The Hobbit: or There and Back Again', 'The bedtime story for his children famously begun on the blank page of an exam script that tells the tale of Bilbo Baggins and the dwarves in their quest to take back the Lonely Mountain from Smaug the dragon.', 1937, 1), -- ... ; It is our responsibility to make sure that repeatable migrations can, indeed, be repeated, so we delete everything from our two example tables. That’s overkill for our demo, but I find it a good general practice. Now we need to wire Flyway into our application. Fortunately, Quarkus has built-in support for this, so we simply need to add a property to enable it. We add this in src/main/resources/application.properties: quarkus.flyway.migrate-at-start=true Quarkus will use the defined datasource for running Flyway, which we’ll configure now. Quarkus Dev Services Quoting from the documentation, "Quarkus supports the automatic provisioning of unconfigured services in development and test mode." Specifically, we’re interested in the database at this point. Quoting again from the docs, "The database Dev Services will be enabled when a reactive or JDBC datasource extension is present in the application, and the database URL has not been configured.". So to enable Dev Services, we need to not configure a datasource, but we still need a datasource in production. Fortunately, Quarkus has us covered there as well. We can qualify our configuration properties for various modes. That leads us to a configuration that might look like this: quarkus.datasource.db-kind=postgresql quarkus.datasource.devservices.port=54321 %prod.quarkus.datasource.jdbc.url=$\{DATABASE_URL:jdbc:postgresql://localhost:5432/fullexample} %prod.quarkus.datasource.username=$\{DATABASE_USER:steeplesoft} %prod.quarkus.datasource.password=$\{DATABASE_PASS:steeplesoft} We need to tell Quarkus what kind of database we want, so we set quarkus.datasource.db-kind. We also don’t want to conflict with any possibly running PostgreSQL instance on a given machine, so we set the port to something less likely to conflict. It would be nice to be able to randomize this, but I’m not sure how. If you do, hit me up on Twitter. :) The second set of properties are prefixed with %prod. When running in dev or test mode, these properties will be ignored, but will be applied (minus the prefix) when the application is run in production. The magic here is somewhat implicit. When we start the app with mvn quarkus:dev, since we have the quarkus-agroal extension included in our build, Quarkus will start up a PostgreSQL instance, as well as setting up a DataSource, ready for injection. Or use with Flyway. When we start the server in dev mode, we should see entries like the following from standard out: [io.qua.dat.dep.dev.DevServicesDatasourceProcessor] (build-30) Dev Services for the default datasource (postgresql) started. [org.fly.cor.int.lic.VersionPrinter] (Quarkus Main Thread) Flyway Community Edition 8.5.8 by Redgate [org.fly.cor.int.lic.VersionPrinter] (Quarkus Main Thread) See what's new here: https://flywaydb.org/documentation/learnmore/releaseNotes#8.5.8 [org.fly.cor.int.lic.VersionPrinter] (Quarkus Main Thread) [org.fly.cor.int.dat.bas.BaseDatabaseType] (Quarkus Main Thread) Database: jdbc:postgresql://localhost:54321/default (PostgreSQL 14.2) [org.fly.cor.int.sch.JdbcTableSchemaHistory] (Quarkus Main Thread) Creating Schema History table "public"."flyway_schema_history" ... [org.fly.cor.int.com.DbMigrate] (Quarkus Main Thread) Current version of schema "public": << Empty Schema >> [org.fly.cor.int.com.DbMigrate] (Quarkus Main Thread) Migrating schema "public" to version "0001 - schema" [org.fly.cor.int.com.DbMigrate] (Quarkus Main Thread) Migrating schema "public" with repeatable migration "dummy data" [org.fly.cor.int.com.DbMigrate] (Quarkus Main Thread) Successfully applied 2 migrations to schema "public", now at version v0001 (execution time 00:00.091s) Of course, the app doesn’t do anything yet, as we haven’t created any REST endpoints, but it does run, and we do have a database, which is pretty cool. Let’s take a look now at how we can integrate jOOQ so we can more easily access this database. jOOQ Setup jOOQ, among other things, will allow us to write type-safe queries. For certain use cases, it’s a great alternative to (or supplement for!) things like JPA. To get started, we need to integrate the code generation tool into our build. We’re going to do this in a way that only generates the code only if it’s missing, and we’ll add the generated output to source control to make things faster in CI and other developers machines. Let’s start with the build. Let’s define some properties, and the profile for the code gen: <properties> <jooq.outputdir>src/main/jooq</jooq.outputdir> </properties> <profiles> <profile> <id>codegen</id> <activation> <file> <missing>$\{jooq.outputdir}</missing> </file> </activation> <build> <plugins> <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>groovy-maven-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <id>startdb</id> <phase>generate-sources</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> db = new org.testcontainers.containers.PostgreSQLContainer("postgres:latest") .withUsername("$\{flyway.user}") .withDatabaseName("$\{flyway.user}") .withPassword("$\{flyway.password}") db.start() project.properties.setProperty('flyway.url', db.getJdbcUrl()) </source> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>$\{version.testcontainers}</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.flywaydb</groupId> <artifactId>flyway-maven-plugin</artifactId> <version>$\{version.flyway}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>migrate</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>$\{version.pgsql-jdbc}</version> </dependency> </dependencies> <configuration> <locations> <location>filesystem:src/main/resources/db/migration</location> </locations> </configuration> </plugin> <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <version>$\{version.jooq}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <jdbc> <url>$\{flyway.url}</url> <user>$\{flyway.user}</user> <password>$\{flyway.password}</password> <schema>public</schema> </jdbc> <generator> <database> <name>org.jooq.meta.postgres.PostgresDatabase</name> <includes>.*</includes> <inputSchema>public</inputSchema> <outputSchema>public</outputSchema> </database> <target> <packageName>com.steeplesoft.fullexample.jooq</packageName> <directory>$\{jooq.outputdir}</directory> </target> </generator> </configuration> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>$\{version.pgsql-jdbc}</version> </dependency> </dependencies> </plugin> </plugins> </build> </profile> </profiles> If you want more details on what all’s going on here, take a moment to (re)visit my post detailing it here. In short, though: Using the Testcontainers API, we start a containerized database and grab the resulting URL Using the Flyway Maven plugin, we run our migrations using the files defined above against this database Finally, we point the jOOQ codegen Maven plugin at this newly populated database to generate the artifacts we’re after. There is one more step: telling Maven where to find the generated classes so we can use them. To do that, we’ll use the build-helper-maven-plugin: <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>$\{version.build-helper}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>$\{jooq.outputdir}</source> </sources> </configuration> </execution> </executions> </plugin> </plugins> Now Maven, as well as any IDE that bases its project information on the Maven POM, will be able to see these classes. We can git add src/main/jooq to add these to git, and, when there are changes to the schema, we simply execute something like this: $ rm -rf src/main/jooq $ mvn generate-sources $ git add src/main/jooq That’s probably a bit heavy-handed, but it should work. :) If you have a more elegant solution, again, find me on Twitter. :) Writing the first endpoint We now have a database instance started for us, we have the schema being created and dummy data add automatically, and we have the jOOQ classes we need to more safely access the data, so let’s write a very simple endpoint to show off our hard work. First, we need the DSLContext, so let’s create a CDI Producer: public final class DslContextProducer { @Inject protected DataSource dataSource; @Produces @RequestScoped public DSLContext getDslContext() { try { return DSL.using(getConfiguration()); } catch (Exception e) { throw new RuntimeException(e); } } private Configuration getConfiguration() { return new DefaultConfiguration() .set(dataSource) .set(new Settings() .withExecuteLogging(true) .withRenderFormatted(true) .withRenderCatalog(false) .withRenderSchema(false) .withMaxRows(Integer.MAX_VALUE) .withRenderQuotedNames(RenderQuotedNames.EXPLICIT_DEFAULT_UNQUOTED) .withRenderNameCase(RenderNameCase.LOWER_IF_UNQUOTED) ); }} This is a pretty simple CDI producer: We’re injecting the DataSource that Quarkus provides us. It will either be one for the Dev Services database in dev or test mode, or the "real" one in production mode. We pass that DataSource to jOOQ via the Configuration object. Bob’s your uncle. The REST endpoint could look like this: import static com.steeplesoft.fullexample.jooq.tables.Authors.AUTHORS; import java.util.List; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import org.jooq.DSLContext; @Path("/authors") public class AuthorsResource { @Inject DSLContext context; @GET public List<AuthorDTO> getAuthors() { return context.select() .from(AUTHORS) .fetchInto(AuthorDTO.class); } } Note that it’s generally not a good idea to access the database in the REST layer, but I’ve done so here to keep things simple, and the usage of jOOQ here is very simple as well, so I won’t spend too much time on it. With this overly simple REST endpoint in place, we’ve demonstrated Quarkus Dev Services, Flyway, and jOOQ. Let’s finish with testing this with Testcontainers. Testing with Testcontainers In a previous post, I discussed setting up a test using Testcontainers, but I did so using Kotlin. In another post, I did the same thing, but I booted the database from Maven using the groovy-maven-plugin. While those work, there’s an even better way: let Quarkus do it for us. Way back up the page a bit, we saw how the quarkus-agroal extension will create a containerized database instance for when run in dev and test mode. As it turns out, we’re running in test mode here, so Quarkus will create and start the database for us and create the DataSource for us. This is injected normally as it was above, with no changes to the classes under test. All we have to do, then, is write the test. import static io.restassured.RestAssured.when; import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; import org.junit.jupiter.api.Test; @QuarkusTest @TestHTTPEndpoint(AuthorsResource.class) public class AuthorsResourceTest { @Test public void testEndpoint() { when().get("/") .then() .log() .body() .statusCode(200); } } This is, admittedly, kind of a dumb test, but it does demonstrate the use the Quarkus test framework, which handles starting and stopping the server for us, allowing us to easily write unit tests against it. The test is full @Inject-able as well. If we wanted to inject the DataSource or the DSLContext, we would simply add the injection point like we would in production code: @Inject DSLContext context; @Test public void testContextInjection() { Assertions.assertNotNull(context); } Note that it does take a while for the tests to start running. That’s because Dev Services is spinning up the database instance, which is not a cheap operation. The start of our application is quite quick, however, once the DB is ready. It’s also worth noting that, in our tests, we’re not actually interacting with Testcontainers directly. Quarkus is doing that on our behalf. If you edit the logging configuration to allow it, you’ll see output like this: [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.steeplesoft.fullexample.AuthorsResourceTest [org.jbo.threads] (main) JBoss Threads version 3.4.2.Final [org.tes.doc.DockerClientProviderStrategy] (build-30) Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first [com.git.doc.zer.sha.org.apa.hc.cli.htt.imp.cla.HttpRequestRetryExec] (ducttape-0) Recoverable I/O exception (java.io.IOException) caught when processing request to {}->unix://localhost:2375 The only place we use Testcontainers directly is in our Flyway/codegen configuration above, but it’s still there, and it’s still awesome. :) Conclusion In this project, we show a complete — if simple — integration of several important technologies which will allow use to write REST endpoints quickly and easily, and we need to worry (too much) about the local environment, whether it’s our machine, a coworkers, or even, say, a GitHub Action. If the machine has Java and Maven installed (and git and docker, of course), it’s simply a matter of cloning the project and issuing mvn clean install to build, test, and package the application. In case you missed the link above, you can find this complete example here. Hopefully, you’ll find this helpful. If you have problems, or suggestions on how to prove it, find me on Twitter and let’s talk. ### [Exporting Arquillian Archives](/2022/exporting-arquillian-archives/) A big part of the testing we do on WildFly involves in-container testing, for which we use Arquillian. It’s a great tool when it works right, but sometimes things don’t. When that happens, I find it helpful to examine the archives that the tests produce. Fortunately, Arquillian makes that easy if you know that magic words, and they’re not easy to find, so I’m going to fix that here. :P There are actually (at least) two ways to it, programmatic (thanks to James Perkins for this tidbit!) or declarative (in arquillian.xml): Programmatic war.as(ZipExporter.class) .exportTo(new File("target/deployments", war.getName()), true); Declarative <engine> <property name="deploymentExportPath">target/deployments</property> </engine> Now, when you run your tests, you’ll find something like target/deployments/_DEFAULT___DEFAULT__my-test-archive.war (the name will vary, of course, based on your test’s configuration). I hope that helps someone. It will definitely help me when I can’t remember how to do this next time. :) ### [Testing with Quarkus, jOOQ, and Testcontainers Redux](/2022/testing-with-quarkus-jooq-and-testcontainers-redux/) In a recent post, I showed how one could fairly easily test your Quarkus application against a Testcontainers-managed Postgres database. While that works great, my set up is a little more complex, and I found the solution lacking. In a nutshell, as part of my build, I use Flyway with H2 to create a schema, then jOOQ’s code generation against H2 to create the needed classes. That all worked well enough until I found some types that didn’t quite map correctly against newer versions of H2 (a security issue necessitated the update), so I decided I should finally make use of the same database from start to finish. In this post, I’ll show how I did it. Technically, one could easily make use of Testcontainer’s JDBC URL approach for starting the container. I could simply specify, say, jdbc:tc:postgresql:14:///testdb and let the container be started and ended automatically, and indeed that works. Sort of. If I specify that as flyway.url, the container is started and the migrations are run. If I then pass that to jOOQ’s codegen, the container is started and…​ nothing is generated, as the schema went away when the container shut down after the flyway step. I can, of course, make sure that the container stays running, but that leaves the problem of my tests starting another container and running migrations again. I want a single instance against which migrations are run, code is generated, and tests are run. To do that, we need to start the container manually, and to do that, we turn to groovy-maven-plugin: <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>groovy-maven-plugin</artifactId> <version>2.1.1</version> <executions> <execution> <id>startdb</id> <phase>generate-sources</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> db = new org.testcontainers.containers.PostgreSQLContainer("postgres:14") .withUsername("$\{flyway.user}") .withDatabaseName("$\{flyway.user}") .withPassword("$\{flyway.password}") db.start() project.properties.setProperty('flyway.url', db.getJdbcUrl()) </source> </configuration> </execution> </executions> <dependencies> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>$\{version.testcontainers}</version> </dependency> </dependencies> </plugin> The script is pretty simple: We create a new instance of PostgresqlContainer, passing the username, and password configured in the properties section above (not shown). The database name doesn’t matter much, so we’re just reusing the username. We start the instance, which causes all the Docker lifecycle events to happen. Finally, we get the JDBC url from the now-running instance and store that in the flyway.url property that the next step will need. Note that we place this first in the order for generate-sources lifecycle phase to make it runs before the migration and code generation steps. Next we want to set up the migration step, which is pretty straightforward: <plugin> <groupId>org.flywaydb</groupId> <artifactId>flyway-maven-plugin</artifactId> <version>$\{version.flyway}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>migrate</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>$\{version.pgsql-jdbc}</version> </dependency> </dependencies> <configuration> <locations> <location>filesystem:src/main/resources/db/migration</location> </locations> </configuration> </plugin> Since we’re using project properties, the url, username, and password do not need to be explicitly configured. All we need to do is provide the correct dependencies for the plugin and tell it where to find the migration scripts. Finally, we get to the code generation: <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <version>$\{version.jooq}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <jdbc> <url>$\{flyway.url}</url> <user>$\{flyway.user}</user> <password>$\{flyway.password}</password> <schema>public</schema> </jdbc> <generator> <database> <name>org.jooq.meta.postgres.PostgresDatabase</name> <includes>.*</includes> <inputSchema>public</inputSchema> <outputSchema>public</outputSchema> </database> <target> <packageName>com.foo.models.jooq</packageName> <directory>$\{jooq.outputdir}</directory> </target> </generator> </configuration> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>$\{version.pgsql-jdbc}</version> </dependency> </dependencies> </plugin> For those familiar with this process, this is pretty typical: We configure the JDBC connection, using the same properties that Flyway uses. Notice that we’re using the flyway.url configured via the groovy-maven-plugin execution. We tell jOOQ that we’re using a PostgresDatabase, and we configure the input and output schemas. Finally, we configure the package we want the generate code to be in, and tell jOOQ where to write the files. There are two more plugins we need to configure: we need to add our generated code to the build, and we need to configure the test run, via Surefire, so that it knows where the database is. First, let’s compile the generated source: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>$\{version.build-helper}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>$\{jooq.outputdir}</source> </sources> </configuration> </execution> </executions> </plugin> and configure the test: <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>$\{version.surefire-plugin}</version> <configuration> <systemProperties> <quarkus.datasource.jdbc.url>$\{flyway.url}</quarkus.datasource.jdbc.url> </systemProperties> </configuration> </plugin> Here we simply set quarkus.datasource.jdbc.url to the computed value of flyway.url, which is the standard Quarkus property, so it will be picked up automatically. When we run the build now, a PostgreSQL container will be started, its database will be built using Flyway, jOOQ type-safe code will be generated using that databse, these new classes will be compiled along with the hand-written code, tests will be run against the Docker-based database, and, finally, the container will be torn down and cleaned up by Testcontainers, so there’s no need for us to worry about it explicitly. While Testcontainers will shut down and remove containers, the imagaes it downloads will remain on disk, so it will be up to you (or someone in your organization) to manage that disk space. This may be especially important in a shared CI environment. With this setup, which does work in the context of GitHub actions, you don’t need to download and install a database, or worry about your tests damaging any existing databases on the local machine; they’re always given a new, pristine database image against which to work. The downside, though, is that if a test fails, analyzing the test data in the database gets trickier. That is, however, solvable, though I’ll leave that as an exercise for the reader. For now, at least. Enjoy! ### [Testing with Quarkus, jOOQ, and Testcontainers](/2021/testing-with-quarkus-jooq-and-testcontainers/) In a project I’ve been working on, I’ve been targeting PostgreSQL, but testing with H2. While that works, I’m a big fan of having the test environment match production as much as possible. That said, I don’t like to have external system dependencies for tests, such as requiring having a database installed. That’s where Testcontainers comes in. In this post, I’ll look at how I integrated Testcontainers into my Quarkus+jOOQ project To set the stage, I should describe how my project is set up as far as data access goes. I’m using jOOQ, rather than, say, JPA or Panache. I manage the central jOOQ object, DSLContext, via CDI, and @Inject that as needed. The @Produces method looks something like this: @RequestScoped class DslContextProvider { @Inject lateinit var dataSource: DataSource @Produces @RequestScoped fun getDslContext(): DSLContext { val configuration = DefaultConfiguration() .set(dataSource) .set(SQLDialect.POSTGRES) .set( Settings() .withExecuteLogging(true) .withRenderCatalog(false) .withRenderSchema(false) .withRenderQuotedNames(RenderQuotedNames.NEVER) .withRenderNameCase(RenderNameCase.LOWER_IF_UNQUOTED) ) return DSL.using(configuration) } } The DataSource is managed via Quarkus' built-in support, so I just have to configure it: quarkus.datasource.db-kind=$\{DB_TYPE:postgresql} quarkus.datasource.jdbc.url=$\{DB_URL:jdbc:postgresql://$\{DB_HOST:localhost}:5432/myDb} quarkus.datasource.username=$\{DB_USER:someUser} quarkus.datasource.password=$\{DB_PASS:somePassword} This works great until I start testing. The problem as I saw it is this: Testcontainers can easily start a PostgreSQL instance, but the default port exposed is randomized so as to avoid collisions with what might already be running on the host. What I need, then, is a way to point my DataSource to a server on an unknown-at-build-time port. So what to do? There are likely a number of options, but the route I chose was to create my DataSource manually, at run time: @Alternative @ApplicationScoped @Priority(1) /** * This class handles the creation and start of the Docker-based pgsql database, as well as * @Producing a DataSource to be injected into DslContextProvider, allowing jOOQ to talk to * our container-based DB. */ class DynamicDataSourceProvider { @Produces fun produceContainerDatasource(): DataSource { if (!started) { started = true startContainer() createDataSource() Flyway.configure() .dataSource(dataSource) .load() .migrate() } return dataSource } private fun createDataSource() { dataSource = PGSimpleDataSource() dataSource.serverNames = arrayOf("localhost") dataSource.portNumbers = intArrayOf(postgres.getMappedPort(5432)) dataSource.user = DB_NAME dataSource.password = DB_NAME dataSource.databaseName = DB_NAME } private fun startContainer() { postgres = PostgreSQLContainer(PostgreSQLContainer.IMAGE) .withUsername(DB_NAME) .withPassword(DB_NAME) .withDatabaseName(DB_NAME) .withExposedPorts(5432) .withReuse(true) postgres.start() } companion object { const val DB_NAME = "testdb" private var started = false private lateinit var dataSource : PGSimpleDataSource private lateinit var postgres : PostgreSQLContainer<*> } } I start by creating a new @ApplicationScoped bean, annotated with @Alternative to tell CDI I’m overriding another bean. I then add the @Produces method that will do the work. I have three requirements: start the container, create the DataSource, and run my Flyway migrations, and those are handled in order by produceContainerDatasource(). In startContainer(), we see the Testcontainer usage where the database instance is started. We hardcode the database name, user name, and password, as they really don’t matter. This is a throw-away database, so security is not a concern. In createDataSource, we create an instance of PostgreSQL’s PGSimpleDataSource, and configure it to match the container, pulling the randomized port from the container. Finally, back in produceContainerDatasource(), we programmatically migrate the database to set up our schema and test data. I also chose to wrap the whole process inside the if (started) block. While not strictly necessary, it seems to speed things up just a little bit. Rather than Testcontainers having to decide whether or not to create or reuse the container, we just create it once and store the reference in a static variable. If you find that distasteful, you can store the reference in an instance variable and let Testcontainers figure things out. I’m not a Testcontainers expert, and while I’m pretty comfortable with Quarkus, there’s always something more to learn, so please take this (and everything you read from me ;) as something freely shared as I learn the technology. There very well my be a better way to do this. If you find one, I’d love to hear about it so I can learn some more. If you find this works well enough for you, then use it in good health. :) ### [Merry Christmas, 2021](/2021/merry-christmas-2021/) To all my readers, I’d like to wish a merry Christmas, and a happy new year. In a world seeking hope, my prayer is that each of you would find real, lasting hope, in the birth the baby we celebrate today, Jesus Christ, Emmanuel, God with us. (Image source. Thanks, Dr. Mounce :) ### [WildFly and Micrometer](/2021/wildfly-and-micrometer/) Earlier in the summer, I wrote some about the addition of OpenTelemetry support in WildFly. With the release of WildFly 25, that support is now official and in the wild. With 25 behind us, we start looking at 26, and my next effort will be to integrate Micrometer metrics into the server. In this post, we’ll take a look at what that might mean, as well as presenting a way to take an early look. Savvy users will likely note that WildFly already has metrics support. In fact, it has two: what we call "base" or "WildFly metrics" available out-of-the-box in standalone.xml, as well as MicroProfile Metrics, available in standalone-microprofile.xml. If we have those two, why a third? The answer is simple: Micrometer seems to be where Java-land is heading, so much so, in fact, that MicroProfile Metrics is, currently, basically dead (there are ongoing discussions about how to move forward with regard to Micrometer and MP Metrics, but those are out of scope here). What adding another metrics to the system means for the two existing systems is a big topic, and I’ll touch on that below. Getting Started So how does one get started with Micrometer on WildFly? Of course, you’ve always been able to add Micrometer to your application and deploy it, but we’re hoping to do is integrate it with the server so that it’s always available, and so that administrators can get server- and JVM-level metrics as well, right out of the box. Since this feature is still under discussion and development, though, it doesn’t reside in the main WildFly git repo. It lives, instead, in my own {git-repo}[repository] as a feature branch. These changes are now part of the official WildFly builds, so this part is no longer necessary. To install it, you have two options: 1) Install this archive, or 2) Build from {git-repo}[source]. Once you have a server running, it’s time (no pun intended) to get some metrics. As a small demo, take this Jakarta REST resource: @RequestScoped @Path("/") public class MetricResource { @Inject private MeterRegistry meterRegistry; @GET @Path("/") public double getCount() { Counter counter = meterRegistry.counter("demo_counter"); Timer timer = meterRegistry.timer("demo_timer"); Timer.Sample sample = Timer.start(); try { Thread.sleep((long) (Math.random() * 1000L)); } catch (InterruptedException e) { throw new RuntimeException(e); } counter.increment(); sample.stop(timer); return counter.count(); } } This sample creates two meters, a Counter and Timer, and makes some pretty trivial updates. We can see this when we request metrics from the server. As noted above, this support is still under active discussion at the time of this writing, so a lot of details on how things will look when this support is released are still uncertain. That being so, I’ve exposed the Micrometer metrics on a new management endpoint http://localhost:9990/micrometer. Accessing that, we can see our metrics show up: $ http :9990/micrometer | grep demo # HELP demo_counter_total # TYPE demo_counter_total counter demo_counter_total 1.0 # HELP demo_timer_seconds # TYPE demo_timer_seconds summary demo_timer_seconds_count 1.0 demo_timer_seconds_sum 0.952373899 # HELP demo_timer_seconds_max # TYPE demo_timer_seconds_max gauge demo_timer_seconds_max 0.952373899 There are, of course, a number of other metrics. When the Micrometer subsystem is loaded, we automatically register a number of meters to capture JVM and system data as well, similar to what one would expect from WildFly Metrics or MicroProfile Metrics. For example: # HELP datasources_pool_total_get_time The total time spent obtaining physical connections # TYPE datasources_pool_total_get_time gauge datasources_pool_total_get_time\{app="wildfly",deployment="",name="ExampleDS",subdeployment="",type="data-source",} 0.0 # HELP ee_current_queue_size The current size of the executor's task queue. # TYPE ee_current_queue_size gauge ee_current_queue_size\{app="wildfly",deployment="",name="default",subdeployment="",type="managed-scheduled-executor-service",} 0.0 ee_current_queue_size\{app="wildfly",deployment="",name="default",subdeployment="",type="managed-executor-service",} 0.0 # HELP ee_hung_thread_count The number of executor threads that are hung. # TYPE ee_hung_thread_count gauge ee_hung_thread_count\{app="wildfly",deployment="",name="default",subdeployment="",type="managed-scheduled-executor-service",} 0.0 ee_hung_thread_count\{app="wildfly",deployment="",name="default",subdeployment="",type="managed-executor-service",} 0.0 # HELP messaging_activemq_global_client_thread_pool_keepalive_time_seconds The amount of time that pool threads should be kept running when idle. # TYPE messaging_activemq_global_client_thread_pool_keepalive_time_seconds gauge messaging_activemq_global_client_thread_pool_keepalive_time_seconds\{app="wildfly",deployment="",subdeployment="",} 60.00000000000001 # HELP batch_jberet_completed_task_count The approximate total number of tasks that have completed execution. # TYPE batch_jberet_completed_task_count gauge batch_jberet_completed_task_count\{app="wildfly",deployment="",name="batch",subdeployment="",type="thread-pool",} 0.0 # HELP infinispan_success_ratio The data replication success ratio (successes/successes+failures). # TYPE infinispan_success_ratio gauge infinispan_success_ratio\{app="wildfly",deployment="",name="http-remoting-connector",subdeployment="",type="cache",} 0.0 # HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool # TYPE jvm_buffer_count_buffers gauge jvm_buffer_count_buffers\{id="mapped",} 0.0 jvm_buffer_count_buffers\{id="direct",} 90.0 There are many more, of course, but you get the point, and this being Micrometer, what we see represented here is Prometheus-compatible output ready for consumption by your tool of choice. Where Next? It can’t be overstated that is all under development, so things may change, but we would definitely appreciate any experimentation and feedback you care to offer, either on the JIRA or the WildFly developers' list. We have a number of open questions, which, while listed on the JIRA, I’ll reproduce here: We have two subsystems for doing metrics now (WF metrics and MP metrics). Are we adding a third? Removing/replacing WF Metrics? What’s the long term relationship with MP Metrics? Other components that we integrate have their own Micrometer integration. What happens with those? How does this affect RBAC? Does each application get its own registry, or are all the apps lumped together? If each application gets its own, do we prefix each metric name with, say, the deployment name? WF and MP Metrics have the concept of "base" and "vendor" metrics (with MP Metrics adding an "application" scope). Do we want to continue this convention? Should we prefix each "vendor" metric name with "wildfly"/"eap" as we are doing now? Some of these we’ve already answered internally. For example, for "WF and MP Metrics have the concept of "base" and "vendor" metrics (with MP Metrics adding an "application" scope). Do we want to continue this convention?", we’re moving forward with "No" on that, as that does not seem to match what we’re seeing in terms of customer desires. There is time, of course, to make your case on this question, or any of them, if you feel strongly one way or another. We’re hoping to ship this in WildFly 26 (no promises from me, of course), so you have a few weeks to take a look and provided feed should you so desire. We’re 100% interested in making this a feature that meets your needs, so please don’t be shy. :) ### [A Quarkus Command Line Application](/2021/a-quarkus-command-line-application/) Most people know Quarkus as a great way to build fast, scalable microservices. What many may not be aware of, however, is that Quarkus can also be used to build command line applications as well. In this post, we’ll take a look at how we can leverage the Quarkus ecosystem we already know to build a command line utility quickly and easily. The command line application we’ll build actually already exists. The GitHub user techpavan has a utility, mvn-repo-cleaner, that can be used to clean up old, unused artifacts from the local Maven repository. It’s a great utility, but it hasn’t been updated in at least a couple of years. Using this as a practical target, then, let’s see what Quarkus can offer. Quarkus' CLI support is based on Picocli. Using Quarkus' project generation site, we can bootstrap our app: Specify the groupId: com.steeplesoft Specify the artifact name: mvn-repo-cleaner Select the build tool: Maven Search for pico and select the library Select No for Starter Code Click Generate your application Since we’re migrating/porting an existing CLI utility, we already have a nice, practical command to implement, which means all we need to do is copy the existing classes in techpavan’s upstream project: ArgData, CleanM2, and FileInfo. These classes require some dependencies we haven’t declared yet, so let’s add those now: <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-artifact</artifactId> <version>3.8.2</version> </dependency> The first class we need to update is CleanM2. This class will be the entry point into our utility. Since the upstream project is based on JCommander, our first step is to remove the related imports. We also need to annotate the class so Picocli knows we’re defining a new command in this class: @CommandLine.Command public class CleanM2 implements Runnable { // ... We’ve also added an implements Runnable, as Picocli requires that each command be Runnable. The next step is to modify the class' public void main, making it implement the run() method from the interface: - public static void main(String[] args) { + @Override + public void run() { We now have our Picocli command, but it could use some parameters, which are defined currently in ArgData. Like CleanM2, this class heavily uses JCommander APIs. Fortunately, the APIs are pretty similar, so it’s mostly a matter of changing the imports - @Parameter(names = {"--path", "-p"}, description = "Path to m2 directory, if using a custom path.") - private String m2Path; + @CommandLine.Option(names = {"--path", "-p"}, + description = "Path to m2 directory, if using a custom path.") + protected String m2Path; and then updating the annotations on the parameters. You can actually update them all at once with a simple search and replace: @Parameter → @CommandLine.Option. To make these options available to the command, we have two options: copy/move each of these properties to CleanM2 or have CleanM2 extend ArgData. I chose to go with the second option to reduce the number of changes from the upstream project: @CommandLine.Command public class CleanM2 extends ArgData implements Runnable { CleanM2 will still have quite a few compilation errors related to the parameter properties. I won’t go over those here, as they’re pretty simple to update (you can also "cheat" by looking at the GitHub repo for this project.) I’ve also taken the opportunity to remove all of the static modifiers. That’s more of a personal preference than a technical requirement, so feel free not to do the same if that’s your preference. With those changes done, we’re ready to build and run this: $ mvn clean package ... $ ls -alh target/ total 20K drwxrwxr-x 1 jdlee jdlee 226 Oct 10 20:44 . drwx--x--x. 1 jdlee jdlee 244 Oct 10 20:44 .. drwxrwxr-x 1 jdlee jdlee 72 Oct 10 20:44 classes drwxrwxr-x 1 jdlee jdlee 22 Oct 10 20:44 generated-sources drwxrwxr-x 1 jdlee jdlee 28 Oct 10 20:44 maven-archiver drwxrwxr-x 1 jdlee jdlee 42 Oct 10 20:44 maven-status -rw-rw-r-- 1 jdlee jdlee 16K Oct 10 20:44 mvn-repo-cleaner-1.0.0-SNAPSHOT.jar drwxrwxr-x 1 jdlee jdlee 112 Oct 10 20:44 quarkus-app -rw-rw-r-- 1 jdlee jdlee 117 Oct 10 20:44 quarkus-artifact.properties As things stand out of the box, to run our command, you would do something like this: $ java -jar target/quarkus-app/quarkus-run.jar --help ... While that works, shipping that is not ideal. We can fix that by changing how Quarkus packages the app. The default for Quarkus is the "fast jar" format, which we see above in target/quarkus-app. What we’d like is a fat/uber jar, where our utility and all of its dependencies are in one archive. To do that with Quarkus, we need to configure the build using src/main/resources/application.properties: quarkus.package.type=uber-jar Now, if we rebuild: $ mvn clean package ... $ ls -alh target/ total 4.0M drwxrwxr-x 1 jdlee jdlee 286 Oct 10 20:53 . drwx--x--x. 1 jdlee jdlee 244 Oct 10 20:53 .. drwxrwxr-x 1 jdlee jdlee 72 Oct 10 20:53 classes drwxrwxr-x 1 jdlee jdlee 22 Oct 10 20:53 generated-sources drwxrwxr-x 1 jdlee jdlee 28 Oct 10 20:53 maven-archiver drwxrwxr-x 1 jdlee jdlee 42 Oct 10 20:53 maven-status -rw-rw-r-- 1 jdlee jdlee 16K Oct 10 20:53 mvn-repo-cleaner-1.0.0-SNAPSHOT.jar.original -rw-rw-r-- 1 jdlee jdlee 4.0M Oct 10 20:53 mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.jar -rw-rw-r-- 1 jdlee jdlee 122 Oct 10 20:53 quarkus-artifact.properties We now have a 4M archive, mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.jar, which we can run with: $ java -jar target/mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.jar --help ... That gives us a single file to ship around to users' machines, which is definitely an improvement. It still requires a JVM, though. While that’s not necessarily an issue for this command, which is clearly targeted at developers, your command line utility may not be. This is where Quarkus starts to shine: we’re going to build a native image, which Quarkus makes super easy, barely an inconvenience. To do so, though, we will need GraalVM installed, which I’ve done using sdkman!. $ sdk install java 21.2.0.r16-grl $ sdk use java 21.2.0.r16-grl $ gu install native-image $ mvn -Pnative package ... [INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildRunner] /home/jdlee/.sdkman/candidates/java/21.2.0.r16-grl/bin/native-image -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Duser.language=en -J-Duser.country=US -J-Dfile.encoding=UTF-8 -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy\$BySpaceAndTime -H:+JNI -H:+AllowFoldMethods -H:FallbackThreshold=0 -H:+ReportExceptionStackTraces -H:-AddAllCharsets -H:EnableURLProtocols=http -H:NativeLinkerOption=-no-pie -H:-UseServiceLoaderFeature -H:+StackTrace -H:-ParseOnce mvn-repo-cleaner-1.0.0-SNAPSHOT-runner -jar mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.jar [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] classlist: 888.08 ms, 0.96 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (cap): 461.21 ms, 0.96 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] setup: 1,674.56 ms, 0.96 GB 21:04:16,716 INFO [org.jbo.threads] JBoss Threads version 3.4.2.Final [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (clinit): 266.48 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (typeflow): 7,152.50 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (objects): 9,486.04 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (features): 518.46 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] analysis: 18,004.64 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] universe: 758.33 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (parse): 1,882.04 ms, 3.22 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (inline): 2,659.86 ms, 5.29 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] (compile): 14,088.48 ms, 5.54 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] compile: 19,952.01 ms, 5.54 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] image: 2,717.06 ms, 5.54 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] write: 321.33 ms, 5.54 GB [mvn-repo-cleaner-1.0.0-SNAPSHOT-runner:20610] [total]: 44,515.50 ms, 5.54 GB # Printing build artifacts to: /home/jdlee/src/personal/mvn-repo-cleaner/target/mvn-repo-cleaner-1.0.0-SNAPSHOT-native-image-source-jar/mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.build_artifacts.txt [INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildRunner] objcopy --strip-debug mvn-repo-cleaner-1.0.0-SNAPSHOT-runner [INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 45883ms $ ls -alh target/ total 38M drwxrwxr-x 1 jdlee jdlee 604 Oct 10 21:04 . drwx--x--x. 1 jdlee jdlee 244 Oct 10 21:02 .. drwxrwxr-x 1 jdlee jdlee 72 Oct 10 20:56 classes drwxrwxr-x 1 jdlee jdlee 22 Oct 10 20:56 generated-sources drwxrwxr-x 1 jdlee jdlee 28 Oct 10 20:56 maven-archiver drwxrwxr-x 1 jdlee jdlee 42 Oct 10 20:56 maven-status -rw-rw-r-- 1 jdlee jdlee 16K Oct 10 20:59 mvn-repo-cleaner-1.0.0-SNAPSHOT.jar -rw-rw-r-- 1 jdlee jdlee 16K Oct 10 20:56 mvn-repo-cleaner-1.0.0-SNAPSHOT.jar.original drwxrwxr-x 1 jdlee jdlee 206 Oct 10 21:04 mvn-repo-cleaner-1.0.0-SNAPSHOT-native-image-source-jar -rwxrwxr-x 1 jdlee jdlee 34M Oct 10 21:04 mvn-repo-cleaner-1.0.0-SNAPSHOT-runner -rw-rw-r-- 1 jdlee jdlee 4.0M Oct 10 20:56 mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.jar drwxrwxr-x 1 jdlee jdlee 112 Oct 10 21:04 quarkus-app -rw-rw-r-- 1 jdlee jdlee 293 Oct 10 21:04 quarkus-artifact.properties That gives us a 34M file, mvn-repo-cleaner-1.0.0-SNAPSHOT-runner, with an amazing startup: $ time java -jar target/mvn-repo-cleaner-1.0.0-SNAPSHOT-runner.jar --help ... real 0m0.787s user 0m1.130s sys 0m0.101s $ time ./target/mvn-repo-cleaner-1.0.0-SNAPSHOT-runner --help ... real 0m0.034s user 0m0.020s sys 0m0.015s From 787 thousandths of a second to 34 thousandths of a second. That’s pretty impressive! With that, we have a complete command line utility based on Quarkus (with a big tip o' the hat to techpavan for doing the hard work of making the original utility). Hopefully, this will serve as a nice example to follow if and when you write your own utility. You can find the complete source here. Use it in good health. :) ### [An Update on OpenTelemetry and WildFly](/2021/an-update-on-opentelemetry-and-wildfly/) In a recent post, I worked through setting up OpenTelemetry support in your Jakarta EE application. Since that time, I’ve put quite a bit of work into integrating that support, as teased in the post, into WildFly. In this post, I’d like to provide an update on what that WildFly support currently looks like, and put out a request for feedback. These changes are now part of the official WildFly builds, so this part is no longer necessary. To get started experimenting with my changes, you need to do one of two things: build the server from source using my branch, or download this hopefully up-to-date binary build.__ With the current state of changes, you get the following: CDI injection of a Tracer instance. CDI injection of an OpenTelemetry instance should want to manually create a Tracer. Automatic context propagation on all incoming REST requests so long as the request adheres to the OpenTelemetry context propagation spec. Automatic context propagation on all outgoing REST Client requests. This is done via an automatically-registered ClientRequestFilter, so no additional work need be done in your application. Along with that runtime functionality, you can configure how OpenTelemetry behaves: service-name: The name of the service reported in the traces exporter: Can either be jaeger or otlp. The default is jaeger using gRPC. endpoint: The endpoint of the trace collector. The default is for Jaeger on localhost. span-processor: Can either be batch or simple. The default is batch. batch-delay: The time in milliseconds to delay a batch processing. This is only used if span-processor is set to batch. The default is 5000ms. max-queue-size: The maximum size of the batch before sending. The default is 2048. max-export-batch-size: The maximum number of samples to export at a time. The default is 512. export-timeout: The maximum wait time while exporting traces. The default is 30000ms, or 30 seconds. sampler: The sampler to use: on, off, or ratio sampler-arg: The ratio to use when sampling traces. From a WildFly configuration perspective, the configuration looks like this: <subsystem xmlns="urn:wildfly:opentelemetry:1.0" exporter="jaeger" endpoint="http://localhost:14250" span-processor="batch" batch-delay="5000" max-queue-size="2048" max-export-batch-size="512" export-timeout="30000" /> As it stands now, it seems to work really well. In designing and implementing what I have so far, I’ve discussed things internally with other Red Hat engineers in the observability space, as well as with some in the CNCF Slack channel, but more input would be extremely helpful. Are there features you’d like to see? Are there any changes you’d like to see in the configuration? Is there anything missing in the runtime support that you’d like to see? Currently, the service name is the same for all applications deployed to a given WildFly instance. Is that acceptable? If not, if it’s technically possible, would a per-app service name be preferable? Any and all feedback is welcome. You can always find me on Twitter or, better yet, comment on the issue in JIRA. ### [OpenTelemetry and Jakarta REST Services](/2021/opentelemetry-and-jakarta-rest-services/) Knowing what’s going on in your microservices deployment is extremely important when something goes wrong. In a distributed system, though, it can be difficult to know where things have gone wrong. That’s where a tracing system such as OpenTelemetry can be immensely valuable. In this post, we’ll build two simple services, one of which calls the other, and trace the execution from end to end. The Parent POM We’ll start by setting up the project, and we’ll do so by creating a multimodule Maven pom: pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft.otel</groupId> <artifactId>multiservice-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>otel-integration</module> <module>service1</module> <module>service2</module> </modules> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-bom</artifactId> <version>1.2.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <version>2.1.6</version> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <version>2.0.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-okhttp</artifactId> <version>1.36.1</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-trace</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-jaeger</artifactId> </dependency> </dependencies> </project> By setting up the parent POM this way, we’ll make the three submodules much simpler. Since the two services are largely identical, we’ll only look at one of those POMs. The Basic REST service service1/pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>multiservice-demo</artifactId> <groupId>com.steeplesoft.otel</groupId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>service1</artifactId> <packaging>war</packaging> <dependencies> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>otel-integration</artifactId> <version>$\{project.version}</version> </dependency> </dependencies> </project> There’s really not much to this beyond a dependency on another module from our project, which we’ll look at shortly. First, our REST endpoint: RestEndpoint1.java @Path("/endpoint1") public class RestEndpoint1 { @Inject private Tracer tracer; @Inject private OpenTelemetry otel; @GET public String method1() { final Span span = tracer.spanBuilder("Doing some work") .startSpan(); span.makeCurrent(); span.setAttribute("in.my", "application"); span.addEvent("Test Event"); sleep(); doSomeMoreWork(); span.addEvent("After work"); String service2 = sendRequest(); sleep(); doEvenMoreWork(); span.end(); return "Hello World, from service 1! Service 2 happened to say '" + service2 + "'"; } private void doSomeMoreWork() { final Span span = tracer.spanBuilder("Doing some more work") .startSpan(); span.makeCurrent(); sleep(); doEvenMoreWork(); span.end(); } private void doEvenMoreWork() { final Span span = tracer.spanBuilder("Doing even more work") .startSpan(); span.makeCurrent(); sleep(); span.end(); } // ... } This is a pretty boring, if somewhat contrived, REST endpoint. The interesting part is the injection of the OpenTelemetry Tracer instance, and the creation of the spans in the REST method itself. From the OpenTelemetrey docs, we learn that Traces track the progression of a single request, called a trace, as it is handled by services that make up an application…​Each unit of work in a trace is called a span; a trace is a tree of spans." and that "[s]pans are objects that represent the work being done by individual services or components involved in a request as it flows through a system. In the midst of our "work", then, we create a span to track the process. This will help help us mark the beginning and end of unit of work. As we monitor the system, we can compute statistics on, for example, the average time a given span takes. Should it start deviating wildly, we may have found our issue’s culprit. The use of a span may look something like this, generically speaking: Span span = tracer.spanBuilder("Doing some work") .startSpan(); span.makeCurrent(); // Do some work span.end(); When creating the span, we want to give it a meaningful name so we can find it more easily when we look at the logs. Remember, though, that a trace is a tree of spans. When we create the span here, OpenTelemetry automatically sets as its parent any span that might be current. In looking through our endpoint, we create several spans, and their parent span is automatically set for us so we can see the relationship of one span to another (e.g., "Span A" encompasses "Span B" through "Span D") to get a better picture of a request’s flow through the system. While that’s all well and good, where do OpenTelemetry and Tracer come from? For that, let’s look at the otel-integration module. OpenTelemetry Integration Module At the moment, unless one is using OpenTelemetry’s automatic instrumentation to integrate the library, there’s a small bit of setup that is required. This module offers three classes that do that: one to produce the OpenTelemetry instance, one for the Tracer, and one to set up a Jakarta REST filter to automatically trace incoming requests. The producer methods are fairly standard CDI producers. For OpenTelemetry, we have this: OpenTelemetryProducer.java @ApplicationScoped public class OpenTelemetryProducer { @javax.annotation.Resource(lookup="java:app/AppName") private String applicationName; private volatile OpenTelemetry openTelemetry; @Produces public OpenTelemetry getOpenTelemetryInstance() { OpenTelemetry localRef = openTelemetry; if (localRef == null) { synchronized (this) { localRef = openTelemetry; if (localRef == null) { openTelemetry = localRef = localBuild(); } } } return localRef; } private OpenTelemetrySdk localBuild() { final JaegerGrpcSpanExporterBuilder exporterBuilder = JaegerGrpcSpanExporter.builder(); final BatchSpanProcessorBuilder spanProcessorBuilder = BatchSpanProcessor.builder(exporterBuilder.build()); final SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder() .addSpanProcessor(spanProcessorBuilder.build()) .setResource(Resource.create(Attributes.of( ResourceAttributes.SERVICE_NAME, applicationName, AttributeKey.stringKey("foo"), "bar"))); return OpenTelemetrySdk.builder() .setTracerProvider(tracerProviderBuilder.build()) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); } } In this application-scoped bean, we have a producer method that…​ produces the OpenTelemetry instance, using the double-check idiom (you can read more about that here, if you’re curious, and, yes, using it might be overkill, but better safe, eh? :) In the localBuild() method (so named to differentiate from the GlobalOpenTelemetry.get() approach), we define an exporter, which will export our trace information to an external system, Jaeger, for aggregation and study, and a Tracer provider, which lets us configure our Tracer. In this case, we want to use the Jakarta EE application name, injected into applicationName to set the service name (and we add a random attribute just to demonstrate where that might show up). For the Tracer, we have something similar: TracerProvider.java @ApplicationScoped public class TracerProducer { @Inject private OpenTelemetry openTelemetry; private volatile Tracer tracer; @Produces public Tracer getTracer() { Tracer localRef = tracer; if (localRef == null) { synchronized (this) { localRef = tracer; if (localRef == null) { tracer = localRef = openTelemetry.getTracer("com.steeplesoft.otel", "1.0.0-SNAPSHOT"); } } } return localRef; } } The only new thing of note here is simply the OpenTelemetry API call to get the Tracer instance. Finally, let’s look at our request/response filter: OpenTelemetryFilter.java @ApplicationScoped public class OpenTelemetryFilter implements ContainerRequestFilter, ContainerResponseFilter { @Inject private OpenTelemetry openTelemetry; @Inject private Tracer tracer; @Override public void filter(ContainerRequestContext requestContext) { Context extractedContext = openTelemetry.getPropagators() .getTextMapPropagator() .extract(Context.current(), requestContext, new TextMapGetter<>() { @Override public String get(ContainerRequestContext requestContext, String key) { if (requestContext.getHeaders().containsKey(key)) { return requestContext.getHeaders().get(key).get(0); } return null; } @Override public Iterable<String> keys(ContainerRequestContext requestContext) { return requestContext.getHeaders().keySet(); } }); final UriInfo uriInfo = requestContext.getUriInfo(); final URI requestUri = uriInfo.getRequestUri(); final String method = requestContext.getMethod(); final String uri = uriInfo.getPath(); Span serverSpan = tracer.spanBuilder(method + " " + uri) .setSpanKind(SpanKind.SERVER) .setParent(extractedContext) .startSpan(); serverSpan.makeCurrent(); serverSpan.setAttribute(SemanticAttributes.HTTP_METHOD, method); serverSpan.setAttribute(SemanticAttributes.HTTP_SCHEME, requestUri.getScheme()); serverSpan.setAttribute(SemanticAttributes.HTTP_HOST, requestUri.getHost() + ":" + requestUri.getPort()); serverSpan.setAttribute(SemanticAttributes.HTTP_TARGET, uri); requestContext.setProperty("span", serverSpan); } @Override public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) { Object serverSpan = containerRequestContext.getProperty("span"); if (serverSpan != null && serverSpan instanceof Span) { ((Span) serverSpan).end(); } } } There’s quite a bit going on here: First, we extract any context that may have been propagated to us by the calling system. OpenTelemetry is a specification with implementations in many languages, so it’s entirely possible that, say, a JavaScript client has created a trace and is calling our service. In that case, we want to pick up that context and continue using it in this part of the system. We’ll see this in use when we call between our two Java services in a bit. Next, we extract some information about the request from the Jakarta REST UriInfo instance on the ContainerRequestContext. We create a server span, adding information about the request as attributes. Before finishing up the request part of the filter, we set the span as a property on the ContainerRequestContext for use later. Finally, in the response portion of the filter, we retrieve the span from the ContainerRequestContext and call span.end() If we deploy the services now, we’ll certainly get traces logged, but when we call from Service 1 to Service 2, we lose some of the context, so let’s see how to get the trace to propagate across services. Context Propagation Back in Service 1, we make a call to Service 2 in the method sendRequest(). We left that out earlier for brevity’s sake, so let’s look at that now: RestEndpoint1.java private String sendRequest() { TextMapSetter<HttpRequest.Builder> setter = (requestBuilder, key, value) -> { requestBuilder.header (key, value); }; HttpRequest.Builder builder = HttpRequest.newBuilder() .uri(URI.create("http://localhost:8080/service2-1.0-SNAPSHOT/api/endpoint2")) .timeout(Duration.ofMinutes(1)) .header("Content-Type", "application/json") .GET(); otel.getPropagators().getTextMapPropagator().inject(Context.current(), builder, setter); final HttpRequest request = builder.build(); try { HttpResponse<String> response = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .build() .send(request, HttpResponse.BodyHandlers.ofString()); return response.body(); } catch (Exception e) { throw new RuntimeException(e); } } Similar to reading the context from an incoming request, we create an instance of TextMapSetter<T> that will write the context propagation header to the outgoing request. We start building the request, using Java 11’s HTTP client, hardcoding Service 2’s API because we can. :) In the middle, there, we ask OpenTelemetry to inject itself into the request: otel.getPropagators().getTextMapPropagator().inject(Context.current(), builder, setter); This line of code adds a header that our request filter above will then extract to set up the trace context in service 2. Once the context headers are injected, we finish the request to service 2, and let the request to service 1 complete as well. Looking at the traces Now that we’ve instrumented our application, how do we view the telemetry data? For that, we’re going to use Jaeger, and since this post is already long enough and a production setup of Jaeger is out of scope, we’ll go super simple. Download the Jaeger all-in-one distribution from here and run it in one terminal, then start, say, WildFly in another, and deploy our apps in still another: $ jaeger-all-in-one --collector.zipkin.host-port=:9411 // Another terminal $ bin/standalone.sh // Yet another $ cd $PROJECT_DIR $ mvn clean package ... $ jboss-cli.sh -c "deploy --force service1/target/service1-1.0-SNAPSHOT.war" && jboss-cli.sh -c "deploy --force service2/target/service2-1.0-SNAPSHOT.war" $ http :8080/service1-1.0-SNAPSHOT/api/endpoint1 HTTP/1.1 200 OK Connection: keep-alive Content-Length: 81 Content-Type: application/octet-stream Date: Wed, 02 Jun 2021 21:44:11 GMT Hello World, from service 1! Service 2 happened to say 'Service 2 did something!' While this proves our services work (for some value of 'work'), where are the traces? For that, point your browser at the Jaeger UI. Once the page loads, select service1-1.0-SNAPSHOT from the Service dropdown, then click Find Traces. You should see results that look something like this: Clicking on that first trace, should get you a screen like this: You should see 8 spans across 2 different services. I added some random sleeps in the services to help the nested spans be more obvious. Wrapping Up I am not an expert on OpenTelemetry, so I can’t guarantee this is a production-sound approach, but, Jaeger setup aside, it feels pretty solid to me at this point. At the very least, I hope it offers someone some help in getting started with OpenTelemetry. I should note that I’m doing this, at least in part, as part of the nascent efforts of adding OpenTelemetry support to WildFly, so, if all goes well, much of this will be done for you automatically if you deploy to WildFly. Until then, go forth and instrument your applications manually. :) If you’d like to see the entire project, you can find it on GitHub, and you can find me on Twitter. ### [A Simple Jakarta EE 9.1 REST Project](/2021/a-simple-jakarta-ee-9-1-rest-project/) Jakarta EE 9.1 was released today, which now lets developers use — officially — Java 11 with the shiny new Jakarta EE namespace introduce in EE 9. So what does a simple Jakarta EE 9.1 REST project look like? I’m so glad you asked. :) Let’s start with the Maven POM: pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>jakarta-ee-91-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-bom</artifactId> <version>9.1.0</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> </dependencies> </project> Strictly speaking, you don’t need the BOM import, but it does make adding Jakarta EE deps easier later. We’ll need two classes, an Application instance, and at least one endpoint. Notice the imported packages. ;) The Jakarta REST application: JakartaEEApplication.java import java.util.HashSet; import java.util.Set; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/") public class JakartaEEApplication extends Application { @Override public Set<Class<?>> getClasses() { final Set<Class<?>> classes = new HashSet<>(1); classes.add(RestEndpoint1.class); return classes; } } And the endpoint: RestEndpoint.java package com.steeplesoft.ee91; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @Path("/endpoint1") public class RestEndpoint1 { @GET public String getString() { return "Hello World, from Jakarta EE 9.1!"; } } And now let’s deploy this on WildFly Preview: $ java --version openjdk 11.0.11 2021-04-20 OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9) OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode) $ wget https://download.jboss.org/wildfly/23.0.2.Final/wildfly-preview-23.0.2.Final.zip $ unzip wildfly-preview-23.0.2.Final.zip $ wildfly-preview-23.0.2.Final/bin/standalone.sh ... (In another window) $ wildfly-preview-23.0.2.Final/bin/jboss-cli.sh -c "deploy target/jakarta-ee-91-demo-1.0-SNAPSHOT.war" $ http :8080/jakarta-ee-91-demo-1.0-SNAPSHOT/endpoint1 HTTP/1.1 200 OK Connection: keep-alive Content-Length: 33 Content-Type: application/octet-stream Date: Tue, 25 May 2021 20:18:03 GMT Hello World, from Jakarta EE 9.1! That’s it. Easy peasy. Go grab the bits while they’re warm! :) ### [Microprofile Fault Tolerance Retry in Action](/2021/microprofile-fault-tolerance-retry-in-action/) As part of some of my recent work, I’ve gotten some exposure to some Microprofile specs I’ve not had the opportunity or need to use. One of those is Fault Tolerance. I was curious to see it action, so I’ve cobbled together this simple example that demonstrates some of that spec’s features, namely retries and fallback. It should be noted that the Fault Tolerance spec actually provides several mechanisms to improve the reliability of a distributed system including timeouts, retries, bulkheads, circuit breakers, and fallbacks. We are only going to look at retries and fallbacks here. Perhaps in a future post we’ll explore the others. To start, let’s describe our (contrived) scenario and show the code. We’re going to implement a simple REST service that calls an external service. In this case, we’re going to submit a search request to Google. (We won’t be using any API for this, just a simple GET request. There’s no need for anything more complicated at this point). To that end, here’s our gem: FailingResource.java @Path("/failing") public class FailingResource { @Inject @RestClient GoogleClient client; @GET @Produces(MediaType.TEXT_PLAIN) @Retry(maxRetries = 2, delay = 200, jitter = 100) @Fallback(fallbackMethod = "doWorkFallback") public String hello() throws URISyntaxException { return client.search("microprofile"); } private String doWorkFallback() { return "fallback"; } } It’s a pretty vanilla resource. On the resource method itself, note that we have two additional annotionations: @Retry and @Fallback. Using @Retry, we specifiy how many times the method should be called (maxRetries), how long to wait between invocations (delay), as well as a random "jitter", or variation, in the delay (jitter). Should maxRetries be exceeded, @Fallback comes into play, instructing the system to call doWorkFallback(). In this example, we’re also using the Microprofile REST Client. Note the injection of a GoogleClient: GoogleClient.java @RegisterRestClient @Path("/") public interface GoogleClient { @GET @Path("search") String search(@QueryParam("q") String text); } I don’t want to spend too much time here, so I’ll just note that the MP REST Client allows us to create a type-safe REST client as an interface, with which "the system" will then create a concrete instance that does the actual work of making the remote calls. We configure that client using yet another specification, Microprofile Config: application.properties com.steeplesoft.GoogleClient/mp-rest/url=https://www.google.com The client will make requests against https://www.google.com, but, for testing, we’ll need to change that. We’ll see how to do that in a bit. As in my last post, we’re going to test this using Wiremock. Before we jump into the code, though, let’s talk about how we need to go about testing this. Obviously, the point of the exercise to see Fault Tolerance’s retry and fallback in action. From what we saw in the last post, though, it seems we configure Wiremock to return certain response for each request to a given endpoint. While that is certainly true, Wiremock does allow us to change what the response is based on something they call scenarios. A scenarios is "essentially a state machine whose states can be arbitrarily assigned." They are arbitrarily named using string names, but always start with Scenario.STARTED. Using the Wiremock API, we can advance the scenario from one state to another based on various aspects of the request (such as reqest body, query params, etc). In our example, though, we just want it to fail a certain number of times, then, possibly, not fail. Let’s see what that looks like. FailingResourceTest.java @QuarkusTest @QuarkusTestResource(MockServer.class) public class FailingResourceTest { public static final String SCENARIO_NAME = "Failing Resource"; public static final String[] STATES = new String[]{"one", "two", "three", "four", "five"}; public static final String REQUEST_URL = "/search?q=microprofile"; @Test public void testSuccessfulRetry() throws URISyntaxException { reset(); stubFor(get(urlEqualTo(REQUEST_URL)) .inScenario(SCENARIO_NAME) .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse().withStatus(500)) .willSetStateTo(STATES[0])); stubFor(get(urlEqualTo(REQUEST_URL)) .inScenario(SCENARIO_NAME) .whenScenarioStateIs(STATES[0]) .willReturn(aResponse().withStatus(500)) .willSetStateTo(STATES[1])); stubFor(get(urlEqualTo(REQUEST_URL)) .inScenario(SCENARIO_NAME) .whenScenarioStateIs(STATES[1]) .willReturn(aResponse().withBody("success"))); given() .when() .get("/failing") .then() .statusCode(200) .body(is("success")); } } While it’s overkill, we call reset() at the start to…​wait for it…​ reset the Wiremock state, making sure the stubs and scenarios are in a clean, known state. The need for that will become apparent shortly. The stubFor() calls follow this logic: For requests to /search?q=microprofile, if the scenario is STARTED, return a 500 error, and set the state to one. For requests to /search?q=microprofile, if the scenario is one, return a 500 error, and set the state to two. For requests to /search?q=microprofile, if the scenario is two, return a 200, with a response body of success. Now, using RestAssured, we call our resource, which calls the mocked server using the MP Rest Client we configured above. Before we can do that, though, we need to setup and start Wiremock: MockServer.java public class MockServer implements QuarkusTestResourceLifecycleManager { private WireMockServer wireMockServer; @Override public Map<String, String> start() { wireMockServer = new WireMockServer(); wireMockServer.start(); return Map.of("com.steeplesoft.GoogleClient/mp-rest/url", wireMockServer.baseUrl()); } @Override public void stop() { wireMockServer.stop(); } } Since we’re stubbing the responses in our test, our setup is pretty simple. The super important part here, though, is the Map we return. Remember how we configure the REST Client using Microprofile Config? We can override the value of that configuration property by adding a key of the same name to the map, but providing the URL representing our mock server: wireMockServer.baseUrl(). Now if you run your test, you should get a green test. Huzzah! But what about the retry? The fallback? Let’s add another test, with a slightly different scenario setup. Here’s where reset() is important ;) FailingResourceTest.java @Test public void testUnsuccessfulRetry() { reset(); stubFor(get(urlEqualTo(REQUEST_URL)) .inScenario(SCENARIO_NAME) .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse().withStatus(500))); given() .when() .get("/failing") .then() .statusCode(200) .body(is("fallback")); } In this scenario, we will always return a 500 error since we don’t really care if "the server" ever recovers. We just want to attempts to fail over to our fallback method, in which case our resource returns "fallback". There is much, much more to the Fault Tolerance spec, but that gives you a taste of what retry and fallback looks like. You can find the complete project here. ### [Securing and Testing Quarkus Applications using Keycloak and Wiremock](/2021/securing-and-testing-quarkus-applications-using-keycloak-and-wiremock/) Obviously, web apps need to be secured. If you’re brave (and some might say foolish), you can roll your own security. Unless you have compelling reasons to do so, however, you probably shouldn’t. Almost as if by design (nyuk nyuk), Quarkus makes it easy to use any OpenID Connect server. One such server is Keycloak, an open source offering also from Red Hat. If your experience is like mine, though, securing endpoints makes testing a touch more complicated. In this post, I’d like to present and walk through a complete example of a secured Quarkus app, using Keycloak, JUnit and Wiremock. To begin, let’s set up a very simple Quarkus application. All it contains is a single resource, SampleResource, with two endpoints: one for admins, and one for users. In the interest of completeness, we start by setting up the project’s POM: The Application pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>quarkus-keycloak-wiremock</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <version.quarkus.platform>1.11.3.Final</version.quarkus.platform> <version.compiler-plugin>3.8.1</version.compiler-plugin> <version.surefire-plugin>2.22.2</version.surefire-plugin> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-bom</artifactId> <version>$\{version.quarkus.platform}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-oidc</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>io.quarkus</groupId> <artifactId>quarkus-maven-plugin</artifactId> <version>$\{version.quarkus.platform}</version> <executions> <execution> <goals> <goal>build</goal> </goals> </execution> </executions> </plugin> </build> </project> There’s typically more in a Quarkus POM, but I’ve stripped this down to the bare minimum. Next, our simple resource: SampleResource.java import javax.annotation.security.RolesAllowed; import javax.ws.rs.GET; import javax.ws.rs.Path; @Path("/sample") public class SampleResource { @GET @Path("admin") @RolesAllowed("admin") public String admin() { return "admin"; } @GET @Path("user") @RolesAllowed("user") public String user() { return "user"; } } Before we can start the app, we need to configure the OIDC support: application.properties quarkus.oidc.auth-server-url=$\{OIDC_URL:https://localhost:8180/auth/realms/quarkus-demo} quarkus.oidc.client-id=$\{OIDC_CLIENT_ID:backend-service} quarkus.oidc.credentials.secret=$\{OIDC_SECRET:51ebd5dc-5f2e-403c-be60-60fed3a75c47} We are now ready, or so we might think, to run our project: mvn compile quarkus:dev. Assuming you have Keycloak running on localhost but haven’t configured it, you should see an error like this: Caused by: io.vertx.core.impl.NoStackTraceThrowable: Not Found: {"error":"Realm does not exist"} Since we can’t run our app just yet, let’s configure Keycloak. Keycloak Create the realm For a more complete Getting Started, you can visit the Keycloak docs[https://www.keycloak.org/getting-started/getting-started-zip]. For our purposes, we’ll be brief: Download the latest version of Keycloak Extract the zip Start Keycloak with a port offset to avoid conflicts with our application: $KEYCLOAK_DIR/bin/standalone.sh -Djboss.socket.binding.port-offset=100 Create an admin user: http://localhost:8180 User: admin Password: admin Log on to the admin console by clicking on the Administration Console link Add a realm Move your mouse over Master in the left nav bar Click Add Realm Click Select File Navigate to and select quarkus-realm.json that we downloaded above Set the realm name to quarkus-demo Click Create We now have a realm for our demo, so next we need to configure the roles and add a user. Configure roles and users Ordinarily, we would need to add these, but since we imported a realm, that work has been done for us. To verify: Make sure the realm quarkus-demo is selected at the top the left nav bar. Click Roles in the nav bar In the list, you should see admin and user as well as a few others. Similarly, we don’t need to add users, as the import handled that for us. To verify that: Click Users under the Manage section in the nav bar In the list, you should see admin, alice`, and jdoe To verify admin Click the UUID in the ID column Click the Role Mappings tab Verify that admin and user are listed under Assigned Roles Let’s change the password Click the Credentials tab Enter "password" in the Password and Password Confirmation fields Set Temporary to "Off" Click Reset Password To view alice 's roles Click the Users nav bar link to return to the user list Click the UUID in the ID column for alice Click the Role Mapping tab Verify that only user is listed under Assigned Roles Change the password for alice as we did above. Configure the client We have one last step, configuring the client: Click Clients in the left nav bar Click backend-service in the table Click the Credentials tab Click the Regenerate Secret button Copy the new value in the Secret field and update quarkus.oidc.credentials.secret in application.properties Manually test the application With our realm configured, we’re ready to test our application: $ mvn compile quarkus:dev ... INFO [io.quarkus] (Quarkus Main Thread) quarkus-keycloak-wiremock 1.0-SNAPSHOT on JVM (powered by Quarkus 1.11.3.Final) started in 2.806s. Listening on: http://localhost:8080 And in another console (I’m using httpie here, btw): $ http --form \ --auth backend-service:51ebd5dc-5f2e-403c-be60-60fed3a75c47 \ :8180/auth/realms/quarkus-demo/protocol/openid-connect/token \ 'Content-Type:application/x-www-form-urlencoded' \ username=alice \ password=alice \ grant_type: password That gets a not-small JSON response, but we only want a part, so we can use the JSON query tool, jq, to help us extract the value: $ export TOKEN=`http --form \ --auth backend-service:51ebd5dc-5f2e-403c-be60-60fed3a75c47\ :8180/auth/realms/quarkus-demo/protocol/openid-connect/token \ 'Content-Type:application/x-www-form-urlencoded' \ username=alice \ password=password \ grant_type: password | jq --raw-output '.access_token'` $ echo $TOKEN eyJhbGciOiJSUzI1Ni.... Let’s try accessing the application now, first without a token, and then hitting each restricted endpoint: $ http :8080/sample/user HTTP/1.1 401 Unauthorized Content-Length: 0 $ http :8080/sample/admin "Authorization:Bearer $TOKEN" HTTP/1.1 403 Forbidden Content-Length: 0 $ http :8080/sample/user "Authorization:Bearer $TOKEN" HTTP/1.1 200 OK Content-Length: 4 Content-Type: application/octet-stream user So we see unauthenticated users rejected, unauthorized users rejected, and authorized users allowed, exactly as expected. Let’s check an admin user: $ export TOKEN=`http --form \ --auth backend-service:51ebd5dc-5f2e-403c-be60-60fed3a75c47\ :8180/auth/realms/quarkus-demo/protocol/openid-connect/token \ 'Content-Type:application/x-www-form-urlencoded' \ username=admin \ password=password \ grant_type: password | jq --raw-output '.access_token'` $ http :8080/sample/admin "Authorization:Bearer $TOKEN" HTTP/1.1 200 OK Content-Length: 5 Content-Type: application/octet-stream admin $ http :8080/sample/user "Authorization:Bearer $TOKEN" HTTP/1.1 200 OK Content-Length: 4 Content-Type: application/octet-stream user We’ve manually tested the app, but that doesn’t scale, so let’s take a look at how to test this simple application programmatically. Testing Part of the trick in testing an OIDC-secured apps can be tricky. Given how the token is verified behind the scenes, intercepting those calls can be difficult. Fortunately, WireMock handles that for us. Setting up the project is easy. Here, we’re adding JUnit5, WireMock, and some supporting libraries: pom.xml <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.18.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.github.tomakehurst</groupId> <artifactId>wiremock-jre8</artifactId> <version>2.26.3</version> <scope>test</scope> </dependency> <dependency> <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> <version>8.20</version> <scope>test</scope> </dependency> The test itself is also pretty simple: SampleResourceTest.java @QuarkusTest @QuarkusTestResource(MockAuthorizationServer.class) public class SampleResourceTest { @Test public void testUserAsUser() { RestAssured.given() .contentType("application/json") .auth() .oauth2(generateJWT("user")) .get("/sample/user") .then() .statusCode(200); } // ... private String generateJWT(String role) { // Prepare JWT with claims set SignedJWT signedJWT = new SignedJWT( new JWSHeader.Builder(JWSAlgorithm.RS256) .keyID(MockAuthorizationServer.keyPair.getKeyID()) .type(JOSEObjectType.JWT) .build(), new JWTClaimsSet.Builder() .subject("backend-service") .issuer("https://wiremock") .claim( "realm_access", new JWTClaimsSet.Builder() .claim("roles", Arrays.asList(role)) .build() .toJSONObject() ) .claim("scope", "openid email profile") .expirationTime(new Date(new Date().getTime() + 60 * 1000)) .build() ); // Compute the RSA signature try { signedJWT.sign(new RSASSASigner(MockAuthorizationServer.keyPair.toRSAKey())); } catch (JOSEException e) { throw new RuntimeException(e); } return signedJWT.serialize(); } Using REST Assured, we simply submit a request to server. The magic starts with the call to generateJWT(). In this method, we create a signed JWT using the key pair from our mock authorization server (which we’ll look at next), we sign the key, and return it. REST Assured passes this as part of the request, which Quarkus will extract and pass to the authorization server to validate. So what does the mock authorization server look like? MockAuthorizationServer.java public class MockAuthorizationServer implements QuarkusTestResourceLifecycleManager { private WireMockServer wireMockServer; public static RSAKey keyPair; static { try { keyPair = new RSAKeyGenerator(2048) .keyID("123") .keyUse(KeyUse.SIGNATURE) .generate(); } catch (JOSEException e) { e.printStackTrace(); } } @Override public Map<String, String> start() { wireMockServer = new WireMockServer(); wireMockServer.start(); postStubMapping(oidcConfigurationStub()); postStubMapping(publicKeysStub(keyPair.toPublicJWK().toJSONString())); Map<String,String> props = new HashMap<>(); props.put("quarkus.oidc.auth-server-url", wireMockServer.baseUrl() + "/mock-server"); props.put("wiremock.url", wireMockServer.baseUrl()); return props; } @Override public void stop() { if (wireMockServer != null) { wireMockServer.stop(); } } private ResponseBody<?> postStubMapping(String request) { RestAssured.baseURI = wireMockServer.baseUrl(); return RestAssured.given() .body(request) .post("/__admin/mappings") .then() .statusCode(Response.Status.CREATED.getStatusCode()) .extract() .response() .body(); } private String oidcConfigurationStub() { return readFile("/oidcconfig.json") .replace("$baseUrl", wireMockServer.baseUrl()); } private String publicKeysStub(String keys) { return readFile("/publickey.json") .replace("$keys", keys); } private String readFile(String fileName) { return new Scanner(getClass() .getResourceAsStream(fileName), "UTF-8") .useDelimiter("\\A") .next(); } } There’s a lot going on here, and I’m not going to pretend to be an expert. In effect, we’re setting up a mock server, configuring two endpoints, defined in oidcconfig.json and publickey.json, and those files look like this: oidcconfig.json { "name": "oidc_configuration", "request": { "method": "GET", "url": "/mock-server/.well-known/openid-configuration" }, "response": { "status": 200, "headers": { "Content-Type": "application/json;charset=UTF-8" }, "jsonBody": { "issuer": "$baseUrl/mock-server", "authorization_endpoint": "$baseUrl/v1/authorize", "token_endpoint": "$baseUrl/v1/token", "userinfo_endpoint": "$baseUrl/v1/userinfo", "registration_endpoint": "$baseUrl/v1/clients", "jwks_uri": "$baseUrl/v1/keys", "response_types_supported": ["code", "id_token", "code id_token", "code token", "id_token token", "code id_token token"], "response_modes_supported": ["query", "fragment", "form_post", "okta_post_message"], "grant_types_supported": ["authorization_code", "implicit", "refresh_token", "password"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["RS256"], "scopes_supported": ["sms", "openid", "profile", "email", "address", "phone", "offline_access"], "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"], "claims_supported": ["iss", "ver", "sub", "aud", "iat", "exp", "jti", "auth_time", "amr", "idp", "nonce", "name", "nickname", "preferred_username", "given_name", "middle_name", "family_name", "email", "email_verified", "profile", "zoneinfo", "locale", "address", "phone_number", "picture", "website", "gender", "birthdate", "updated_at", "at_hash", "c_hash"], "code_challenge_methods_supported": ["S256"], "introspection_endpoint": "$baseUrl/v1/introspect", "introspection_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"], "revocation_endpoint": "$baseUrl/v1/revoke", "revocation_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "client_secret_jwt", "private_key_jwt", "none"], "end_session_endpoint": "$baseUrl/v1/logout", "request_parameter_supported": true, "request_object_signing_alg_values_supported": ["HS256", "HS384", "HS512", "RS256", "RS384", "RS512", "ES256", "ES384", "ES512"] } } } publickey.json { "name": "public_keys_stub", "request": { "method": "GET", "url": "/v1/keys" }, "response": { "status": 200, "headers": { "Content-Type": "application/json;charset=UTF-8" }, "jsonBody": { "keys": [ $keys ] } } } These are basically mock objects, but representing requests. When a request for request.url comes in, WireMock returns response. Before passing the values to WireMock, we do a simple string replace to configure the responses to look how they should for a given request. We tie, so to speak, the Quarkus test to our MockAuthorizatioServer (which is a QuarkusTestResourceLifecycleManager) via the @QuarkusTestResource annotation on our test class. All that’s left is to run it. And there you have it. A complete, albeit absurdly simple, Quarkus application, secured with OIDC via Keycloak, and tested with WireMock. It’s a simple example, but it’s a working one, so hopefully it will be enough to get you started. If you find any interesting tips or tricks, be sure to drop a comment below! You can find the full source for the project here. ### [Merry Christmas, 2020](/2020/merry-christmas-2020/) Merry Christmas! After what has been a tough year, my prayer is that this Christmas season will be relaxing and refreshing for us all. To help celebrate the season — I hope — I’ve embedded my church’s Christmas program, Christmas Under the Arches. My prayer is that it encourages you all and helps you focus on the Reason we celebrate. :) ### [Java 15: New and Notable](/2020/java-15-new-and-notable/) JDK 15 hit General Availability today. While I spend most of my time in Kotlin these days, I do keep a close on Java, as it still has a special place in my heart, so I thought I’d make a quick post highlighting some of its new features. :) There are quite a few changes in the release, so I’ll list all of them, but focus on the ones I think most developers will find more interesting. The Complete List If you look at the project page, you will see a list of all the JEPs (JDK Enhancement Propsals). I’ll save you a click and reproduce that list here: 339: Edwards-Curve Digital Signature Algorithm (EdDSA) 360: Sealed Classes (Preview) 371: Hidden Classes 372: Remove the Nashorn JavaScript Engine 373: Reimplement the Legacy DatagramSocket API 374: Disable and Deprecate Biased Locking 375: Pattern Matching for instanceof (Second Preview) 377: ZGC: A Scalable Low-Latency Garbage Collector 378: Text Blocks 379: Shenandoah: A Low-Pause-Time Garbage Collector 381: Remove the Solaris and SPARC Ports 383: Foreign-Memory Access API (Second Incubator) 384: Records (Second Preview) 385: Deprecate RMI Activation for Removal General Notes There are some pretty techincal changes here (it seems to me) that most people won’t care about. If you’re into crypto, the EdDSA change might be of interest,. If you’re performance-sensitive, ZGC will likely pique your interest, and if you’re a framework developer, hidden classes sound pretty awesome. Solaris, RMI, and Javascript users, though, may be in for a slight disappointment, but these changes were telegraphed long ago, so they shouldn’t come as a surprise. For my money, the most interesting (read as: applicable to me) are Sealed classes Pattern matching instanceof Text blocks Records Let’s take a super quick looks. Sealed Classes There’s a good chance that at some point in your career, you’ve needed to define a hierarchy of classes and control where it can be extended. In languages like Kotlin, there is the sealed modifier that prevents the class from being extended without permission, so to speak. In Java however, you’re carefully curated list of system status codes, say, can be extended willy nill by any and all. Until now. the new feature, for those not familiar with the concept, allows the developer to "seal" a class, preventing its extension by all except a special few. In it’s simplest form, it might look like this: abstract sealed class Shape { abstract public draw(); } final class Square extends Shape { public draw() { } } final class Circle extends Shape { public draw() { } } In this example, Shape is abstract (though it need not be), and there are only two available shapes: Square and Circle. In this example, all three classes are declared in the same file, but, unlike, say, Kotlin, that need not be the case. If your classes are complex, have a lot of code, etc., and it would be better from a maintainability perspective, say, to have them in separate files, the compiler will let you do that, but you have to tell it which classes are allowed to participate: public abstract sealed class Shape permits fully.qualified.class.Square, fully.qualified.class.in.another.package.Circle { ... } Interfaces can also be sealed, with all of the same rules applying. Pattern-matching instanceof (Preview feature) For years, we’ve used instanceof to test the type of a variable, and for years, immediately after, we’ve type-casted that variable so we can use it: if (foo instanceof Interface1) { ((Interface1)foo).someMethod(); } Having to type (har har) twice was a bit annoying. JDK 15 brings a new syntax that lets us reduce that: if (foo instanceof Interface1 f) { f.someMethod(); } else { f.someOtherMethod(); // compiler error } Notice that we can declare a variable after the instanceof check that we can then use in the true branch of the if. The variable is not available in the else. This does not currently work in a switch statement, but that change is expected to come as well. This is only a preview feature so we can kick its tires, so use it with caution. Text blocks One of the things I’ve loved about Kotlin is the ability to write multi-line strings and let the compiler do the hardwork for me. For example. val foo = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus finibus velit dictum lacinia. """.trimIndent() This allows us to write a text block, spanning lines, and the system does the work for us to make a single, properly formatted string. In Java, that might look like String foo = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus\n" + "finibus velit dictum lacinia."; JDK 15 allows this: String foo = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus luctus finibus velit dictum lacinia. """; Very neat and clean. Records Finally, we come to records.In a nutshell, Records, a new kind of class on the JVM, allow us to declare an new, immutable type primarily intended to carry data in a _very_concise manner. Take this example from the JEP: // The old way class Point { private final int x; private final int y; Point(int x, int y) { this.x = x; this.y = y; } int x() { return x; } int y() { return y; } public boolean equals(Object o) { if (!(o instanceof Point)) return false; Point other = (Point) o; return other.x == x && other.y = y; } public int hashCode() { return Objects.hash(x, y); } public String toString() { return String.format("Point[x=%d, y=%d]", x, y); } } // The new way record Point(int x, int y) { } A huge improvement. The eagle-eyed may notice that the record definition is missing some methods. That is because, for record classes, the compiler generates equals, hashCode, and toString for you. It also generates getters and setters as well. While the JEP officially states that this isn’t the opening salvo of a War on Boilerplate, it’s at least a nice test shot. :P Conclusion There is, of course, more in the release than what I’ve discussed here, and you may find other bits more interesting, but these are the things that I’m most excited about. You can download it here and read the official release notes here. Congrats to the entire JDK team! ### [Writing CLIs with Spring Boot and JCommander](/2020/writing-clis-with-spring-boot-and-jcommander/) I was recently asked to convert a Spring Boot-based "CLI" to a real CLI utility. It was actually just a normal Spring Boot application with REST endpoints that we’d hit with curl. Pretty ugly. After a few frustrating hours, I finally settled on a solution that seems to work pretty well for us. It uses Spring Boot, of course, as that’s our library of choice, plus JCommander for the argument handling. This is a pared-down example of how the application is structured. And because I care about of each you deeply, I’ll present it in Java AND Kotlin. :) For those of you in a hurry, you can get the complete code in my GitHub repo. Everyone else, feel free to read along. Setting up Maven The first step will be setting up your Maven POM (If you’re using Gradle, I’m sorry. I’m already doing two languages. You can figure that part out on your own. :). We can start with this: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> </parent> <properties> <maven.compiler.target>11</maven.compiler.target> <maven.compiler.source>11</maven.compiler.source> </properties> <groupId>com.steeplesoft.spring-cli-app</groupId> <artifactId>spring-cli-app-master</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>spring-cli-app-java</module> <module>spring-cli-app-kotlin</module> </modules> <dependencies> <dependency> <groupId>com.beust</groupId> <artifactId>jcommander</artifactId> <version>1.78</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> </plugin> </plugins> </build> </project> While the project I was modifying had a lot of existing Spring beans, including some JPA entities and repositories, this simple project does not, and I didn’t feel the added complexity helped any, so I went with simple. To bring in the Spring dependencies, then, I declared a dependency on org.springframework.boot:spring-boot-starter. If you are using, say, JPA, then feel free use org.springframework.boot:spring-boot-starter-data-jpa or whatever else may be appropriate. Note also the declaration of a parent. It does a lot of work for you, so don’t skip it. :) For Java, there’s no additional POM work required. In my multi-module setup, the POM is very basic and mostly just refers to the POM above as its parent. The Kotlin POM is a bit more involved, but it’s just configuring the kotlin-maven-plugin. If you need help with that, check out the official docs. With Maven configured, we’re ready to start writing our commands. Let’s start with writing the application’s entry point. Spring Boot, while most people probably think of it solely as a REST microservice framework, does actually come with built-in support for command line utilities via the CommandLineRunner interface. Our @SpringBootApplication starts out looking like this: Java @SpringBootApplication public class SpringBootCliApplication implements CommandLineRunner { @Override public void run(String... args) { } public static void main(String[] args) { SpringApplication.run(SpringBootCliApplication.class, args); } } Kotlin @SpringBootApplication class SpringBootCliApplication(val commands: List<Command>) : CommandLineRunner { override fun run(vararg args: String?) { } } fun main(args: Array<String>) { runApplication<SpringBootCliApplication>(*args) } You can compile and run that now, but it’s going to be awfully boring. Adding commands When we start defining commands, which we’re going to do right now, we’re immediately hit with two concerns: How do we define them? and How do we find them? Defining Commands JCommander lets us define commands using simple classes, so we’ll create a very simple command, ExampleCommand, that takes one parameter: Java @Parameters(commandNames = ExampleCommand.COMMAND_NAME, commandDescription = "Example command") public class ExampleCommand implements Command { public static final String COMMAND_NAME = "example"; @Parameter(names = "--example", description = "Example parameter") private String example; @Override public String commandName() { return COMMAND_NAME; } @Override public void run() { System.out.println("You ran the command " + COMMAND_NAME + " with the parameter --example set to " + example); } } Kotlin @Parameters(commandNames = [ExampleCommand.COMMAND_NAME], commandDescription = "Example command") class ExampleCommand : Command { @Parameter(names = ["--example"], description = "Example parameter") private var example: String? = null override fun commandName(): String { return COMMAND_NAME } override fun run() { println("You ran the command $COMMAND_NAME with the parameter --example set to $example") } companion object { const val COMMAND_NAME = "example" } } You’ll see a bit of extra ceremony in this (the public static final String) than is strictly necessary, but you will see why in a moment. The first thing of important to note is the @Parameters annotation on the class. I’m not a JCommander expert, but I get the sense that the reason we’re using that annotation rather than, say, the not-real @Command annotation is that we’re technically building one "command", and just defining here a sub-command, or a parameter, if you will, that refines what actions an invocation will perform. Total guess there, but that’s certainly the annotation you need. At any rate, inside the class, we define an actual parameter we want to support, --example. It’s an optional String. You can define as many options as you want, and JCommander has very robust support for just about anything you would want to do, it seems. Finally, we have a run method (or function for all you Kotlin folks!) that does the real work. That’s not a JCommander requirement, but is something I built into the solution I’m showing here. Before we take a look at that, let’s find out how to find the commands. We do that by leaning on Spring. Finding Commands Since we’re suing Spring, we’re going to let Spring do as much of the work as we can. This is especially helpful if you’re injecting repositories or other Spring beans. The integration is very natural: we simply annotate the class with @Component: Java @Component @Parameters(commandNames = ExampleCommand.COMMAND_NAME, commandDescription = "Example command") public class ExampleCommand { // ... } Kotlin @Component @Parameters(commandNames = [ExampleCommand.COMMAND_NAME], commandDescription = "Example command") class ExampleCommand : Command { // ... } When the Spring ApplicationContext starts up, our command is found and registered in Spring’s metadata. All we have to do now is ask for it: Java @SpringBootApplication public class SpringBootCliApplication implements CommandLineRunner { @Autowired private List<Command> commands; @Override public void run(String... args) { // ... } // ... } Kotlin @SpringBootApplication class SpringBootCliApplication(val commands: List<Command>) : CommandLineRunner { override fun run(vararg args: String?) { // ... } } When our Application starts, Spring injects a list of any Command objects it finds. But what is that? Java public interface Command { String commandName(); void run(); } Kotlin interface Command { fun commandName() : String fun run() } It’s a very simple interface that provides a way to find out what it represents, and then to do the work. Armed with that, we can now build our JCommander objects: Java @Override public void run(String... args) { JCommander.Builder builder = JCommander.newBuilder() // 1 .programName("spring-boot-cli"); commands.forEach((c) -> builder.addCommand(c)); // 2 JCommander jc = builder.build(); jc.parse(args); // 3 Optional<Command> command = commands.stream() // 4 .filter(c -> c.commandName().equals(jc.getParsedCommand())) .findFirst(); if (command.isPresent()) { // 5 command.get().run(); } else { jc.usage(); // 6 } } Kotlin override fun run(vararg args: String?) { val builder = JCommander.newBuilder() // 1 .programName("spring-boot-cli") commands.forEach { // 2 builder.addCommand(it.commandName(), it) } val jc = builder.build(); jc.parse(*args) // 3 val command = commands // 4 .firstOrNull { it.commandName() == jc.parsedCommand } if (command != null) { // 5 command.run() } else { jc.usage() // 6 } } This isn’t terribly complex, but let’s step through it: We create a JCommander.Builder instance, and start by giving our command a name, spring-boot-cli. We iterate through the injected list of Command instances, calling builder.addCommand() to register it with JCommander. Once we’ve finished configuring and building our JCommander instance, we need to parse the command line arguments Now we need to find the command the user requested. We do that by iterating over our list of commands again, comparing Command.commandName() with the value returned by jc.getParsedCommand(). We’ll either get a Command instance, or an empty Optional If we have found a Command, we call its run method/function. JCommander takes care of injecting the command line options/parameters that have been defined, so by the time control enters run(), we’re ready to do our work. On the other hand, if no Command is found, we ask JCommander to print a usage message, which it generates for us using the @Parameter and @Parameters annotations. Running the commands We should be ready to build and run these now: $ mvn install ... $ java -jar spring-cli-app-java/target/spring-cli-app-java-1.0-SNAPSHOT.jar Usage: spring-boot-cli [command] [command options] Commands: example Example command Usage: example [options] Options: --example Example parameter $ java -jar spring-cli-app-kotlin/target/spring-cli-app-kotlin-1.0-SNAPSHOT.jar Usage: spring-boot-cli [command] [command options] Commands: example Example command Usage: example [options] Options: --example Example parameter They look remarkable similar, don’t they? :) Here’s an example with setting a parameter: $ java -jar spring-cli-app-kotlin/target/spring-cli-app-kotlin-1.0-SNAPSHOT.jar example --example 'This is a Spring Boot cli!' You ran the command example with the parameter --example set to This is a Spring Boot cli! Adding more commands Remember how I kinda made a big deal about finding commands and injecting lists? With this setup, it’s super easy. Barely an inconvience: Java @Component @Parameters(commandNames = Example2Command.COMMAND_NAME, commandDescription = "Example command #2") public class Example2Command implements Command { public static final String COMMAND_NAME = "something-else"; @Override public String commandName() { return COMMAND_NAME; } @Override public void run() { System.out.println("You ran something else!"); } } Kotlin @Component @Parameters(commandNames = [Example2Command.COMMAND_NAME], commandDescription = "Example command #2") class Example2Command : Command { override fun commandName(): String { return COMMAND_NAME } override fun run() { println("You ran something else!") } companion object { const val COMMAND_NAME = "something-else" } } Making only that change, if we repackage our utility, and rerun the usage request, we get: $java -jar spring-cli-app-java/target/spring-cli-app-java-1.0-SNAPSHOT.jar Usage: spring-boot-cli [command] [command options] Commands: example Example command Usage: example [options] Options: --example Example parameter something-else Example command #2 Usage: something-else The Kotlin version looks exactly the same. Trust me. :) One final note. Spring Boot can be pretty chatty in the logs/console, so I add this to my application.properties: src/main/resource/application.properties spring.main.banner-mode=off logging.level.root=ERROR Voila! That’s it. Any real CLI utility will obviously do more, but that should get you the plumbing you need. Just @Autowire any Spring Beans you need, and you’re off to the races! ### [Hands-free Flyway and jOOQ](/2020/hands-free-flyway-and-jooq/) Recently, I started working on a new project and I wanted to give Jooq a go. I also wanted to integrate Flyway: I wanted jOOQ to generate its various classes based off the database schema, and I want to Flyway to create that schema. That’s all easy enough, but I’m resisting, right now, committing the generated classes to source control (to avoid the churn and additional maintenance), so how do I make that happen with as little work as possible? How do I make it work in a CI environment? Thanks to Maven, the answer is lots and lots of XML. :) Let’s take a look…​ Adding the dependencies To add jOOQ and Flyway to a project, you need these dependencies: <properties> <jooq.version>3.13.1</jooq.version> <flyway.version>6.4.2</flyway.version> </properties> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>$\{jooq.version}</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-meta</artifactId> <version>$\{jooq.version}</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-codegen</artifactId> <version>$\{jooq.version}</version> </dependency> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> <version>$\{flyway.version}</version> </dependency> This will enable the use of the jOOQ libraries in your code, as well as for runtime Flyway migrations. The mechanics of both of those are outside the scope of this post, so, if you need help there, please see the respective project websites. Setting up build-time Flyway The next step is setting up the build to run the jOOQ generator. For there to be anything to generate, we need Flyway to generate the schema. For this project, I’m using H2 for tests, so I’m going to configure Maven and Flyway create an H2 database: <properties> <flyway.version>6.4.2</flyway.version> <flyway.url>jdbc:h2:file:$\{project.build.directory}/testdb</flyway.url> <flyway.user>sa</flyway.user> <flyway.password>sa</flyway.password> <h2.version>1.4.200</h2.version> </properties> <plugin> <groupId>org.flywaydb</groupId> <artifactId>flyway-maven-plugin</artifactId> <version>$\{flyway.version}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>migrate</goal> </goals> </execution> </executions> <configuration> <locations> <location>filesystem:src/main/resources/db/migration</location> </locations> </configuration> <dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>$\{h2.version}</version> </dependency> </dependencies> </plugin> This tells Flyway to create a database called testdb in the build directory, then generate the schema using the production migrate files in the source directory. Generate the jOOQ classes With the schema prepared, we can generate sources: <properties> <jooq.outputdir>target/generated-sources/jooq</jooq.outputdir> </properties> <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <version>$\{jooq.version}</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>generate</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>$\{h2.version}</version> </dependency> </dependencies> <configuration> <jdbc> <url>$\{flyway.url}</url> <user>$\{flyway.user}</user> <password>$\{flyway.password}</password> </jdbc> <generator> <database> <includes>.*</includes> <excludes> Flyway.* | All.* | SchemaVersion.* </excludes> <inputSchema>PUBLIC</inputSchema> <outputSchema>public</outputSchema> <properties> <property> <key>dialect</key> <value>H2</value> </property> </properties> </database> <target> <packageName>com.example.backend.models.jooq</packageName> <directory>$\{jooq.outputdir}</directory> </target> </generator> </configuration> </plugin> Now, when we run mvn compile, Flyway creates an H2 database, and builds the schema, then jOOQ generates all of its files in target/generated-sources/jooq. Adding generated classes to the build All of that’s pretty cool, until…​ you try to use those classes in your project. Neither Maven nor your IDE will be able to see them just yet. There’s one more large block of XML we need to add: <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>add-source</goal> </goals> <configuration> <sources> <source>$\{jooq.outputdir}</source> </sources> </configuration> </execution> </executions> </plugin> Using the Build Helper plugin, we add jOOQ’s output directory to the build, and we’re in business. Closing note One last note: if you make changes to the Flyway migrate file, you’ll need to execute a mvn clean to remove the test database and any Flyway checksum caches. If you don’t, your build will fail. All of this does add a bit to the build process, but, for me, so far it’s justified. As I make changes to the schema, my jOOQ classes are automatically recreated, and the test database is brought up to date. ### [Building Maps in Kotlin](/2020/building-maps-in-kotlin/) Over the years, I’ve found myself processing a set of data and storing it in a Map, say, something like Map<Long, List<String>> (think something like a list of Room objects, keyed by a building id). I have found myself writing it something like this (in non-idiomatic Kotlin): val foo = map.get(key) if (foo == null) { foo = MutableList<String>() map.put(key, foo) } foo.add(bar) Fortunately, the Kotlin standard library has a better way: map.getOrPut(key) { mutableListOf() } .add(bar) If key is not found, the lambda is run, adding the result to Map and return to use the value, new or otherwise, to which we add bar. Much more concise. :) Generally speaking, any time you can let the language/compiler do the work for you, you’re going to be better off. ### [Custom Methods in Spring Repositories](/2020/custom-methods-in-spring-repositories/) One of the great things about Spring Data Repositories is that they provide a number of query methods out of the box, with the ability to add additional queries simply by adding carefully named methods to the interface, and Spring generates the actual implementation for you. Sometimes, though, you do need to color outside the lines a bit. Thankfully, Spring allows us to do this. You just have to ask it nicely. Here’s now. For the sake of space, I’m going to assume you know how to create a simple Spring Data repository, so I’ll leave out the details. That said, we’ll start with a basic repository: interface FooRepository : CrudRepository<Foo, Long> Let’s say, for demonstration purposes, that we need to add a method that requires a complex query that can’t be modeled, easily, cleanly, or otherwise, using the required semantics. You can, of course, specify the query using @Query rather than letting Spring derive it, but sometimes not even that’s enough. You have some really complex logic you need to implement to make the query work, so you need to write it explicitly, let’s say getSomeFoosBasedOnComplexLogic. Nice, huh? Let’s start by defining an additional interface: interface FooRepositoryCustom { fun getSomeFoosBasedOnComplexLogic(oaram1 Int, param2 String) : List<Foo> } Having defined the interface, we need to define its implementation: class FooRepositoryCustomImpl(private val entityManager : EntityManager) : FooRepositoryCustom { fun getSomeFoosBasedOnComplexLogic(param1 Int, param2 String) : List<Foo> { // Do some JPA query here, but we'll return dummy data return listOf(Foo("bar"), Foo("baz")) } } Now we need to revisit FooRepository and update it: interface FooRepository : CrudRepository<Foo, Long>, FooRepositoryCustom When Spring creates the FooRepository instance, it will do all the magic required to wire in FooRepositoryCustomImpl as part of the resulting class. How I don’t know, to be honest (but I’m guessing it delegates from generated code), but it’s not too terribly important at this point. What is important is that we can call this custom method like any other. For example: @CrossOrigin @RestController @RequestMapping("/dummy") class DummyController(private val repo : FooRepository) { @GetMapping fun foo(): List<Foo> { return repo.getSomeFoosBasedOnComplexLogic() } } Hit that with your favorite client, and you should see, e.g., a nice JSON representation of a List<Foo>. See? Super easy once you know how to hold your mouth just right! ### [Restoring a Deleted Git Branch](/2020/restoring-a-deleted-git-branch/) Thanks to haste and some sloppy copy-and-paste, today I deleted the wrong remote Git branch. There’s nothing like learning in a panic, but that’s what happened. Here’s what I learned on how to fix that. While watching that all-important branch being deleted erroneously is a heart-stopping moment, as it turns out, restoring the deleted branch is Super Easy. Barely an Inconvenience. All you need to know the hash of the last commit to the branch. If you just deleted the branch, it’s even easier. When you delete branch, you should see something like this: Deleted branch super_important (was 15060e768). To github.com:yourcompany/super_secret_project.git - [deleted] super_important In this case, you have your hash: 15060e768 If you don’t still have that message available, you can use reflog: $ git reflog 15060e768 HEAD@\{0}: commit: Fix test 84a524673 HEAD@\{1}: commit: Really important work 7a2f75f1f HEAD@\{2}: commit: So much I forgot what I did f2a2afa24 HEAD@\{3}: commit: Added dependencies 224260b95 HEAD@\{4}: commit: Implement new knob 68ae60023 HEAD@\{5}: checkout: moving from foo to dev This is a little tricker, as you’ll need to find the hash of the last commit to the branch you want. In this contrived data, it’s right there at the top. Once you have that, you checkout out that hash, create a new branch (of the same name or different. Your call), then push to the remote repository. $ git checkout 15060e768 $ git checkout -b super_important $ git push origin super_important You can also shorthand that a bit: $ git checkout -b super_important 15060e768 $ git push origin super_important You should now see your branch in your remote repository. Take a deep breath. Crisis averted. :) ### [Best Advice I've Been Given: Check Your Ego](/2020/best-advice-i-ve-been-given-check-your-ego/) The Red Hat twitter account just asked this question: "Communities grow by uplifting others. What is one piece of advice you’d offer to a new developer? Reply below and then check out some advice from #RedHatter @somalley108." Here’s my input. As a general rule, if you’re writing software, you’re probably pretty intelligent. That intelligence, while important, of course, can also become a hindrance. For example, I’ve been told by coworkers, "You may write buggy code, but I don’t" and "We don’t need techincal oversight". I think both of those statements are patently false, and they — and others like them — always take me back to that advice from my first manager, Chris Anderson, gave me way back in 1997: Check your ego at the door. It’s really easy to walk in to a coding review, a design session, or one of a myriad of other meetings with your ideas and think they’re the best. It’s also really easy to overlook the fact that other people in that room are also pretty intelligent — maybe even more so (it happens), and that we all have blindspots and weaknesses. In my experience, and I’ve certainly been on both sides more than I care to admit, many conflicts in software development are ego-driven. There’s a difference between being passionate about something and being an arrogant jerk. The latter type does nobody any good, so check your ego. Go in humbly, and see what there is to learn from your coworkers, even if you’re more senior than they. With that mindset, everyone will come out a winner. ### [Dear MockK, Repeat After Me](/2020/dear-mockk-repeat-after-me/) The project I’m working on is using Mockk in the unit tests. It’s a great library that has made true unit testing so much easier. I ran into a problem, though, where I needed a method I was mocking to return the value it was receiving. To be more specific, we were passing an object to a Spring repository method that had been built inside the method to test, and, to test thoroughly, I needed to get to that object. Turns out, that’s pretty easy to do with Mockk. Let’s take a look…​ First, a clear set up. The code basically looks like something like this: @PostMapping("/foo") fun post(@RequestBody foo : Foo) : Bar { val bar = Bar() bar.prop1 = foo.prop1 bar.prop2 = calculatedValue(foo) var newBar = repository.save(bar) // Do some more work with newBar return newBar } For the purposes of the test, I don’t much care about the "Do some more work" part. I need the return value of repository.save(). I set up the test like this: @Test fun testCreateFoo() { val barSlot = slot<Bar>() every { repository.save(capture(barSlot)) } answers { barSlot.captured } val result = mockMvc.perform(MockMvcRequestBuilders .post("/foo") // ... val savedBar = gson.fromJson(result.response.contentAsString, Bar::class.java) assertThat(savedBar.prop2).isEqualTo(expectedValue) } The interesting part is the call to every. Using a CapturingSlot<T>, I instruct the system to capture the Bar that the method under test passes in, and I simply return it in the lambda I pass to answers. It is true that we don’t have access to the what the repository might do to the Bar instance (filling in related objects, etc.), but that’s OK. I just want to look at the value of prop2, and this lets me do that nice and neat. :) ### [Merry Christmas, 2019](/2019/merry-christmas-2019/) Merry Christmas! For God so loved the world, that He gave His only begotten Son, that whoever believes in Him shall not perish, but have eternal life. -- John 3:16 ### [Executable Kotlin Scripts](/2019/executable-kotlin-scripts/) A user in #kotlin on Freenode asked how to run a Kotlin script. While the Kotlin docs are pretty clear on how to do that, I thought I’d make a quick post to show how to make an easily executable Kotlin script. The first step is to name the file with a .kts extension: test.kts println("Hello, world!") You can then run it like this: $ kotlinc -script test.kts Hello, world! That’s pretty cool (and pretty quick on my laptop), but the command line is a bit cumbersome. Let’s fix that with two small changes. First, let’s add a shebang: test.kts #!/usr/bin/env -S kotlinc -script println("Hello, world!") Then we set the executable bit and run it: $ chmod +x test.kts $ ./test.kts Hello, world! Easy peasy. Now you a more powerful language in your shell scripting toolbox. Enjoy! ### [Testing Spring Repositories with Flyway](/2019/testing-spring-repositories-with-flyway/) With my recent job change, I’ve gotten a chance to use Spring Boot in anger a bit. It’s been fun, and I’ve learned a fair bit about the current state of Spring (I still love you, Jakarta EE!). One of my tasks involved adding a query method to a repository, and I wanted to make sure the query worked before I pushed it upstream. To do that confidently, of course, required a unit test. In this post, I’ll show how remarkably simple it is to test Spring Repositories using Flyway to set up schemas and test data. To start off the demo, I created a simple Spring Boot project using https://start.spring.io/#!type: maven-project&language=kotlin&platformVersion=2.2.2.RELEASE&packaging=jar&jvmVersion=1.8&groupId=com.steeplesoft&artifactId=spring-boot-repository-test-demo&name=spring-boot-repository-test-demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.steeplesoft.spring-boot-repository-test-demo&dependencies=data-jpa,flyway,h2,postgresql[Spring Intializr]. Opening that in my IDE, I needed to configure the database connection, which I did in src/main/resources/application.properties: spring.datasource.url=jdbc:postgresql://foo:5432/bar spring.datasource.username=spring spring.datasource.password=password spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto = validate In this case, the production configuration isn’t as interesting as the test config (since this demo doesn’t really do much in "production"). The test config is in src/test/resources/application.properties:` spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 spring.datasource.username=sa spring.datasource.password=sa spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto = none In production, we’re using Postgres, but in test, we’re using H2. Pretty simple. To set up Flyway, all you really need to do is add it to the classpath: <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> <version>6.0.8</version> </dependency> With that dependency in place, when the tests are run (or the application started), Flyway will automatically look for migration scripts on the classpath under db/migration. If you have no scripts, you will see a failure like this: ... Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.flywaydb.core.Flyway]: Factory method 'flyway' threw exception; nested exception is org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingException: Cannot find migration scripts in: [classpath:db/migration] (please add migration scripts or check your Flyway configuration) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE] ... 99 common frames omitted Caused by: org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingException: Cannot find migration scripts in: [classpath:db/migration] (please add migration scripts or check your Flyway configuration) at org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration.checkLocationExists(FlywayAutoConfiguration.java:166) ~[spring-boot-autoconfigure-2.2.2.RELEASE.jar:2.2.2.RELEASE] ... For our demo, we’ll create one migrate, src/main/resources/db/migration/V000__schema.sql: CREATE TABLE book ( id number primary key, title varchar2(255), author varchar2(255), description text, publish_date date ); When we run the test now, our schema is automatically created for us in H2, so we’re ready to "test": @ExtendWith(SpringExtension::class) @DataJpaTest class BookRepositoryTest { @Autowired private lateinit var repository: BookRepository @Test fun dataWasLoaded() { val books = repository.findAll() assertThat(books).hasSize(3) } } Note that we’re running under JUnit 5, so we use @ExtendWith(SpringExtension::class). If you’re using JUnit 4, then you’ll need to use @RunWith(SpringRunner::class). Either way, we annotate the class with @DataJpaTest to tell Spring what we’re testing, and we autowire in our Repository and test as normal. The first time we run this overly simple test, it will fail, as there’s no data in the database. To fix that, we can use a Flyway migrate to load our data. To make the example a bit more interesting, we’ll add it in a non-standard, as I found myself in that situation. The migrate (src/test/resources/testdata/V999__testdata.sql): INSERT INTO book (id, title, author, publish_date) VALUES (1, 'The Fellowship of the Ring', 'Tolkien, J.R.R.', '1952-07-29'); INSERT INTO book (id, title, author, publish_date) VALUES (2, 'The Two Towers', 'Tolkien, J.R.R.', '1954-11-11'); INSERT INTO book (id, title, author, publish_date) VALUES (3, 'The Return of the King', 'Tolkien, J.R.R.', '1955-10-20'); If we make no changes, Flyway won’t be able to find the file, so we have to update test/src/resource/application.properties: ... spring.flyway.locations=classpath:db/migration/,filesystem:../flyway/sql,classpath:testdata/ The value is a comma-delimited (don’t ask me why) of paths to search. Note that we have to prefix each with the type, either classpath or filesystem. In my real world case that drove this line of investigation, our migrates were actually outside of the module’s source directory (as part of a larger multi-module build), so I needed to specifiy a filesystem path, which, it turns out, is relative to the project directory when run like this. We also have to take care to add the default path, classpath:db/migration, or we’ll break thing. Finally, we add our somewhat arbitrary new path, and we’re ready to run our test again, which turn green. As it turns out, then, testing with Flyway is amazingly simple. Flyway’s also a great way to manage schema changes in your production application. If you’re not using Flyway (or testing your Spring Repositories), I hope this will be the encouragement — and information — you need to get started. ### [When Testing with a Different Database Chokes on Your DDL](/2019/when-testing-with-a-different-database-chokes-on-your-ddl/) I recently found myself writing a test that needed a database. Unfortunately, our testing database, H2, doesn’t support all of the features of our production database, PostgreSQL. This meant that the Flyway migrates used to manage the production database broke in the testing environment. The fix for this turned out to be pretty simple. To set the scenario, imagine you have this table: CREATE TABLE foo ( id bigint PRIMARY KEY, some_json JSONB ); The only thing interesting about this table is the jsonb column, but it’s that column that breaks when run under H2: SQL Error [50004] [HY004]: Unknown data type: "JSONB" The fix is a simple one-liner: CREATE domain IF NOT EXISTS jsonb AS character varying (8192); In my case, I added that to a Flyway migrate file, named in such a way that it ran before the problematic CREATE TABLE statement, and Bob’s…​uhhh.. my uncle! :) Hope that helps! ### [Easily Switching JDKs](/2019/easily-switching-jdks/) Development environments can get fairly complex, and making sure you’re using the right version of some library or another can be annoying on the best of days. I have a situation like that where my "day job" requires (still, and hopefully not for much longer) JDK 8, but my side projects, learning efforts, etc. can use a more modern version. Years ago, Charles Nutter shared a shell script he uses to switch JDKs. I’ve been happily using it, but I’ve made some minor tweaks, so I thought I’d share my version here in case it helps someone (and make it easier for me to find in the future ;). UPDATE: It seems the original author is Nick Sieger. Thanks to you as well, Nick, for a great little utility! The two primary changes in my script versus Charles' is that I try to set JDKS_ROOT if it’s not already set, and I try to filter out "false" JDK entries (where the Ubuntu packages, for example, seem to like to create symlinks). I have not tested these changes to make sure I haven’t broken MacOS support, however, so if you’re on a Mac and this doesn’t work correctly, please let me know. :) Without further ado: #!/bin/bash # # Provides a function that allows you to choose a JDK. Just set the environment # variable JDKS_ROOT to the directory containing multiple versions of the JDK # and the function will prompt you to select one. JAVA_HOME and PATH will be cleaned # up and set appropriately. # Usage: # Include in .profile or .bashrc or source at login to get 'pickjdk' command. # 'pickjdk' alone to bring up a menu of installed JDKs on OS X. Select one. # 'pickjdk <jdk number>' to immediately switch to one of those JDKs. _checkos() { if [ $(uname -s) = $1 ]; then return 0 else return 1 fi } if [ -z "$JDKS_ROOT" ] ; then if _checkos Linux ; then JDKS_ROOT=/usr/lib/jvm elif _checkos Darwin ; then JDKS_ROOT=/Library/Java/JavaVirtualMachines fi fi pickjdk() { if [ -z "$JDKS_ROOT" ]; then return 1 fi declare -a JDKS local n=1 jdk total_jdks choice=0 currjdk=$JAVA_HOME explicit_jdk for jdk in $JDKS_ROOT/[0-9a-z]*; do if [ ! -L $jdk -a -d $jdk -a -e $jdk/bin ]; then JDKNAMES[$n]="$(basename $jdk)" if _checkos Darwin ; then jdk=$jdk/Contents/Home fi if [ -z "$1" ]; then echo -n " $n) $\{JDKNAMES[$n]}" if [ $jdk = "$currjdk" ]; then echo " < CURRENT" else echo fi fi JDKS[$n]=$jdk total_jdks=$n n=$[ $n + 1 ] fi done if [ -z "$1" ]; then echo " $n) None" fi JDKS[$n]=None total_jdks=$n if [ $total_jdks -gt 1 ]; then if [ -z "$1" ]; then while [ -z "$\{JDKS[$choice]}" ]; do echo -n "Choose one of the above [1-$total_jdks]: " read choice done else choice=$1 fi fi if [ -z "$currjdk" ]; then currjdk=$(dirname $(dirname $(type -path java))) fi if [ $\{JDKS[$choice]} != None ]; then export JAVA_HOME=$\{JDKS[$choice]} else unset JAVA_HOME fi explicit_jdk= for jdk in $\{JDKS[*]}; do if [ "$currjdk" = "$jdk" ]; then explicit_jdk=$jdk break fi done if [ "$explicit_jdk" ]; then if [ -z "$JAVA_HOME" ]; then PATH=$(echo $PATH | sed "s|$explicit_jdk/bin:*||g") else PATH=$(echo $PATH | sed "s|$explicit_jdk|$JAVA_HOME|g") fi elif [ "$JAVA_HOME" ]; then PATH="$JAVA_HOME/bin:$PATH" fi echo "New JDK: $\{JDKNAMES[$choice]}" hash -r } To use this, add the following to your Bash profile: source /path/to/pickjdk.sh Restart your shell (or source the file directly), and you can do this: $ pickjdk 1) java-11-openjdk-amd64 < CURRENT 2) oracle-java8-jdk-amd64 3) None Choose one of the above [1-3]: Make your selection, and you’re all set. It’s awesome. ### [Java to Kotlin Conversion Question. And Answer.](/2019/java-to-kotlin-conversion-question-and-answer/) Recently, in the #kotlin channel on Freenode, a user asked a question about what was happening to his Java code when using IDEA’s convert-to-Kotlin functionality. He left before anyone had the time to answer, and while he likely doesn’t read my blog, I’m going to answer his question here anyway. :) Here is his (slightly edited) question: I use intellij idea to convert a java code to kotlin, but there’s something I don’t understand, https://paste.ubuntu.com/p/NNbRwmR4mG/ I don’t know why kotlin convert the second parameter in memory.subscribeToEvent which is a object to a lambda? and idea turn f(a,b) in java to f(a)(b) in kotlin auto currying? And, just in case the paste disappears, here are its contents: java: tts = new ALTextToSpeech(session); frontTactilSubscriptionId = 0; // Subscribe to FrontTactilTouched event, // create an EventCallback expecting a Float. frontTactilSubscriptionId = memory.subscribeToEvent( "FrontTactilTouched", new EventCallback<Float>() { @Override public void onEvent(Float arg0) throws InterruptedException, CallError { // 1 means the sensor has been pressed if (arg0 > 0) { tts.say("ouch!"); } } }); kotlin: tts = ALTextToSpeech(session) frontTactilSubscriptionId = 0 // Subscribe to FrontTactilTouched event, // create an EventCallback expecting a Float. frontTactilSubscriptionId = memory.subscribeToEvent( "FrontTactilTouched" ) { arg0 -> // 1 means the sensor has been pressed if (arg0 > 0) { tts.say("ouch!") } } To understand why the Kotlin code looks the way it does, it’s important to understand a bit about the Java code. Without knowing anything about the method memory.subscribeToEvent, it seems clear that it takes a String (perhaps an event name?), and a callback which is, of course, called when the event happens. Incidentally, and not important here, it seems to return a subscription ID, which I assume one can use to cancel the subscription. The interesting part of all of this is that second parameter, EventCallBack<T>. What the Java code is doing is creating an anonymous instance of the interface and passing it directly to the method. What’s interesting about the interface is that it is what is known as a Single Abstract Method interface, meaning it has…​ wait for it…​ only one abstract method. In Java, lambdas are actually implemented internally, if I recall correctly, as instances of SAMs, often done silently by the compiler. This code, then, could be written like this: frontTactilSubscriptionId = memory.subscribeToEvent( "FrontTactilTouched", (Float arg0) -> { if (arg0 > 0) { tts.say("ouch!"); } }); If memory serves, the compiler is smart enough to know that the method takes an EventCallback, and sees that the lambda requires a single Float, which happens to match the single abstract method of the interface, so this lambda-ized version of the code is magically converted to the non-lambda version above in the bytecode, and life moves on. Now, when we move to Kotlin, the converter code is also smart enough to recognize the SAM in the original Java code, so it converts that to a lambda. It goes a step further, though, and makes the code more idiomatic: in Kotlin, if the last parameter to a method is a lambda, the compiler will allow you to specify that outside the parenthesis in your calling code. This code, then: frontTactilSubscriptionId = memory.subscribeToEvent( "FrontTactilTouched", { arg0 -> // 1 means the sensor has been pressed if (arg0 > 0) { tts.say("ouch!") } ) } is functionally equivalent to this: frontTactilSubscriptionId = memory.subscribeToEvent("FrontTactilTouched") { arg0 -> // 1 means the sensor has been pressed if (arg0 > 0) { tts.say("ouch!") } } And there you go. That’s my take on what’s going with that conversion. I hope you find that helpful. And accurate. :) If I missed something, hit the comments below and let’s talk. ### [Getting started with Micronaut: Kotlin, JPA, and JWT](/2019/getting-started-with-micronaut-kotlin-jpa-and-jwt/) The Micronaut guides are really pretty good. So far, I’ve found just about everything I need. The biggest obstacle so far has been that, at times, the content was scattered across several guides and usually in the wrong language: I’m interested in Kotlin, but the guides seem to be mostly in Java or Groovy. This isn’t surprising, as budgets are limited, of course. What I would like to do here, then, is provide a small sample app, written in Kotlin, that demonstrates how to set up the project, configure and use JPA, and secure the app with JWT. Micronaut comes with a CLI that helps bootstrap a project, as well create various artifacts. So far, I’ve found the project creation to be the most useful, with the rest being less so. Your mileage may vary, of course. That said, let’s bootstrap the project: $ mn create-app -l kotlin -b maven --features=hibernate-jpa,security-jwt,jdbc-hikari,http-server jugdemo Once the script finishes, we’re ready to open the project in the IDE of your choice, so let’s do that now and make some build changes. These are mostly to update versions, but also to make some changes to the dependencies, especially around testing. pom.xml <properties> <exec.mainClass>com.steeplesoft.micronaut.Application</exec.mainClass> <junit.jupiter.version>5.4.0-RC2</junit.jupiter.version> <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget> <kotlinVersion>1.3.21</kotlinVersion> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <micronaut.version>1.0.4</micronaut.version> </properties> Replace all of the test dependencies with this block: pom.xml <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-inject-java</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut.test</groupId> <artifactId>micronaut-test-junit5</artifactId> <version>1.0.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>$\{junit.jupiter.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>$\{junit.jupiter.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupId>io.micronaut.test</groupId> <artifactId>micronaut-test-core</artifactId> <version>1.0.1</version> <scope>test</scope> </dependency> The Controller With our build setup, let’s create our first controller, AuthorController: AuthorContoller.kt import io.micronaut.http.HttpResponse import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Get import io.micronaut.security.annotation.Secured @Controller("/author") class AuthorController { @Get("/") fun index(): HttpResponse<String> { return HttpResponse.ok("author") } } This is a super dumb controller, but should work fine for our purposes. What do we do next? Write a test, of course. The Test Micronaut comes with a really nice testing framework that handles bootstrapping the server for us, and allowing us to inject interesting things. We likely won’t scratch the surface in this test, but I hope you’ll at least get a hint of how cool and easy it is to do: AuthorControllerTest import io.micronaut.context.ApplicationContext import io.micronaut.http.HttpHeaders import io.micronaut.http.HttpRequest import io.micronaut.http.HttpStatus import io.micronaut.http.client.RxStreamingHttpClient import io.micronaut.http.client.exceptions.HttpClientResponseException import io.micronaut.runtime.server.EmbeddedServer import io.micronaut.test.annotation.MicronautTest import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test @MicronautTest class AuthorControllerTest { @Inject @field:Client("/") lateinit var client : RxStreamingHttpClient @Test fun testIndex() { val request = HttpRequest.GET<String>("/author") assertEquals("author", client.toBlocking().exchange(request, String::class.java).body()) } } There is likely a better of way doing this, but, as best I can tell, this is a decent port of the Java test to Kotlin. If there’s a better way, you know where to find the comments section. :) We start by annotating the test with @Micronaut. This signals to JUnit that this is a…​ wait for it…​ Micronaut test, so we get some things done for us, like a running server. Once the server is started for us, we can also have a client inject for us, which we see here. An earlier version of the code used a companion object and started the server explicitly. As noted in the comments, this led to the server being started twice. The code has been updated accordingly. Our actual test is a pretty simple JUnit test: annotate the method, create the request, make the call, get the response body, and make an assertion. Unless you’ve typed something wrong, or you copied and pasted code and I copied into this post incorrectly, you should a green test suite. Kinda sweet, but very boring. Where’s the JPA? The JWT? Let’s see that now…​ Entity and Service To set up JPA, we need to configure it in application.yml: application.yml datasources: default: url: jdbc:h2:mem:jugdemo_database driverClassName: org.h2.Driver username: sa password: '' jpa: default: packages-to-scan: - 'com.steeplesoft.micronaut' properties: hibernate: hbm2ddl: auto: update show_sql: true We start by defining a datasource. Since we want this demo to be easy to setup and use, we’re going to use an in-memory H2 database, so we define the url, driver class, and the login credentials. Next, we need to configure JPA, so we tell the system what packages (which may not be strictly necessary), then enable hbm2ddl so our schema gets created automatically, and turn on SQL logging to help with debugging. With that setup, let’s define an entity. For our purpose here, we’re just going to define a User entity, as we’re just going to deal with JPA in the context of authentication: User.kt import io.micronaut.security.authentication.providers.UserState import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id import javax.persistence.SequenceGenerator import javax.persistence.Table @Entity @Table(name = "users") data class User(@Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_generator") @SequenceGenerator(name="user_generator", sequenceName = "user_seq") var id: Long? = null, val email : String? = null, val pass : String? = null) That’s probably a bit overwhelming, so I’ll give some time to read through that. Ready? Excellent. As you can see, it’s a simple Kotlin data class with three properties. We’ve annotated id so Hibernate/JPA will properly generate the primary key for us. We annotate the class, and we’re done with our model. For now. Our very simple data access service looks like this: UserService.kt import io.micronaut.aop.Around import io.micronaut.spring.tx.annotation.Transactional import javax.inject.Singleton import javax.persistence.EntityManager import javax.persistence.PersistenceContext @Singleton @Around class UserService(@PersistenceContext val entityManager: EntityManager) { @Transactional(readOnly = true) fun findUser(email : String) : User? { return try { entityManager.createQuery("SELECT u FROM User u WHERE email = :email", User::class.java) .setParameter("email", email) .singleResult } catch (e : Exception) { null } } } If you’re familiar with JPA, nothing here should be too unusual. We use @Singleton to signal to Micronaut that this is a managed class (you’ll have to forgive the Jakarta EE-isms peeking through. I just barely avoided calling it a managed bean. Oops. Looks like I did it anyway). The @Around annotation is, as best as I can tell, required to make the system honor the @Transactional annotations you see on the methods. Also note the constructor injection of the EntityManager. We’ll use that same approach to inject this service anywhere it’s needed. If you run your test now, you shouldn’t see much change except, perhaps, some extra logging where the persistence context is being initialized. The application, though, doesn’t do anything with it. Let’s fix that now by implementing security. Security Securing a Micronaut application seems pretty straightforward. You have at least a couple of options, session and JWT. Since we’re building a micro(ish)service, we should probably go full on hipster and use JWTs, right? I kid! They’re really cool, and Micronaut makes them super to use. Let’s start by updating the application config: micronaut: application: name: jugdemo security: enabled: true endpoints: login: enabled: true oauth: enabled: true token: jwt: enabled: true signatures: secret: generator: secret: "$\{JWT_GENERATOR_SIGNATURE_SECRET:pleaseChangeThisSecretForANewOne}" We’ve enabled security, enabled the /login endpoint, turned on oauth, and set the secret for signing the JWT (and, seriously, change that key. Please? :). At this point, we have options. We can go the super simple route and simply implement AuthenticationProvider, or we can go the slightly more complicated route and use the DelegatingAuthenticationProvider. I’ve used both approaches in my experimentation, and the latter approach seems to add a bit more complexity with no (apparent) added value, so we’ll go the simple route: DemoAuthenticationProvider.kt import com.steeplesoft.micronaut.UserService import io.micronaut.security.authentication.AuthenticationFailed import io.micronaut.security.authentication.AuthenticationProvider import io.micronaut.security.authentication.AuthenticationRequest import io.micronaut.security.authentication.AuthenticationResponse import io.micronaut.security.authentication.UserDetails import io.reactivex.Flowable import org.reactivestreams.Publisher import java.util.ArrayList import javax.inject.Singleton @Singleton class DemoAuthenticationProvider(private val userService: UserService, private val passwordEncoder: DemoPasswordEncoder) : AuthenticationProvider { override fun authenticate(authenticationRequest: AuthenticationRequest<*, *>): Publisher<AuthenticationResponse> { val user = userService.findUser(authenticationRequest.identity as String) return (if (user != null && passwordEncoder.matches(authenticationRequest.secret as String, user.password)) { Flowable.just(UserDetails(user.email, ArrayList())) } else { Flowable.just(AuthenticationFailed()) }) } } The interface has a single method, authenticate, to which is passed a AuthenticationRequest<*, *>. Unfortunately, it doesn’t appear we can specify actual types on that, so we’re stuck, it seems, with the ugly casts in the method body. I think I’ll survive. In the constructor, we inject an instance of our UserService, but also a DemoPasswordEncoder? That’s an implementation (from our app) of the PasswordEncoder interface required by the DelegatingAuthenticationProvider. I kinda like that class, so we’re going to use it. Our implementation simply hashes the password, but feel free to do what you want: DemoPasswordEncoder.kt import io.micronaut.security.authentication.providers.PasswordEncoder import java.security.MessageDigest import javax.inject.Singleton @Singleton class DemoPasswordEncoder : PasswordEncoder { private val md = MessageDigest.getInstance("SHA-256") override fun matches(rawPassword: String?, encodedPassword: String?): Boolean { return encodedPassword == encode(rawPassword) } override fun encode(rawPassword: String?): String { return String(md.digest((rawPassword?:"").toByteArray())) } } In our AuthenticationProvider provider, we look up the user by email address and compare the encoded passwords. If they match, we return a UserDetails instance. If they don’t, we return an AuthenticationFailed instance. Either response is wrapped in a Flowable. If you run your tests now, you should get an authentication failure. Let’s add authentication to the test: AuthorControllerTest.kt @Test fun testIndex() { val request = HttpRequest .GET<String>("/author") .header(HttpHeaders.AUTHORIZATION, "Bearer $\{login().accessToken}") assertEquals("author", client.toBlocking().exchange(request, String::class.java).body()) } private fun login() : BearerAccessRefreshToken { val request = HttpRequest.POST("/login", UsernamePasswordCredentials(USERNAME, PASSWORD)) val response = client.toBlocking().exchange(request, BearerAccessRefreshToken::class.java) assertEquals(HttpStatus.OK, response.status); return response.body()!! } companion object { val USERNAME = "jugdemo@steeplesoft.com" val PASSWORD = "password" } Note the addition of the login() function. We want to POST the user credentials (modeled by UsernamePasswordCredentials) to the /login endpoint. Upon a successful response, we can pull the JWT from the response body. Super simple. In our test method, we just need to add the Authorization header with our bearer token, and we’re golden! Almost. The problem now is that our login() function fails because the user doesn’t exist. So how should we load test data? You probably have a preferred method, if you’ve been doing this kind of testing for a while, but here’s a pretty novel Micronaut-provided solution: an ApplicationEventListener. By creating a class that implements this interface in the test source tree, we can listen for the server to start and do $SOMETHING but ONLY when running tests. This startup code wouldn’t affect a production deployment. You can, of course, use it in a production environment, but we don’t want to create test users in production, so we won’t. :) ApplicationTestListener.kt import io.micronaut.context.event.ApplicationEventListener import io.micronaut.runtime.server.event.ServerStartupEvent import javax.inject.Singleton @Singleton class ApplicationTestListener(private val userService : UserService) : ApplicationEventListener<ServerStartupEvent> { override fun onApplicationEvent(event: ServerStartupEvent?) { if (userService.findUser(AuthorControllerTest.USERNAME) == null) { userService.addUser(AuthorControllerTest.USERNAME, AuthorControllerTest.PASSWORD) } } } When the application starts, this code runs. It checks to see if the user exists. If it does not, it’s added. Before running our tests, we need to make one more change to the system: UserService.addUser: UserService.kt import com.steeplesoft.micronaut.security.DemoPasswordEncoder import io.micronaut.aop.Around import io.micronaut.spring.tx.annotation.Transactional import javax.inject.Singleton import javax.persistence.EntityManager import javax.persistence.PersistenceContext class UserService(@PersistenceContext val entityManager: EntityManager, private val passwordEncoder: DemoPasswordEncoder) { //... @Transactional fun addUser(userName : String, password : String) : User { val user = User(email = userName, pass = passwordEncoder.encode(password)) entityManager.persist(user) return user } } We’ve added the DemoPasswordEncoder to our constructor injection, then, in addUser, we (naively) create a new User instance, encoding the password, then persisting it. If you run your tests now, you should once again be green, and you’ll have a working, test Micronaut application, written in Kotlin, using JPA for persistence, and secured with JWTs, and that’s pretty cool. There’s a lot more to Micronaut, and the upcoming 1.1 release promises many great enhancements. Head over, then, to the Micronaut site and check out their great documentation. You can find the demo source here. ### [Kotlin+Micronaut and IDEA Don't Get Along Together](/2019/kotlin-micronaut-and-idea-don-t-get-along-together/) Recently, I’ve been experimenting with Micronaut, a new-ish "modern, JVM-based, full-stack framework for building modular, easily testable microservice and serverless applications" from the makers of Grail. So far, I’ve been really impressed. The documentation has been excellent, and the framework is very easy to get started with. I have, though, run in to some trouble writing tests, or, more accurately running tests. I spent far too much time trying to figure it out until I finally broke down and asked, and it turns out that it’s IDEA’s fault. While that’s a bit annoying, there is a workaround, which I’d like to document briefly here. If you read the getting started guide for Micronaut, you’ll notice a section on setting up your IDE. Having grown accustomed to having my projects "just work" in an IDE thanks to the excellent support for Maven and Gradle build files, I was a bit taken aback by this, but it turns out that Micronaut uses annotation processing fairly heavily, so you just have to tell IDEA to do the same when using its internal build system: If you’re using Java or Groovy, you’re all set. If you’re using Kotlin, however, you’re not. As the bug linked above points out, Kotlin’s kapt tool is not working correctly with IDEA’s internal build system. You have a couple of options, then. You can run your tests from the command line, using either Maven or Gradle, or you can change the test configuration to execute the build using the external tool before running or debugging your test. For example, I created a brand new (demo) application, then added a controller: $ mn create-app -l kotlin -b maven --features=junit demo |Generating Kotlin project... ................................... |Application created at C:\Users\jdlee\src\micronaut\demo $ cd demo $ mn create-controller Author |Rendered template Controller.kt to destination src\main\kotlin\demo\AuthorController.kt |Rendered template ControllerTest.java to destination src\test\java\demo\AuthorControllerTest.java From IDEA, if I Run AuthorControllerTest, the test will fail with a very unhelpful message: C:\java\jdk8\bin\java.exe ... 13:15:35.686 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [test] 13:15:35.700 [main] INFO i.m.context.env.DefaultEnvironment - Established active environments: [test] io.micronaut.http.client.exceptions.HttpClientResponseException: Page Not Found The trick is to change how IDEA builds the project before starting the test. With the AuthorControllerTest configuration created for us by virtue of having just tried to run the test, we just need to edit that configuration and change the "Before Launch" steps. This is how it should look by default: We want to click plus icon and tell it to run a Maven goal (or a Gradle task): Once you’ve added the goal/task configuration, click on the Build configuration and click the minus icon to remove it, then click OK. You’re now ready to run/debug your test, which should you give a green build. Given that this is a per-test configuration change, you’ll either have to repeat it for every test (if you run them individually) or change the default JUnit test configuration. How you want to handle that is completely up to you. If you don’t want to have to do that at all, you can either use Java or Groovy, or go vote on this issue. In fact, whatever you do, go vote! :) ### [Merry Christmas, 2018](/2018/merry-christmas-2018/) I hope you all have a merry Christmas. More importantly, I hope you take the time to think about the birth of the child that gives Christmas its meaning. "The birth of Christ is the timeless event that leads us to believe that the cries of a broken world have actually been heard. A Savior has been born. The vault of Heaven truly has been opened" -- Author Unknown Thanks be to God for His indescribable gift! ### [A Possibly Silly Question about Java Visibility](/2018/a-possibly-silly-question-about-java-visibility/) This morning, I was asked a question by a coworker that we both thought we knew the answer to: if a method is protected, can other classes see that method? The answer surprised us: maybe. :) It’s a pretty simple, basic question, but I thought I’d mention it in case there’s a beginner wondering, or more senior developers, such as myself and my team mate, that just have it wrong. :) The official Java docs provide a nice chart, which I’ve reproduced here: Modifier Class Package Subclass World public Y Y Y Y protected Y Y Y N no modifier Y Y N N private Y N N N What we knew was that protected members were visible to subclasses. What we expected, though, was they would not be visible to any other classes. What we found accidentally when writing tests, and what the table clearly indicates, is that the method is visible to classes in the same package. To demonstrate, I cobbled together a simple project: package com.steeplesoft.visibilitytest; public class Class1 { public void publicMethod() { } protected void protectedMethod() { } private void privateMethod() { } } package com.steeplesoft.visibilitytest; public class Class2 { public Class1 publicInstance = new Class1(); protected Class1 protectedInstance = new Class1(); private Class1 privateInstance = new Class1(); public void publicMethod() { publicInstance.publicMethod(); publicInstance.protectedMethod(); publicInstance.privateMethod(); // Error - not visible } protected void protectedMethod() { } private void privateMethod() { } } package com.steeplesoft.visibilitytest.sub; import com.steeplesoft.visibilitytest.Class1; import com.steeplesoft.visibilitytest.Class2; public class Class3 { public Class1 class1 = new Class1(); protected Class2 class2 = new Class2(); public void publicMethod() { class1.publicMethod(); class2.publicMethod(); class1.protectedMethod(); // Error - not visible class1.privateMethod(); // Error - not visible class2.protectedMethod(); // Error - not visible class2.privateMethod(); // Error - not visible class2.secondInstance(); // Error - not visible class2.thirdInstance(); // Error - not visible } } As expected (for those sharper than I, it seems), Class2 can see Class1.publicMethod and Class1.protectedMethod, but not Class1.privateMethod. Class3, however, can only see Class2.publicMethod, but not the other two. It can also only see the publicInstance field, but neither protectedInstance nor privateInstance. Moral of the story: if you’re trying to hide methods from other classes, protected may not be the answer your looking for. ### [Getting Started with Eclipse MicroProfile, Part 8: The Conclusion](/2018/getting-started-with-eclipse-microprofile-part-8-the-conclusion/) Many times, one of the hardest parts of getting started with a particular piece of technology is figuring out how to get started. :) In this series, I’ve used an extremely simple project to show how to do just that with a number of MicroProfile implementations. Obviously, a real application will have many more concerns than we dealt with in this application, but what this effort gave us is working, runnable, and testable build for six different MicroProfile implementations. What I’d like to do in this final installment in the series, is give some closing thoughts. In case you missed a post, here are links to each part: The Introduction The Application Payara Micro Thorntail OpenLiberty TomEE Hammock Helidon As I noted, we have hardly scratched the surface of the MicroProfile specification or, more generally, a Java EE Jakarta EE application. There are things like DataSources, clustering, transactions, etc. that we didn’t even attempt to address. What your application needs will likely drive, at least in part, which implementation you choose. For example, if you want to use JSF, JNDI, JTA, etc., you might prefer one of the more…​ traditional implementations (Payara Micro, Thorntail, TomEE or OpenLiberty). However, if you aren’t using any of those, then perhaps the smaller CDI-based implementations (Hammock, or Helidon) might be more appealing. Either way, if you don’t have any of these technologies already in place, it would probably be prudent to experiment with them and find the best fit. One thing that struck me about each of the implementations is the variation in startup times. Microservices being what they are, startup times can be a significant concern. I’m not a performance expert, so I won’t attempt a rigorous analysis, but I will say, just based on wall time, the Helidon seemed the fastest, and OpenLiberty was the slowest. Given the difference in the nature of the two implementations, I guess that’s not too surprising, but the size of the difference (less than a second versus north of 15) in my admittedly non-scientific tests was. Is that a valid concern? Again, your needs will vary, so take a look and decide for yourself. Regardless of your implementation choice, there are several great specifications that make up the profile. Two that intrigue/excite me the most are JWT Auth and Config, both of which I’ll look at in future posts, but this is it for now. What do you think of MicroProfile? Was this getting started series helpful? Hit me up on Twitter and let me know what you think! ### [Getting Started with Eclipse MicroProfile, Part 7: Helidon](/2018/getting-started-with-eclipse-microprofile-part-7-helidon/) Up next in our series comes an offering from, to me, a somewhat surprising source, Oracle, and that offering is Helidon. I first heard about in September 2018, and while it’s still pre-1.0, it looks extremely promising. Like Hammock, Helidon projects are jar projects, so we need to set the package type appropriately, then import the Helidon dependencies: <packaging>jar</packaging> <properties> <helidon.version>0.10.1</helidon.version> <package>com.steeplesoft.microprofile.helidon</package> <mainClass>$\{package}.Main</mainClass> <libs.classpath.prefix>libs</libs.classpath.prefix> <copied.libs.dir>$\{project.build.directory}/$\{libs.classpath.prefix}</copied.libs.dir> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.helidon</groupId> <artifactId>helidon-bom</artifactId> <version>$\{helidon.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> Our dependencies, then are very short: <dependencies> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>common</artifactId> <version>$\{project.version}</version> </dependency> <dependency> <groupId>io.helidon.microprofile.bundles</groupId> <artifactId>helidon-microprofile-1.2</artifactId> </dependency> </dependencies> There are a number of dependencies pulled in transitively, but that’s fine. We only have to manage the one. Unless I’ve missed something, you do need to code an entry point. It’s an extremely small class that doesn’t do anything special, so I hope I’ve either overlooked something, or it’s something that will be fixed as the project matures. At any rate, here it is: public final class Main { public static void main(final String[] args) throws IOException { Server.create().start(); } } It seems like a waste of time, but, as best as I can tell, it’s required at the moment. :) With that in place, we’re almost ready to run it. We can, of course, run directly from the IDE, but to run from the command line, we need a Maven plugin. Or two. The official docs show the maven-jar-plugin, but I’ve also thrown in the maven-capsule-plugin we saw from Hammock: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>$\{copied.libs.dir}</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> <overWriteIfNewer>true</overWriteIfNewer> <includeScope>runtime</includeScope> <excludeScope>test</excludeScope> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>$\{libs.classpath.prefix}</classpathPrefix> <mainClass>$\{mainClass}</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>com.github.chrisdchristo</groupId> <artifactId>capsule-maven-plugin</artifactId> <executions> <execution> <goals> <goal>build</goal> </goals> <configuration> <appClass>$\{mainClass}</appClass> <type>fat</type> </configuration> </execution> </executions> </plugin> </plugins> </build> The maven-dependency-plugin copies all of the projects runtime dependencies to the configured directory, and the maven-jar-plugin builds a jar, specifying where to find the dependencies (in the lib directory next to the jar) and the main class to run. Using this plugin, we would run the project like this: $ java -jar target/helidon-1.0-SNAPSHOT.jar The libs directory MUST be in target or you will get a java.lang.NoClassDefFoundError and the project will fail to start. If you move the jar, you must move lib as well. With the maven-capsule-plugin, it’s all self-contained: $ java -jar target/helidon-1.0-SNAPSHOT-capsule.jar` If you move the jar, like, say, when you deploy your application, all you need is the jar. I like this approach better, and many thanks to John Ament for introducing me to the plugin. :) Testing, like Hammock, is also a bit different. There doesn’t appear to be Arquillian support for Helidon (yet?), so we test much like we did Hammock: public class HelidonTest { private static Server server; @BeforeClass public static void setup() { server = Server.create(); server.start(); } @AfterClass public static void shutdown() { if (server != null) { server.stop(); } } @Test public void shouldSayWorld() throws URISyntaxException, IOException { requestAndTest(new URI("http://localhost:8080"), "Hello, world"); } @Test public void shouldSayHelidon() throws URISyntaxException, IOException { requestAndTest(new URIBuilder(new URI("http://localhost:8080")) .setParameter("name", "Helidon") .build(), "Hello, Helidon"); } private void requestAndTest(URI uri, String s) throws IOException { try (CloseableHttpResponse response = HttpClients.createMinimal().execute(new HttpGet(uri))) { Assertions.assertThat(EntityUtils.toString(response.getEntity())) .isEqualTo(s); } } } And Bob’s your uncle! For more information, head over to the Helidon site for their getting started docs, which seem quite thorough and complete for such a young project. In our next installment, we’ll wrap up our discussion with some closing thoughts. ### [Getting Started with Eclipse MicroProfile, Part 6: Hammock](/2018/getting-started-with-eclipse-microprofile-part-6-hammock/) This time around, we’re going to start looking at a slightly different take on MicroProfile implemenations. Whereas Payara Micro, Thorntail, OpenLibery, and TomEE are all based on application servers (albeit stripped down versions), our implementation in this post, Hammock, is based on a CDI container. Rather than start what amounts to an app server under which a web is deployed, we’ll be spinning up a plain ol' CDI container, which will look for CDI beans to load/start/etc. That may sound weird, and I may not be describing it clearly, so let’s just jump in to the code and take a look. Hammock, as I noted above, is a CDI-based MicroServices framework. I should note that, as best as I can tell, while it supports MicroProfile features, I’m not entirely sure which version (seems to be 1.2), and it seems that Hammock is not a certified MicroProfile implementation (i.e., it doesn’t seem to have passed the TCKs, but I’m more than happy to be proven wrong). All that said, it seems to be a great (and FAST) deployment option. As usual, we’ll start with our POM: <packaging>jar</packaging> <properties> <version.hammock>2.1</version.hammock> </properties> <dependencies> <dependency> <groupId>ws.ament.hammock</groupId> <artifactId>dist-microprofile</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>common</artifactId> <version>$\{project.version}</version> </dependency> </dependencies> The eagle-eyed among us may notice something peculiar: our packaging is jar. In large part, this doesn’t really affect how the app is built, but it’s an interesting difference. We include one dependency to pull in Hammock’s MicroProfile distribution, and we’re off the to races. Almost. Like other demos, most of the heavy lifting is done with a build plugin: <plugin> <groupId>com.github.chrisdchristo</groupId> <artifactId>capsule-maven-plugin</artifactId> <executions> <execution> <goals> <goal>build</goal> </goals> <configuration> <appClass>ws.ament.hammock.Bootstrap</appClass> <type>fat</type> </configuration> </execution> </executions> </plugin> Here, at the suggestion of the Hammock documentation, we’re using the Capsule Maven plugin to build a fat jar, specifying ws.ament.hammock.Bootstrap as our application’s entry point. This class takes care of starting the CDI container (as well as integrating with JAX-RS runtimes, etc.) and leaves us with a running service ready to answer calls: # mvn install ... # java -jar target/hammock-1.0-SNAPSHOT-capsule.jar ... 17:53:07.928 [main] INFO ws.ament.hammock.HammockRuntime - Starting webserver on http://jdlee:8080 ... # curl http://localhost:8080 Hello, world # curl http://localhost:8080/?name=Hammock Hello, Hammock Beautiful, no? Testing here is a bit different as well. I was unable to find any sort of Arquillian support for Hammock, but that doesn’t mean it’s not testable: public class HammockTest { private static Bootstrapper bootstrapper; @BeforeClass public static void setup() { bootstrapper = ServiceLoader.load(Bootstrapper.class).iterator().next(); bootstrapper.start(); } @AfterClass public static void shutdown() { if (bootstrapper != null) { bootstrapper.stop(); } } @Test public void shouldSayWorld() throws URISyntaxException, IOException { requestAndTest(new URI("http://localhost:8080"), "Hello, world"); } @Test public void shouldSayHammock() throws URISyntaxException, IOException { requestAndTest(new URIBuilder(new URI("http://localhost:8080")) .setParameter("name", "Hammock") .build(), "Hello, Hammock"); } private void requestAndTest(URI uri, String s) throws IOException { try (CloseableHttpResponse response = HttpClients.createMinimal().execute(new HttpGet(uri))) { Assertions.assertThat(EntityUtils.toString(response.getEntity())) .isEqualTo(s); } } } In our @BeforeClass and @AfterClass methods, we simply start and stop the server programmatically. The tests look exactly like the ones we’ve seen prior. And that’s all there is to it. I should note that I have not pressed Hammock very hard, so I don’t know how it will differ with things like JPA, DataSources/ConnectionPools, etc. that other implementations may offer out of the box. Granted, those things aren’t MicroProfile APIs, so if your app uses them, it’s on you to make sure they’re available at runtime. It may be, then, that your application requires a bit more configuration and dependency management with Hammock than it would with, say, Payara Micro. I just don’t know enough to give any guidance on that. Maybe John Ament can chime in. :) That’s all for now. Next time, we’ll look at a new entry from Oracle, of all places, Helidon. ### [Getting Started with Eclipse MicroProfile, Part 5: TomEE](/2018/getting-started-with-eclipse-microprofile-part-5-tomee/) In this installment of our series, we’re going to take a look at the last of what I think of as the more traditional, app-server-based/-spawned implementations, TomEE. TomEE is a fully Java EE-enabled distribution of the venerable workhorse Tomcat, and comes with support for creating MicroProfile applications, so let’s see what that looks like. This should come as no surprise at this point, but setting up a TomEE-based project requires little effort. We start by adding these dependencies to our web project: <properties> <tomee.version>7.1.0</tomee.version> </properties> <dependencies> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>common</artifactId> <version>$\{project.version}</version> </dependency> <dependency> <groupId>org.apache.tomee</groupId> <artifactId>arquillian-tomee-embedded</artifactId> <version>$\{tomee.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.tomee</groupId> <artifactId>tomee-jaxrs</artifactId> <version>$\{tomee.version}</version> <scope>test</scope> </dependency> </dependencies> Notice that the only compile/runtime dependency is our shared code. The rest is for testing. We’ll need a plugin to bundle our application: <build> <plugins> <plugin> <groupId>org.apache.tomee.maven</groupId> <artifactId>tomee-maven-plugin</artifactId> <version>$\{tomee.version}</version> <configuration> <tomeeClassifier>webprofile</tomeeClassifier> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>exec</goal> </goals> <configuration> <context>ROOT</context> </configuration> </execution> </executions> </plugin> </plugins> </build> The exec goal will build our uberjar, and we set the context to ROOT so that our application is deployed on the root context. # mvn install ... # java -jar target/tomee-1.0-SNAPSHOT-exec.jar ... # curl http://localhost:8080 Hello, world # curl http://localhost:8080/?name=TomEE Hello, TomEE We already have our Arquillian dependencies added, and there are no additional configuration files needed for this very basic case, so we can run our tests via mvn test as we’ve seen many times already. As Emeril would say, BAM! We’re all done. Things get more complicated as the project gets more complicated, but I’ll try to discuss that in our wrap up. Stay tuned for an implementation of a different color next time when we look at Hammock. You can find the source for the whole project here, and for this part here. ### [Getting Started with Eclipse MicroProfile, Part 4: OpenLiberty](/2018/getting-started-with-eclipse-microprofile-part-4-openliberty/) Having looked at Thorntail last time, we’ll take a look at OpenLiberty this time. OpenLiberty is the open source project under which, as I understand the state of things, IBM’s WebSphere Liberty is developed. In this installment, we’ll give its MicroProfile support a quick spin. We start by setting up our POM: <packaging>war</packaging> <properties> <app.name>openliberty</app.name> <testServerHttpPort>8080</testServerHttpPort> <testServerHttpsPort>8443</testServerHttpsPort> <warContext>/</warContext> <package.file>$\{project.build.directory}/$\{app.name}.zip</package.file> <packaging.type>minify,runnable</packaging.type> <version.openliberty>18.0.0.3</version.openliberty> <version.openlibertyplugin>2.2</version.openlibertyplugin> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.openliberty.features</groupId> <artifactId>features-bom</artifactId> <version>$\{version.openliberty}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>common</artifactId> <version>$\{project.version}</version> </dependency> </dependencies> Notice that we have no direct dependencies on OpenLiberty at this point. We simply build a war with one dependency, our common code. The real work, it seems, comes in the build: <plugin> <groupId>net.wasdev.wlp.maven.plugins</groupId> <artifactId>liberty-maven-plugin</artifactId> <version>$\{version.openlibertyplugin}</version> <configuration> <assemblyArtifact> <groupId>io.openliberty</groupId> <artifactId>openliberty-runtime</artifactId> <version>$\{version.openliberty}</version> <type>zip</type> </assemblyArtifact> <configFile>src/main/liberty/config/server.xml</configFile> <packageFile>$\{package.file}</packageFile> <include>$\{packaging.type}</include> <bootstrapProperties> <default.http.port>$\{testServerHttpPort}</default.http.port> <default.https.port>$\{testServerHttpsPort}</default.https.port> <app.context.root>$\{warContext}</app.context.root> </bootstrapProperties> </configuration> <executions> <execution> <id>install-liberty</id> <phase>process-test-resources</phase> <goals> <goal>install-server</goal> </goals> </execution> <execution> <id>install-app</id> <phase>pre-integration-test</phase> <goals> <goal>install-apps</goal> </goals> <configuration> <looseApplication>true</looseApplication> <stripVersion>true</stripVersion> <installAppPackages>project</installAppPackages> </configuration> </execution> <execution> <id>package-app</id> <phase>package</phase> <goals> <goal>package-server</goal> </goals> <configuration> <outputDirectory>target/wlp-package</outputDirectory> </configuration> </execution> <execution> <id>package-server</id> <phase>package</phase> <goals> <goal>package-server</goal> </goals> <configuration> <outputDirectory>target/wlp-package</outputDirectory> </configuration> </execution> </executions> </plugin> There is a lot going on there, but, as best as I can tell, we’re using the OpenLiberty Maven plugin to extract the OpenLiberty server, add our app to it, then package it back up. It works, but it takes a lot of work to get there. :) Before we can build, though, we do need to create one file to configure the OpenLiberty instance. That lives at src/main/liberty/config/server.xml: <server description="Sample MicroProfile server"> <featureManager> <feature>microProfile-2.0</feature> </featureManager> <applicationManager autoExpand="true"/> <httpEndpoint host="*" httpPort="$\{default.http.port}" httpsPort="$\{default.https.port}" id="defaultHttpEndpoint"/> <webApplication location="openliberty.war" contextRoot="$\{app.context.root}"/> </server> This tells OpenLiberty that we want to enable MicroProfile 2.0, what ports we want to listen on, what application to deploy, and its context root. Once that’s done, we can run our app: # mvn install ... # java -jar target/openliberty.jar ... [AUDIT ] CWWKT0016I: Web application available (default_host): http://jdlee:8080/ ... # curl http://localhost:8080 Hello, world # curl http://localhost:8080/?name=OpenLiberty Hello, OpenLiberty Just as expected. Before closing out this installment, though, a word on testing. With the last two implementations, I was able to provide an Arquillian-based set of tests. Technically, I think OpenLiberty can be tested with Arquillian, but I was unable to make it work. Obviously, if this were a production project, I’d figure it out, but I took the easy way out here. :) However, in the OpenLiberty docs, they had some extra execution configurations for the plugin that starts and stops the server for integration tests, so I went with that. During the build, then, the server is started, the tests (which are just HTTP client calls to the server) run, and the server is shutdown. Not as nice as Arquillian, but it works in a pinch. Let’s start with Maven config: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skipTests>true</skipTests> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <executions> <execution> <id>integration-tests</id> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> <configuration> <includes> <include>**/*.java</include> </includes> </configuration> </execution> </executions> </plugin> <plugin> <groupId>net.wasdev.wlp.maven.plugins</groupId> <artifactId>liberty-maven-plugin</artifactId> <version>$\{version.openlibertyplugin}</version> ... <executions> ... <execution> <id>start-server</id> <phase>pre-integration-test</phase> <goals> <goal>test-start-server</goal> </goals> </execution> <execution> <id>stop-server</id> <phase>post-integration-test</phase> <goals> <goal>test-stop-server</goal> </goals> </execution> ... </executions> </plugin> We start by configuring the surefire plugin to not run during the test phase, then configure the failsafe plugin to run during the integration-test phase. Finally, we set up executions for the liberty-maven-plugin to start and stop the server in the pre-integration-test and post-integration-test phases. There are likely a myriad of ways to handle that, so feel free to pick your favorite. This should get you going, though. Our test, then, is pretty simple: public class OpenLibertyTest { public static final String URL = "http://localhost:8080/"; @Test public void shouldSayWorld() throws URISyntaxException, IOException { requestAndTest(new URI(URL), "Hello, world"); } @Test public void shouldSayOpenLiberty() throws URISyntaxException, IOException { requestAndTest(new URIBuilder(new URI(URL)) .setParameter("name", "OpenLiberty") .build(), "Hello, OpenLiberty"); } private void requestAndTest(URI uri, String s) throws IOException { System.out.println("Connecting to " + uri.toString()); try (CloseableHttpResponse response = HttpClients.createMinimal().execute(new HttpGet(uri))) { Assertions.assertThat(EntityUtils.toString(response.getEntity())) .isEqualTo(s); } } } And we can see that test run by issuing this: # mvn install ... [INFO] --- maven-failsafe-plugin:2.22.1:integration-test (integration-tests) @ openliberty --- [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.steeplesoft.microprofile.openliberty.test.OpenLibertyTest Connecting to http://localhost:8080/?name=OpenLiberty Connecting to http://localhost:8080/ [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.726 s - in com.steeplesoft.microprofile.openliberty.test.OpenLibertyTest [INFO] [INFO] Results: [INFO] [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- liberty-maven-plugin:2.2:test-stop-server (stop-server) @ openliberty --- ... Like I said. It’s not the most elegant, but it should get you going, and with that, we’re done! In the next installment, well see what it takes to get MicroProfile and Apache TomEE up and running. You can find the source for the whole project here, and for this part here. UPDATE Twitter user gcharters contacted me to tell me about a parent POM that OpenLiberty users can use to avoid some of the boilerplate above. You can find that POM here and cut the size of your POM significantly. Enjoy! ### [Getting Started with Eclipse MicroProfile, Part 3: Thorntail](/2018/getting-started-with-eclipse-microprofile-part-3-thorntail/) In the last installment, we talked about Payara Micro. In this, we’re going to look at Thorntail. Thorntail, née WildFly Swarm, is based on WildFly from Red Hat and is said to be "just enough app-server". Much like Payara Micro, Thorntail exposes a battle-tested application server platform, stripped down for microservices usage. Let’s a take a look at what it takes to deploy our application on Thorntail. Before getting, it’s worth pointing to the Thorntail documentation, which seems to be very complete and thorough. If you’d like to peruse that now, feel free. We’ll be here when you’re done. To get started, we need to create a new project, and add a few odds and ends to our build. Somewhat surprisingly, the required changes seem to be much smaller and simpler than those required by Payara Micro: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>mp-demo-master</artifactId> <groupId>com.steeplesoft.microprofile</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>thorntail</artifactId> <packaging>war</packaging> <properties> <version.thorntail>2.2.0.Final</version.thorntail> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.shrinkwrap.resolver</groupId> <artifactId>shrinkwrap-resolver-bom</artifactId> <version>3.1.3</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>io.thorntail</groupId> <artifactId>bom</artifactId> <version>$\{version.thorntail}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>io.thorntail</groupId> <artifactId>microprofile</artifactId> </dependency> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>common</artifactId> <version>$\{project.version}</version> </dependency> <dependency> <groupId>io.thorntail</groupId> <artifactId>arquillian</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>io.thorntail</groupId> <artifactId>thorntail-maven-plugin</artifactId> <version>$\{version.thorntail}</version> <executions> <execution> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project> I decided to include the entire POM, as it’s really rather small. We import the BOM in dependencyManagement, add one dependency to pull in Thorntail, one for our application, and one (ONE!) for the Arquillian tests. Likewise, we have a single build plugin. I had to include an updated version for ShrinkWrap, as the version included transitively from io.thorntail:arquillian was old and was causing test failures due to odd dependency look-ups against Central. Like Payara Micro, we build this as a war file, so we have the same empty src/main/webapp/WEB-INF/beans.xml file to trigger CDI processing. That is literally all we have to do. I even copied and pasted the tests, which run unchanged (yes, I could probably define those in another module and import them, but it’s not that important to me right now. :) When I run mvn install, I see the following in the target directory: #ll -h target/ total 104M drwxr-xr-x 1 jdlee jdlee 0 Oct 15 13:31 generated-test-sources drwxr-xr-x 1 jdlee jdlee 0 Oct 15 13:32 maven-archiver drwxr-xr-x 1 jdlee jdlee 0 Oct 15 13:31 maven-status drwxr-xr-x 1 jdlee jdlee 0 Oct 15 13:32 surefire-reports drwxr-xr-x 1 jdlee jdlee 0 Oct 15 13:31 test-classes drwxr-xr-x 1 jdlee jdlee 0 Oct 15 13:32 thorntail-1.0-SNAPSHOT -rw-r--r-- 1 jdlee jdlee 3.3M Oct 15 13:32 thorntail-1.0-SNAPSHOT.war -rw-r--r-- 1 jdlee jdlee 27M Oct 15 13:32 thorntail-1.0-SNAPSHOT.war.original -rw-r--r-- 1 jdlee jdlee 1.9K Oct 15 13:32 thorntail-1.0-SNAPSHOT-classes.jar -rw-r--r-- 1 jdlee jdlee 74M Oct 15 13:32 thorntail-1.0-SNAPSHOT-thorntail.jar And I can start my application using the -thorntail.jar uberjar: # java -jar target/thorntail-1.0-SNAPSHOT-thorntail.jar ... 2018-10-15 13:37:15,328 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 6) WFLYUT0021: Registered web context: '/' for server 'default-server' 2018-10-15 13:37:15,364 INFO [org.jboss.as.server] (main) WFLYSRV0010: Deployed "thorntail-1.0-SNAPSHOT.war" (runtime-name : "thorntail-1.0-SNAPSHOT.war") 2018-10-15 13:37:15,371 INFO [org.wildfly.swarm] (main) THORN99999: Thorntail is Ready Manual testing works just the same as it did with Payara Micro: # curl http://localhost:8080 Hello, world # curl http://localhost:8080/?name=Thorntail Hello, Thorntail With that, we’ve finished another simple MicroProfile deployment with zero changes to our application, and no container-specific code, but we’ll circle back to that idea when we wrap up the series. You can find the source for the whole project here, and for this part here. Up next, OpenLiberty! ### [Getting Started with Eclipse MicroProfile, Part 2: Payara Micro](/2018/getting-started-with-eclipse-microprofile-part-2-payara-micro/) Payara Micro is a MicroProfile implementation from the good folks at Payara, based on Payara Server, which is itself based on GlassFish. Whew! If you’re familiar with either GlassFish or Payara, you should feel right at home with Payara Micro. To start, we need to understand how Payara Micro deploys the application. Payara Micro spins up an instance, albeit a somewhat stripped down version, of Payara Server. Once the server instance has started, Payara Micro deploys your MP application as a web application. In your build file (and we’ll be using Maven), you must declare that you are building a war file: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 3 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <artifactId>mp-demo-master</artifactId> <groupId>com.steeplesoft.microprofile</groupId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>payara-micro</artifactId> <packaging>war</packaging> <name>payara-micro</name> <!-- ... --> Next, we need to declare the dependencies for Payara Micro, but we also need to declare a dependency on our common module, as that’s where the actual application lives. The Payara Micro module here has no real application data in. :) <dependencies> <dependency> <groupId>org.eclipse.microprofile</groupId> <artifactId>microprofile</artifactId> <version>2.0.1</version> <type>pom</type> <scope>provided</scope> </dependency> <dependency> <groupId>fish.payara.extras</groupId> <artifactId>payara-micro</artifactId> <version>$\{version.payara}</version> <scope>provided</scope> </dependency> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>common</artifactId> <version>$\{project.version}</version> </dependency> </dependency> Next, we can add the Payara Micro Maven Plugin to build, which will allow us to start and stop the server using Maven. We will also add some configuration for the Maven Dependency Plugin to copy the Payara Micro jar to the build output directory so that we can start and stop the server from the commandline: <build> <plugins> <plugin> <groupId>fish.payara.maven.plugins</groupId> <artifactId>payara-micro-maven-plugin</artifactId> <version>1.0.2</version> <configuration> <payaraVersion>$\{version.payara}</payaraVersion> <autoDeployArtifact>true</autoDeployArtifact> <deployArtifacts> <artifactItem> <groupId>$\{project.groupId}</groupId> <artifactId>$\{project.artifactId}</artifactId> <version>$\{project.version}</version> <type>war</type> </artifactItem> </deployArtifacts> <daemon>true</daemon> <deployWar>true</deployWar> </configuration> </plugin> </plugins> </build> This will configure the plugin for both the bundle and start goals. That lets us create an uberjar: $ mvn payara-micro:bundle ... $ java -jar tart/payara-micro-microbundle.jar ... [2018-10-15T08:47:25.788-0500] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1539611245788] [levelValue: 800] Payara Micro URLs: http://jdlee:8080/payara-micro-1.0-SNAPSHOT http://jdlee:8080/ 'payara-micro-1.0-SNAPSHOT' REST Endpoints: GET /payara-micro-1.0-SNAPSHOT/ GET /payara-micro-1.0-SNAPSHOT/application.wadl 'ROOT' REST Endpoints: GET / GET /application.wadl GET /openapi/ GET /openapi/application.wadl [2018-10-15T08:47:25.789-0500] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1539611245789] [levelValue: 800] Payara Micro 5.183 #badassmicrofish (build 380) ready in 16,311 (ms) And we can manually test our app: # curl http://localhost:8080 Hello, world # curl http://localhost:8080/?name=Payara+Micro Hello, Payara Micro I said we can test manually, but we can also write automated tests using Arquillian. We start by adding the dependencies for our tests: <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <version>1.4.0.Final</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.jboss.shrinkwrap.resolver</groupId> <artifactId>shrinkwrap-resolver-bom</artifactId> <version>3.1.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.shrinkwrap.resolver</groupId> <artifactId>shrinkwrap-resolver-api-maven</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.shrinkwrap.resolver</groupId> <artifactId>shrinkwrap-resolver-impl-maven</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> <scope>test</scope> </dependency> <dependency> <groupId>fish.payara.arquillian</groupId> <artifactId>arquillian-payara-micro-5-managed</artifactId> <version>1.0.Beta3</version> <scope>test</scope> </dependency> <dependency> <groupId>fish.payara.extras</groupId> <artifactId>payara-embedded-all</artifactId> <version>$\{version.payara}</version> <scope>test</scope> </dependency> </dependencies> Let’s start with a simple test. This test will run in-container, and will demonstrate that the injection is working, and…​ that the methods can return Strings. :P @RunWith(Arquillian.class) public class InjectionTest { @Inject private HelloWorldService service; @Inject private HelloWorldResource resource; @Deployment public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class) .addPackage(HelloWorldService.class.getPackage()) .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test public void verifyInjection() { assert service != null; assert resource != null; } @Test public void serviceSaysHelloCorrectly() { assert "Hello, Test".equals(service.sayHello("Test")); } @Test public void resourceSaysHelloCorrectly() { assert "Hello, Test".equals(resource.sayHello("Test")); } } That’s all there is to it. For using Payara Micro as an Arquillian container, there is no need, at least in the most basic of usages, for arquillian.xml. To run this test from IDEA, there seems to be a bit of extra work needed. It seems that Payara Micro depends on the environment variable MICRO_JAR to tell the bootstrapping code where to find the JAR. It’s on the classpath, but that doesn’t seem sufficient (I can, of course, be way off base — I’m not an expert on Payara Micro or Arquillian), so here are the changes to my POM that I needed to make things work: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <phase>process-test-resources</phase> <goals> <goal>copy</goal> </goals> <configuration> <artifactItems> <artifactItem> <groupId>fish.payara.extras</groupId> <artifactId>payara-micro</artifactId> <version>$\{version.payara}</version> <overWrite>false</overWrite> <outputDirectory>$\{project.build.directory}/</outputDirectory> <destFileName>payara-micro.jar</destFileName> </artifactItem> </artifactItems> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <environmentVariables> <MICRO_JAR>$\{project.build.directory}/payara-micro.jar</MICRO_JAR> </environmentVariables> </configuration> </plugin> It also seemed that I needed to run the tests from the command-line first to make sure the JAR file was in place, as it seems that IDEA does not run the usual Maven lifecycle prior to running the tests. Again, I’m no expert, so if someone who is can clear up the confusion, I would greatly appreciate it. Finally, one last test, which will exercise our REST endpoint end-to-end: @RunWith(Arquillian.class) @RunAsClient public class HelloWorldResourceTest { @ArquillianResource private URL deploymentURL; @Deployment public static WebArchive createDeployment() { return ShrinkWrap.create(WebArchive.class) .addPackage(HelloWorldService.class.getPackage()) .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); } @Test public void shouldSayWorld() throws URISyntaxException, IOException { requestAndTest(deploymentURL.toURI(), "Hello, world"); } @Test public void shouldSayPayara() throws URISyntaxException, IOException { requestAndTest(new URIBuilder(deploymentURL.toURI()) .setParameter("name", "Payara").build(), "Hello, Payara"); } private void requestAndTest(URI uri, String s) throws IOException { try (CloseableHttpResponse response = HttpClients.createMinimal().execute(new HttpGet(uri))) { assert EntityUtils.toString(response.getEntity()).equals(s); } } } We tell JUnit to run the test with Arquillian, and that we want to run the tests on the client. Ordinarily, Arquillian magically wraps up your tests, ships them to the server, and runs them there. For this test, we don’t want that, thus @RunAsClient. Using the Apache HttpClient from HttpComponents, we make an "out of process" REST request to the endpoint and verify the responses. And there you have a very basic Payara Micro example, complete with working Arquillian tests. The thing to take away from this is how simple it is to wrap your application in a Payara Micro runtime: the only additional work was configuring your build to output the uberjar. That’s awesome, as that means there’s no real application glue required for the specific runtime environment. We’ll see that this mostly holds true across the other MicroProfile, thus demonstrating the power of standards and portability. In the next installment, we’ll take a look at Thorntail. You can find the source for the whole project here, and for this part here. ### [Getting Started with Eclipse MicroProfile, Part 1: the Application](/2018/getting-started-with-eclipse-microprofile-part-1-the-application/) To start our investigation, we need an application to work with. Part of the problem with getting started applications is making sure that your example is complicated enough to be interesting, but not so complicated that the greater message is lost in the details of the app. MicroProfile 2.0 is made up of a number of components: MicroProfile Config 1.3 MicroProfile Fault Tolerance 1.1 MicroProfile Health Check 1.0 MicroProfile JWT Authentication 1.1 MicroProfile Metrics 1.1 MicroProfile OpenAPI 1.0 MicroProfile OpenTracing 1.1 MicroProfile Rest Client 1.1 CDI 2.0 Common Annotations 1.3 JAX-RS 2.1 JSON-B 1.0 JSON-P 1.1 To include all of those in this would probably be a bit too much technical weight for a getting started effort, so, for this example, I’ve leaned (probably too far) toward simple. Our application will have a single JAX-RS resource, into which is injected a single CDI bean. The point is to have a working REST endpoint, with an inject "service layer", to show a MicroProfile in action, allowing us to verify that our basic environment is configured and working correctly. From there you are free to load on all the complexity you find you need. That’s exactly what I’ll be doing in a separate project. :) I may be covering far too basic a level, but I want to make sure I don’t leave too many behind, so let’s start at the very beginning: the JAX-RS Application: @ApplicationScoped @ApplicationPath("/") public class MicroProfileApplication extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> set = new HashSet<>(); set.add(HelloWorldResource.class); return Collections.unmodifiableSet(set); } } As you may know, when a JAX-RS-enabled container starts, by default it scans the classpath looking for instances of Application (there are, of course, other deployment options). Here, we define the application, using @ApplicationPath to specify that we want our REST application to answer at the context root of application. As far as JAX-RS goes, that’s all we need. However, some of the MicroProfile implementations are heavily CDI-based, and at least one of them (Helidon), appears to be configured (by default) only to expose as CDI beans those classes that have certain annotations, thus we have @ApplicationScoped on this class as well. I’ll discuss that more later. Next, we need a JAX-RS resource, so we create this: @RequestScoped @Path("/") @Produces(MediaType.TEXT_PLAIN) public class HelloWorldResource { @Inject private HelloWorldService service; @GET public String sayHello(@QueryParam("name") @DefaultValue("world") String name) { return service.sayHello(name); } } Again, the @Path annotation should be enough, but we also provide @RequestScoped to satisfy the CDI containers. As any good REST service should, in my opinion, we delegate the work to a service that we inject using @Inject. In our resource method, we simply pull the values we need off the request (allowing JAX-RS to provide a default if the request doesn’t specify a value), pass that to the service, the return the response. Nothing exciting here. Will the service be more interesting? No. No it will not: @RequestScoped public class HelloWorldService { public String sayHello(String name) { return "Hello, " + name; } } Not a single thing of interest here is there? There is one last thing we need to take care of, and that’s marking this archive as a CDI bean archive. We do that by creating a file at src/main/resource/META-INF/beans.xml that can be completely empty if you prefer. We have nothing special to declare, so that’s what we’ll do. Finally, let’s take a look at a portion of the POM file. For this module to compile, there are really only two relevant entries: <properties> <version.javaee>8.0</version.javaee> </properties> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>$\{version.javaee}</version> <scope>provided</scope> </dependency> As I noted in the introduction, our main interest is in how to deploy this using one of several MicroProfile implementations, so the application is intensely underwhelming. In Part 2, we’ll start looking at deploying using Payara Micro, so stick around for that. You can find the source for the whole project here, and for this part here. ### [Getting Started with Eclipse MicroProfile, Part 0](/2018/getting-started-with-eclipse-microprofile-part-0/) The Eclipse MicroProfile is a community-driven profile initially developed by Red Hat, IBM, TomiTribe, Payara and the London Java Community (LJC). Launched in 2016, it was intended to sit alongside Java EE’s Web and Full profiles, offering Java EE developers a smaller, lighter set of standards with which they could build microservices. Today, MicroProfile lives as an Eclipse project, and is being supported and actively developed by its creators as well as many more, including both corporations and individuals, giving us an embarassment of riches, if you will, when it comes to implementations. By my count, there are at least 6 implementations from which to choose, leading to the question: Which one do I choose? While there are many aspects that factor in to such a decision, it is not my intent here to answer those questions. Rather, what I’d like to do is provided some small "getting started" projects to help you kick off your own investigation. With that in mind, here are the implementations (in no particular order) that we’re going to look at: Payara Micro Thorntail OpenLiberty Apache TomEE Hammock Helidon In Part 1, we’ll cover the (admittedly absurdly basic) application, and in subsequent parts, we’ll see what it takes to deploy that application using each of these MicroProfile implementations. ### [Easy File Copy in Kotlin](/2018/easy-file-copy-in-kotlin/) Copying files in Java is, I think, header than it seems it should be. Typically, I see that done with, say, a ByteArrayInputStream and a ByteArrayOutputStream . Thanks to Kotlin’s extension function capabilities, this operation is a one-liner: File("/path/to/destination").writeBytes(File("/path/to/source").readBytes()) That could even be an extension function itself: fun File.copyFile(dest: File): Unit = dest.writeBytes(this.readBytes()) ### [VirtualBox Shared Folders under Linux](/2018/virtualbox-shared-folders-under-linux/) My work machine runs Windows (go ahead and laugh. I’ll wait). While I’ve been able to tweak the machine and get a moderately acceptable setup, there are times when I’d really like to use Linux for something, so I spin up a virtual machine with VirtualBox. While that works, I don’t really like having source code — especially with changes in flight — on the VM, as it makes it a bit more dangerous/difficlt to destroy the VM should I need the disk space (which happens more often than I’d like). I set out, then to get shared folders working so I can keep the source on my host machine, and just do the work in the VM. Unfortunately, it doesn’t seem to be as simple as adding a shared folder to the VirtualBox config. This post, then, will detail the steps I took to make things work for me. The zeroth step, clearly, is to set up the VM. I’ll not cover that here (though perhaps I can in another post if there’s interest, but it seems to be a well-covered topic already). Once you have a working VM, we need to make our configuration changes. Step 1 (which I did with the VM shut down, though that’s not strictly necessary), is to configure the shared folders. From the VirtualBox Manager window, we need to select the VM we want to modify, and select the Shared Folders tab: From here, we need to click the Add a folder button on the right, and specify the host directory (Folder Path) and the…​ device name (Folder Name) by which the folder is exposed to the guest: Once we’ve configured that, we can boot the VM if it’s not already running. From a command prompt, we need to make some system changes. The most important thing is to verify that the VirtualBox guest additions are installed. Like setting up the VM, this is well documented elsewhere, so I’ll leave that as an exercise for the reader, but I will offer these simple commands that installed the GA for me on my Fedora VM: $ dnf install kernel-headers kernel-devel elfutils-libelf-devel gcc dkms make bzip2 perl $ bash /run/media/jdlee/VBox_GAs_*/VBoxLinuxAdditions.run One way to verify that the Guest Additions are properly installed is to load the kernel module: # modprobe vboxsf The command should complete without error. If it does not, you may need to revisit the Guest Additions installation. That done, it seems that for a user to access the shared folder, the account needs to belong to the vboxsf group, so we need to add the user to the group: # groups jdlee jdlee : jdlee wheel # usermod -a G vboxsf jdlee # groups jdlee jdlee : jdlee wheel vboxsf In my case, I want to mount the host directory as the src directory in my account’s home directory, so I added this to /etc/fstab: HOST_SRC /home/jdlee/src vboxsf defaults,uid=jdlee,gid=jdlee 0 0 I can then mount the shard folder via mount -a. If you get a message about a protocol error, verify that the device name/label given in column 1 in the fstab entry matches the Folder Name given in the VirtualBox configuration. At this point, you should be ready to start using the shared folder like any other local directory. I typically reboot the VM to verify that I have all the bits in the right places while the effort is still fresh in my mind, but that’s totally optional. Have I overlooked anything? Is there a simpler approach? Feel free to sound off in the comments! ### [Resurrecting Turbo Vision](/2018/resurrecting-turbo-vision/) If you wrote software on a DOS system in the 80s or 90s, you probably used one of the Borland products, Turbo Pascal or Turbo C, with that beautiful, beautiful blue, mouse-enabled text-based user interface (TUI, if you will). Those IDEs were powered by a library called Turbo Vision (TV), which Borland documented and published for others to use. I loved it. While we all live in a GUI world and there are lots of libraries for building GUIS, I have for years now been dying to be able to use TV again, if for no other reason than hard core nostalgia. The problem being that I have used C in about 2 decades, and, to be honest, I’m not sure I’m too excited about writing even toy apps in the language. Dead end, right? Not so fast. Enter, stage left: SWIG. SWIG, the Simplified Wrapper and Interface Generator, is a tool for building wrappers for libraries written in, say, C or C, for languages such as Python, PHP, and... Java. While it may not be the best option, it's an option, and I've been tinkering with it off and on for many, many moons now with the C version of the library open source by Borland long ago, before they were sold off and the Borland brand quietly disappeared. Tonight, I made great progress on it. First, for those not familiar with Turbo Vision and don’t want to google, here’s a screen shot from one of the examples: As you can see, it has a menu bar, a status line, and a desktop. It’s not demo’d here, but you can also create new windows, such as text editor windows for an IDE like Turbo Pascal and Turbo C++. The menu items in the menu bar and status line support keyboard activation (like we see in Windows) by pressing Alt plus the highlighted letter. You can also click on the item with your mouse. Now having seen what the C++ demo looks like, let’s jump ahead a bit and look at the Java code. I won’t go into the SWIG interface file just yet, though I hope to write about that in detail at some point in the future. I’ll admit I do like to post rough sketches of things I’m working on (take my Jerkey post, for example) in the open source spirit of "release early, release often". This code, though, is seriously ugly and will likely see some major changes as I learn more about the tool throughout the project. At any rate, just assume that I have an interface file that works well enough for now, and here’s the Java code using the native library: public class TurboVisionDemo extends TApplication { public TurboVisionDemo() { super(); } @Override public TStatusLine initStatusLine(TRect r) { r.getA().setY(r.getB().getY() - 1); return new TStatusLine(r, new TStatusDef(0, 0xFFFF) .addItem(new TStatusItem("~Alt-X~ Exit", tvisionJNI.kbAltX_get(), tvisionJNI.cmQuit_get())) .addItem(new TStatusItem("~Alt-F3~ Close Dude", tvisionJNI.kbAltF3_get(), tvisionJNI.cmClose_get()))); } @Override public TMenuBar initMenuBar(TRect r) { r.getB().setY(r.getA().getY() + 1); TSubMenu sub1 = new TSubMenu("~F~ile", kbAltF_get()); sub1.addItem(new TMenuItem("~O~pen", 200, kbF3_get(), hcNoContext_get(), "F3")) .addItem(new TMenuItem("~N~ew", 201, kbF4_get(), hcNoContext_get(), "F4")) .addItem(newLine()) .addItem(new TMenuItem("E~x~it", cmQuit_get(), cmQuit_get(), hcNoContext_get(), "Alt-X")); TSubMenu sub2 = new TSubMenu("~W~indow", kbAltW_get()); sub2.addItem(new TMenuItem("~N~ext", cmNext_get(), kbF6_get(), hcNoContext_get(), "F6")) .addItem(new TMenuItem("~Z~oom", cmZoom_get(), kbF5_get(), hcNoContext_get(), "F5")); TMenuBar menuBar = new TMenuBar(r, sub1.addSubMenu(sub2)); return menuBar; } public static void main(String argv[]) { TurboVisionDemo app = new TurboVisionDemo(); app.run(); } } This program doesn’t do much, but it does recreate the menu and status bars from the demo that ships with the library. Here’s a screen shot of the app running: Looks familiar, doesn’t it? I could have made things a bit easier for myself and just linked to the same image, but I didn’t because that didn’t seem honest. :) There is, though, one difference between the two images. Look at that status bar and you should see an extra menu item there, "Close Dude" (Don’t ask. I was probably tired one night :). Proof that I haven’t faked things. :P As cool as that is (at least, I think it’s cool ;), it still doesn’t do much, and there’s much more to the library to wrap. Sometimes, the wrapping also comes with some changes to the C library itself to make it more easily consumed by, in my case, Java, and making those changes requires reaching back to my C days, and I’m finding those tools very rusty. I am, though, having a good time with it, and if all goes as planned, I hope to be able to use the same interface file and produce bindings for, say Python. When all is said and done, though, this may never be serious tool, but I’m having a good time learning while I wrap it, and the trip down memory lane is has been fun as well. If you’d really like to the ugly state this thing is in at the moment, you can find the sources on Bitbucket. Just…​ be kind. :) ### [Jerkey: A Kotlin DSL for Jersey](/2018/jerkey-a-kotlin-dsl-for-jersey/) I’m currently working on a DSLs-in-Kotlin presentation for my local JUG, so I need a good domain in which to work. HTML is a great sample domain, but it’s been done to death. After a bit of head scratching, I’ve come up with what is, I think, a somewhat novel domain: REST application building. Sure, there are libraries like Ktor, but suffers from some very serious NIH. I’m totally kidding, but the dearth of discussions regarding REST applications and DSL construction was good enough for me, so let’s see what we have so far. What really sold me on the idea was that Jersey already offers an API for programmatically creating REST endpoints, which you can read about here. All we need to do then, is define a DSL to build the application model, then run it through this API and let Jersey do the heavy lifting, which sounds perfect for what is intended to be, primarily, a didactic project. I’ll spare you the details of how the DSL is built and skip straight to the "finished" project: application { produces = "application/json" consumes = "application/json" resource { path = "items" method = "get" handler = ::listItems param { source = "query" name = "someParam" type = Int::class } } resource { path = "items/\{id}" method = "get" handler = ::getItem param { source = "path" name = "id" type = Int::class } } }.build() While there’s a good chance I’ll modify the structure of the DSL as I continue to work on the presentation, this represents a working DSL. Once I call build(), I can then access the REST application via a browser or curl. A few things to call out. Notice the handler property. With that, I can specify the function in my Kotlin code that will actually handle the request. Where Jersey allows me to define a method like this: public Response listItems(@QueryParam("someParam") Integer someParam) { ... } I have yet to be able to figure out how to dispatch to a Kotlin method with an arbitrary number of parameters. One might think of the spread operator, but requires the receiving method specify a varargs parameter, which I’ve tried to avoid, possibly for no good reason other than tunnel vision. :) What I’ve opted to use, though, is CallContext object, which will encapsulate various things pulled from the request and presented in, in theory, ready-to-use forms. In this instance, the context would have a parameter called 'someParam' of type Int. At this point, the type coercion is pretty crude, but the whole thing is a work in progress, so cut me some slack. :) One of the more interesting parts, I think, is the creation of the resources for Jersey to consume, and part of the fun in that is the demonstration of Kotlin’s Java interop, going both directions: class JerkeyResourceConfig(val application: Application) : ResourceConfig() { init { val resourceBuilder = Resource.builder() resourceBuilder.path(application.path) application.resources.forEach { res -> val childResource = resourceBuilder.addChildResource(res.path) val methodBuilder = childResource.addMethod(res.method.toUpperCase()) methodBuilder.produces(res.produces) .handledBy(Inflector<ContainerRequestContext, Response> { val context = CallContext() (it.uriInfo.queryParameters + it.uriInfo.pathParameters).forEach { qp -> val name = qp.key!! val value = qp.value[0]!! val param = res.params[name] param?.let { context.processParam(param, name, value) } } res.handler?.invoke(context) }) } registerResources(resourceBuilder.build()) } } We iterate over the resource instances from the DSL, creating subresources of the base resource defined by the application element in the DSL. My DSL code consumes that here: fun build() { val rc = JerkeyResourceConfig(this) val baseUri = UriBuilder.fromUri("http://localhost$path").port(port).build() val server = JdkHttpServerFactory.createHttpServer(baseUri, rc); readLine() server.stop(0) } Put all of that together with this handler method: fun listItems(context : CallContext) : Response { val id : Int = context.params["param"] as Int return Response.ok().entity("items $id").build() } and we get this from the command-line: $ curl -Ssk http://localhost:8080/items?param=1024 items 1024 It’s not very flashy, but for one evening’s hacking, it’s not too shabby. :) If you’d like to follow along, you can find the (meager) sources here. ### [String.format()... You May Be Doing It Wrong](/2018/string-format-you-may-be-doing-it-wrong/) If you’ve been working with Java for very long, you’ve probably had occasion to use String.format() . And, if you’re like me, you may very well have been doing it "wrong". Let’s take a look at what was, for me, common usage, and how, maybe, you should be doing it. Let’s start by taking a look at a mildly complex — and highly contrived — usage: String foo = String.format("one %s two %s three %s four %s five %s one again %s", "1", "2", "3", "4", "5"); System.out.println(foo); Other than being beyond ugly, can you spot the problem? Six format specifiers, and five values. It compiles just fine, but blows up at runtime, so that’s no good. There are, of course, other ways to build such a string. StringBuilder comes quickly to mind, but there are times when a use of format() makes more readable code than a series of calls to append() . String foo2 = new StringBuilder("one ") .append("1") .append(" two ") .append("2") .append(" three ") .append("3") .append(" four ") .append("4") .append(" five ") .append("5") .append(" one again ") .append("1") .toString(); Not really a whole lot prettier, but the point here isn’t finding the prettiest way to write something like this. We’re trying to see how to use String.format() in a safer, more reliable way, so let’s get to it. The key is the "argument index", which you can read more about here. Using the argument index, you can specify which value in the argument list goes with the format specifier in question. Using that, we could rewrite the first example like this: String foo3 = String.format("one %1$s two %2$s three %3$s four %4$s five %5$s one again %1$s", "1", "2", "3", "4", "5"); System.out.println(foo3); This doesn’t solve the missing argument issue, but it does allow us to avoid repeating values. It’s not super obvious in this example, so let’s try an uglier one, one in which a particular value needs to be repeated many, many times: String foo4 = String.format("one %1$s two %1$s three %1$s four %1$s five %1$s", "1"); System.out.println(foo4); Six format specifiers, one value. Pretty fancy, eh? So, if you find yourself needing to build a complicated string, especially with a large number of repeating values, argument indices are your friend. And don’t be too hard on yourself if this is new to you. I just learned it about too, so you’re in good…​ well…​ you have company. :) ### [Roku and Hotel Wifi](/2018/roku-and-hotel-wifi/) I was recently on a business trip and, as is my custom, I took along my Roku box so that I would have something to watch in the hotel room in the evenings. Unfortunately, the hotel wifi required that you sign in on each device in order to access the internet, but this Roku is old enough that it didn’t offer way to do that. I found some options in The Tubes, but I didn’t care for them for various reasons, but, fortunately, I found an easy — and free — way to do what I needed. The two options I found included buying a "travel router", which might have worked, but that required that I buy the device (they appear to be about $15), but I’m kinda cheap at times, and even if I weren’t, that didn’t help me much at 10:00 at night in the hotel room, so that was out. Another option involved downloading some software to a Windows machine, which, when run, would set up a small wifi network to which I’d connect my Roku. Since I have a Linux laptop, that would be a bit difficult, but, even in the Windows VM I have installed, it also required downloading and running software from a site I’ve not heard of, so I passed. What I finally did was a very simple hack. On the Roku, I looked at the network configuration and took note of the Mac address for the device. On my laptop, I changed the Mac address of my wireless adapter Disconnected and reconnected from the laptop to make the Mac address change take effect. From the laptop, I authenticated on the hotel’s wifi network Also from the laptop, disconnect the laptop’s wifi. Clear the overridden Mac address and reconnected. From the Roku, connect to the hotel wifi Stream until I fall asleep ### [Firefox, Wine, and Linux](/2018/firefox-wine-and-linux/) Wise or not, I recently made the move to Linux on my work machine. For the most part, it works wonderfully. For reasons that aren’t too terribly relevant here, I found myself needing (or wanting) to run the Windows version of Firefox. While I could run it successfully, it wouldn’t connect to the internet. After a whole lot of digging, I finally found the answer, which I thought I should document here with the hope that it will be easier for others to find (including me when I go through this again in a few years ;). The culprit, it seems, is a couple of Firefox settings: browser.tabs.remote.autostart and browser.tabs.remote.autostart2 Once you have Firefox running under Wine, go to about:config in the browser, and enter remote.autostart in the Search box, and change the value of both settings to false: Restart Firefox, and you should be golden. For what it’s worth, credit where credit is due: this is the post that finally got me over the hump. ### [String.split(), Java 8 style](/2017/string-split-java-8-style/) Today I found myself with a common problem: I had a delimited string of an unknown number of parts that that I needed split apart and process. Prior to Java 8, implementing that might looked something like this: for (String part : string.split("\\n")) { if (!myList.contains(part)) { if (!part.isEmpty()) { myList.add(part); } } } While that works and seems to be pretty efficient, I felt it could use a stream makeover, as I find the stream operations to be clearer and more concise. What I ended up with was something like this: Pattern.compile("\\n") .splitAsStream(string) .filter(s -> !myList.contains(s)) .forEach( s -> myList.add(s)); I could also have used Arrays.stream() rather than Pattern: Arrays.stream(string.split("\\" + DELIMITER)) .filter(s -> !myList.contains(s)) .filter(s -> !s.isEmpty()) .forEach(s -> myList.add(s)); I haven’t done any profiling to see if Pattern.compile() has any non-negligible performance impact versus String.split() (and I probably won’t, but you can easily "cache" the compiled pattern in an instance or static variable if needed :), but I will point out this difference: when using split(), streamed or not, we may get a blank value in some situations, so we need to check for that (notice the calls to String.isEmpty() in both of those implementations). With the Pattern-based implementation, we don’t have that problem. At any rate, there you have it: you can convert String.split() to a stream-based implementation fairly easily, and, I think, get more readable code out of it. Any performance implications are left as an exercise for the reader. :) ### [Chesterton's Fence and the Software Developer](/2017/chesterton-s-fence-and-the-software-developer/) Recently at work, we found an odd scenario with a REST (-ish ;) endpoint from another team: If the request provided a list of, say, 11 IDs in the query string, the system would only return information on the first 10 of them, silently dropping anything over that seemingly odd limit. The initial reaction was of, course, "Well, let’s just increase the limit." To be honest, I had the same reaction, but then I remembered one of my favorite quotes, known as Chesteron’s Fence: In the matter of reforming things, as distinct from deforming them, there is one plain and simple principle; a principle which will probably be called a paradox. There exists in such a case a certain institution or law; let us say, for the sake of simplicity, a fence or gate erected across a road. The more modern type of reformer goes gaily up to it and says, "I don’t see the use of this; let us clear it away." To which the more intelligent type of reformer will do well to answer: "If you don’t see the use of it, I certainly won’t let you clear it away. Go away and think. Then, when you can come back and tell me that you do see the use of it, I may allow you to destroy it." — G.K. Chesterton Chesterton’s context, politics in Great Britain of the 1920s, is, of course, quite different from a software development shop almost 100 years later, but the message is still extremely appropriate: Before you go tearing things down or otherwise changing something you’ve found, you really need to understand not only what you’re changing, but why it was made that way in the first place. In the case of this REST call, we should ask questions like Are there system load concerns, such as memory or processing time? Are there concerns about the on-the-wire response size? Was there an explicit Product Management decision to set the limit this low for business reasons we don’t see reflected in the code? And so on. Until we can answer those questions (or reasonably rule them out as irrelevant), we need to be very hesitant in making the change. Once we’ve explained the original developer(s) built that fence, then we can talk about ripping it down. ### [My Book Has Finally Been Published](/2017/my-book-has-finally-been-published/) As the title states, my book has finally been published. You can get it (and you know you want to) at a number of places: Packt Amazon Barnes and Noble I had fun and learned a lot while working on this. I hope you find it useful. ### [Getting JavaFX ListViews to Honor Container Width](/2017/getting-javafx-listviews-to-honor-container-width/) I recently struggled trying to text in a JavaFX ListView to wrap inside the container like I asked it to, rather than extend (and disappear) past the boundaries of the container. After some discussion on Twitter and a bit of Googling, I found an answer that I thought I’d share here to, perhaps, save someone some time. Let’s start by looking at what I’m trying to solve using this contrived example: Notice that the fourth entry is cut off and that the ListView has a scrollbar at the bottom. That’s precisely what I don’t want. Before we see the fix, let’s look at the offending code first. public class ListWidthController implements Initializable { @FXML private ListView listView1; @Override public void initialize(URL url, ResourceBundle rb) { List<String> strings = Arrays.asList( "String 1", "String 2", "String 3", "An arbitrarily long string 4 intended to run too wide" ); listView1.setItems(FXCollections.observableArrayList(strings)); } <BorderPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.steeplesoft.listviewwidth.ListWidthController"> <left> <VBox prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER"> <children> <ListView fx:id="listView1" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" /> </children> </VBox> </left> </BorderPane> This is, of course, an overly simplified example. In most real world cases, I would expect that the ListView would have a custom ListCell, which we’ll need to make this display correctly. We’ll start by adding another ListView to the UI so we can see them at the same time: <BorderPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.steeplesoft.listviewwidth.ListWidthController"> <left> <VBox prefHeight="200.0" prefWidth="100.0" BorderPane.alignment="CENTER"> <children> <ListView fx:id="listView1" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" /> <ListView fx:id="listView2" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" /> </children> </VBox> </left> </BorderPane> In our controller, we inject the new control: @FXML private ListView listView2; and configure it: listView2.setItems(FXCollections.observableArrayList(strings)); Notice that we’re using the same source data for grins. If you were to runt his now, though, you’d get the same result, so let’s add our custom ListCell and get things looking like we want them: listView2.setCellFactory(new Callback<ListView<String>, ListCell<String>>() { @Override public ListCell<String> call(ListView<String> param) { return new ListCell<String>() { { prefWidthProperty().bind(listView2.widthProperty().subtract(20)); // 1 setMaxWidth(Control.USE_PREF_SIZE); //2 } @Override protected void updateItem(String item, boolean empty) { if (item != null && !empty) { this.setWrapText(true); // 3 setText(item); } else { setText(null); } } }; } }); On our second ListView, we pass in a cell factory, which we create using an anonymous inner class, as is the custom in a lot of JavaFX code. The factory returns the custom ListCell, also an anonymous class, where the real work happens. We bind the preferred width of the cell to the width property of the enclosing list. If we bound width to width, the cell would grow to fill the ListView, which would then grow a bit to give room for the cell, which then grow, etc, etc, resulting in a mildly amusing, if wildly incorrect animation in the running application. We end up subtracting a few pixels to give room for control borders, etc. I’m not 100% sure on that, but the sources I found suggested doing that, and leaving it out resulted in a scrollbar still displaying. We set the max width to the computed size which, if I my SWAG is correct, prevents the control from being resized? I could use some clarification on that point. :) We tell the cell to wrap text (if needed). Otherwise, the text would just get cut off at the control border, which is certainly not what we want. Build and run now and you get something like this: B-e-a-utiful. ### [Compiling for Java 8 and Java 9](/2017/compiling-for-java-8-and-java-9/) In a project I’m working on for my book, I need to share classes between two applications. One, an Android project, requires Java 8. The other, a desktop JavaFX application, needs to run under Java 9, complete with module support. The problem with this is that the Maven tooling isn’t quite ready for Java 9, so it’s not as simple as I would like. I have, however, found a solution that seems to work. In this setup, I have three projects: the shared module, the Android project, and the JavaFX project. The shared module looks roughly like this: src main java module-info.java com steeplesoft foo model Message.java Our module is defined this way: module foo.shared { exports com.steeplesoft.foo.model; } We want to compile everything so that the bytecode is usable via the Java 8 JVM, but module-info.java won’t compile for Java 8. Here, we apply some Maven magic: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <executions> <execution> <id>default-compile</id> <configuration> <excludes> <exclude>**/module-info.java</exclude> </excludes> <source>1.8</source> <target>1.8</target> </configuration> </execution> <execution> <id>module-infos</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> <configuration> <excludes> <exclude>**/*</exclude> </excludes> <includes> <include>**/module-info.java</include> </includes> <source>1.9</source> <target>1.9</target> </configuration> </execution> </executions> </plugin> </plugins> </build> We accomplish our goal by configuring the Maven compiler plugin with two different executions. In the first, we compile everything using a source and target of 1.8. For this pass, though, we exclude module-info.java. For the next pass, we compile with a source and target of 9. We also exclude everything so that our Java 8-compatible .class files aren’t overwritten, but we also explicitly include our module-info.java source file. Once this build runs, we’ll have mostly Java 8 .class files in our output directory, with a single Java 9-specific file, module-info.class. The normal Maven process than jars everything up and installs it in our local repository. Over in our Android application, we can then declare the dependency on this jar: repositories { jcenter() mavenCentral() mavenLocal() } // ... dependencies { compile 'com.steeplesoft:foo-shared:1.0-SNAPSHOT' } We can then import and use our model class, Message, and build and run our application. On the Java 9 side, we declare a dependency on our module in the POM, and can configure our application’s Java module like this: module foo.desktop { requires foo.shared; requires javafx.graphics; requires javafx.controls; requires javafx.fxml; } And we can successfully build and run our JavaFX application. Both Android and Java 9 are, as they say, fat, dumb and happy, and we have our shared code in a single project that can be used by both. It’s a bit more XML than we’d probably like, but, as Maven users, we’re probably used to that by now. :) ### [JavaFX Frameworks](/2017/javafx-frameworks/) In my work on my book, I’ve spent quite a bit of time with JavaFX. In the chapter I just submitted, I wrote the application using the NetBeans RCP, which I think is a great piece of software. My only "complaint", I think, is more of a philosophical one more than a technical one, and even stating it that way is probably really over-selling it: for the most part, to use the RCP is to use Swing. Sure, you can use JavaFX in the application, but it seems you have to hold your mouth just right to get two-way data flow working. Possible, but it seems like a bit of work. At any rate, while casting around The Tubes to track down advice on how to solve one problem or another, I ran across a couple of more modern application frameworks that look really promising, Drombler FX and the Dolphin Platform. Both look pretty slick, but the former seems to be backed by "only one guy" and might be a bit slow moving, while Dolphin is backed by Canoo and, more specifically, Michael Heinrichs, Hendrik Ebbers, Dierk König. Once I finish this book and have more time to play with shiny new things, I need to give both of these a spin. I should probably note, though, that there’s nothing really wrong with the NetBeans RCP in any real technical sense (beyond the 'no software is perfect' notion). I just like shiny things. I did, though, successfully create my RCP app and found the experience to be quite nice. If you need a desktop application, you should definitely check out the RCP. ### [Struggling with Swagger Codegen](/2017/struggling-with-swagger-codegen/) For both my day job and a side project, I need want to generate and manage my REST APIs in a contract-first manner using Swagger. From looking at the docs, the answer seems to be Swagger Codegen, but I’m finding that it’s not that simple. Here’s the workflow I’d like to accomplish: One One a One b Two Three Three a ### [Merry Christmas, 2016](/2016/merry-christmas-2016/) In the same region there were some shepherds staying out in the fields and keeping watch over their flock by night. And an angel of the Lord suddenly stood before them, and the glory of the Lord shone around them; and they were terribly frightened. But the angel said to them, "Do not be afraid; for behold, I bring you good news of great joy which will be for all the people; for today in the city of David there has been born for you a Savior, who is Christ the Lord. This will be a sign for you: you will find a baby wrapped in cloths and lying in a manger." And suddenly there appeared with the angel a multitude of the heavenly host praising God and saying, "Glory to God in the highest, And on earth peace among men with whom He is pleased." -- Luke 2:8-14 ### [NetBeans 9 Nightlies](/2016/netbeans-9-nightlies/) Perhaps I’m a bit of a glutton for punishment, but I have an odd addiction to nightly builds. In working on this book, I need to use NetBeans 9, which, of course, is not out yet. They are, however, publishing nightly builds. Being a command line guy at heart, I’d prefer not to have to go to the download page every time, so I did what any good geek would do: I wrote a script. It’s not pretty, and it’s not very fault tolerant, but it seems to work well enough. If you’re a fellow addict, here you go: #!/bin/bash VERS=`curl -s http://bits.netbeans.org/netbeans/trunk/nightly/latest/js/build_info.js | grep BOUNCER_PRODUCT_PREFIX | cut -f 2 -d \"` FILE=$VERS-javase.zip cd ~/Downloads if [ ! -e $FILE ] ; then wget http://bits.netbeans.org/netbeans/trunk/nightly/latest/zip/$FILE if [ -e $FILE ] ; then rm -rf netbeans unzip $FILE fi fi ### [Call Me Crazy, But I'm Writing a Book](/2016/call-me-crazy-but-i-m-writing-a-book/) A few weeks ago, I was approached by an acquisition editor with Packt Publishing, asking if I might be interested in working on a book with them. Long story short, I signed the paper work and started working on the title Java 9 Blueprints. Books in Packt’s Blueprints series offer a different project in each chapter, showing each is built, explaining the technologies used, etc. So far, it feels a lot like what I aim for in my blog posts, only longer. The target release is Q1 of next year. I have a lot of work ahead of me. :) ### [mv /dev/oracle/NetBeans /dev/apache/](/2016/mv-dev-oracle-netbeans-dev-apache/) Yesterday, the NetBeans team announced plans to move NetBeans from Oracle to Apache. This move was met by a mix of skepticism and optimism. I’ve ranged between the two myself, to be honest, but I’ve landed on optimsim. My first thought, snarky as it is, was that "Apache is where projects go to die". Think Apache OpenOffice. After discussing that with some peers, though, I remembered that 1) OpenOffice was already mostly dead before the move (and not even Miracle Max could fix that) and 2) there are a lot of projects that are thriving at Apache such as Cassandra, Hadoop, Maven, Tomcat/TomEE, and the eponymous HTTP server. Moving to Apache, then, isn’t a kiss of death and all, and, given that Apache has over 300 projects, we’re going to see some die from time to time. That’s life in software. I think, though, that this move could be very good overall for NetBeans for the reasons given by various Dream Team members: transparency, easier access, better infrastructure, etc. There’s also a possible political side where some may shy away from contributing (or even using) because it’s an Oracle product, but now might be tempted to give it a go with the Apache label on it. That’s pretty silly and I have nothing to back it up, but I would be shocked if that weren’t the case for at least a small number. All that said, here’s my biggest concern. I worry that over time, Oracle will spend less and less on the project. They do have another IDE, and they already spend quite a bit building tools for Eclipse, so they may decide that it doesn’t make business sense to continue to invest in the platform (some have argued that this is the reason for this move). When Oracle bought Sun, they continued to invest in GlassFish for some time, then decided that it wasn’t making enough money and rather abruptly pulled most of us off the project. I fear that might play out again with NetBeans. Only time will tell, of course, and NetBeans seems to be more importantly strategically for Oracle, with other products integrating with or building on the platform. We’ll see. All told, though, I think this is a great move that, while it does carry some risk, holds tremendous promise for this great IDE and platform. ### [Android App Development Quandary](/2016/android-app-development-quandary/) I have a grand total of one Android application in the Play Store, Cub Tracker. It serves two functions for me: it helps me manage my sons' Cub Scout den, and it gives me a means for experimentation in the mobile realm. For the most part, it has done well for me on both counts for the past few years. I am currently faced with an issue of new functionality (which is mostly irrelevant for this discussion) that has brought up a question in the realm of experimentation. This post is a discussion of my options which will allow me to think out loud, if you will, as well as getting (I hope) some feedback on my options. In a nutshell, I need to add data synchronization to Cub Tracker to allow users to share data amongst themselves (or simply across multiple devices). While there are certainly a number of architectural choices, my current line of investigation uses Google Drive and JSON data files. I have looked at other options — REST, for example — but I’m looking at Google Drive as it seems like it might be the simplest solution. Time will tell, of course. That said, I’ve started working with the Google Drive Android APIs and was making pretty good progress until I ran into a huge roadblock: the Android APIs currently only support accessing files created by your app, which means I can’t access files and folders shared with the user by someone else, which kills the whole point of the exercise. Two options are to use the Drive REST APIs directly, or use the Java APIs. The latter sounds like a better solution, from a type safety and simplicity perspective, and it also opens up a number of other options, which is the point of this whole rambling affair: Options Implement a "native" Android solution (basically what I have now + the Google Drive Java APIs) Implement a "native" Android solution in Kotlin. I’m really enjoying Kotlin, and, so I’ve heard, the Kotlin team has put out a nice library to simplify Android development. Reimplement the application completely using a cross-platform library. Reimplement using a cross-platform application…​in Kotlin. Native Android Solution This is certainly the easiest solution. I already have an existing project, so all I would have to do is add the Google Drive support. It’s also the most boring. :P As I’m sure you’re aware, the wow factor of a solution is the primary consideration when making architectural choices. Native Android Solution in Kotlin This is an incremental change, sort of. The structure of the app, in terms of classes and resources, is the same. The only difference is the language, and the IDE would do most of the work for me in converting the existing code. Making it idiomatic Kotlin might take a good deal of work, but that’s technically not necessary. I could also rewrite the app from scratch in Kotlin, which might clean up some semi-ugly legacyish code as well. Cross-platform Solution There are, of course, a number of options for this, but, since I’m primarly a Java/JVM guy, I’ve narrowed it down to two options: CodenameOne and JavaFxPorts. I haven’t used either enough to have an opinion on which is easier. Either or both may require a recurring cost for building and/or licensing, neither of which is enticing, given that my app is free. I can’t justify paying good money to give something away. The other downside is that resulting app doesn’t really feel like a normal $PLATFORM application. That may not a very big deal, though. There are enough apps out there that have the same problem, that I’m mostly numb to that "problem", but there are others that are not. Gluon Charm would help with that, but while I don’t want a nag screen, I also can’t justify $23/month on a free app. :\ Cross-platform Solution in Kotlin Are you sensing a theme here? This gives me the cross-platform support I’d like, in a pretty cool new language. The biggest issue here is that it’s almost 100% new (ish) technologies at work. I don’t want to be working on this next release forever, so this might be biting off more than is reasonable. That doesn’t mean it won’t happen, though. There you have it. I’m sure there are other options, but I’m trying not to be too wide open. You have to limit your options somewhat, and these are the boundaries I’ve chosen. Hopefully, having typed all of this so I can stare at it will help me reach some sort of decision soon. The next step, I guess, is some proof-of-concept work. If you’ve read this far, I’m guessing you’re at least quasi-curious, so I’ll report back here once I have something worth saying ("unlike this post!"). ### [Merry Christmas, 2015](/2015/merry-christmas-2015/) At the end of another busy year, full of stress and grief, it’s my hope and prayer that the true message of Christmas, not "getting along with family", but the birth of the Savior of the world, would settle your hearts, and that True Peace would be yours. Merry Christmas! ### [Kotlin and CDI](/2015/kotlin-and-cdi/) If you’ve been following my blog, you’ve probably noticed that I’ve been spending a lot of time with Kotlin of late. (For the curious, I really like it so far, but I haven’t done just a whole lot with it.) I’ve experimented with writing simple JSF and JAX-RS apps in it, largely to see if I can make it work. With those hurdles cleared, I’m trying something a bit more ambitious: a complete (if basic) Java EE application, written completely in Kotlin. Because I’m a sucker for a bad joke, I’ve dubbed the project KotlinEE. I’m not quite ready to walk through that application yet, but I what I would like to discuss now is an issue I ran into trying to get CDI working with Kotlin. In theory, it should be pretty straightforward: @ApplicationScoped class DatabaseService { @PersistenceContext(unitName = "em") private lateinit var em : EntityManager init { println("Starting DatabaseService...") } fun getEntityManager() : EntityManager { println("***** From the server: $\{em.delegate.javaClass.name}") return em } } Yes, that’s a really boring service, and, yes, I’m doing something dumb in exposing the EntityManager that way, but I’m just experimenting at the moment: can I expose a Kotlin class as a CDI bean and do something with it in my Arquillian test? The short answer is yes, but there’s a big-ish caveat. By default, Kotlin defines all classes as public and final. Public, since most classes are public anyway and one of Kotlin’s goals is pragmatism, and final because it forces the library developer to think about which methods should be overridable, and prevents unintentional or undesirable overriding where it wasn’t planned for. This poses a problem for CDI (or at least Weld, the CDI implementation that GlassFish and Payara Server use): since these classes and methods are final, the CDI implementation can’t make proxies for them. My first attempt at working around this limitation (which is a JVM-level issue, for what it’s worth), was to mark everything as open: @ApplicationScoped open class DatabaseServiceImpl { @PersistenceContext(unitName = "em") private lateinit var em : EntityManager init { println("Starting DatabaseService...") } open fun getEntityManager() : EntityManager { println("***** From the server: $\{em.delegate.javaClass.name}") return em } } That works, but it’s kind of ugly. If you have a large bean ("Split it up!", some will likely shout, but that’s not always possible, right? :), this can become very cumbersome very quickly, but it also negates Kotlin’s final-by-default protections. Another way, which I think is cleaner, is to define an interface, implement that on your bean, and use the interface as the injected type, rather than the class: interface DatabaseService { fun getEntityManager() : EntityManager } @ApplicationScoped class DatabaseServiceImpl : DatabaseService { @PersistenceContext(unitName = "em") private lateinit var em : EntityManager init { println("Starting DatabaseService...") } override fun getEntityManager() : EntityManager { println("***** From the server: $\{em.delegate.javaClass.name}") return em } } class MyOtherClass { @Inject lateinit var service : DatabaseService } Now I have a nice interface to provide the usual level of abstraction, and Weld/CDI can make the proxies needed to expose this class as a CDI bean. What does the rest of the application configuration look like? You’ll have to wait a bit longer for that. :) Stay tuned…​ ### [Kotlin-RS](/2015/kotlin-rs/) In keeping with theme of "use existing frameworks with Kotlin" and misleading titles, here’s a quick and dirty demonstration of writing JAX-RS applications using Kotlin. For those that read my Kotlin Faces post, the pom.xml for the project will look very familiar: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>Kotlin-RS</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>Kotlin-RS</name> <properties> <endorsed.dir>$\{project.build.directory}/endorsed</endorsed.dir> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <kotlin.version>1.0.0-beta-1038</kotlin.version> </properties> <repositories> <repository> <id>sonatype.oss.snapshots</id> <name>Sonatype OSS Snapshot Repository</name> <url>http://oss.sonatype.org/content/repositories/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>sonatype.oss.snapshots</id> <name>Sonatype OSS Snapshot Repository</name> <url>http://oss.sonatype.org/content/repositories/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>$\{kotlin.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>kotlin-maven-plugin</artifactId> <groupId>org.jetbrains.kotlin</groupId> <version>$\{kotlin.version}</version> <executions> <execution> <id>compile</id> <phase>process-sources</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>process-test-sources</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> <compilerArguments> <endorseddirs>$\{endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> For our REST service, we have a single endpoint that returns (dummy) information on books. Let’s take a look at our model first: data class Book(var name : String, var description : String) { constructor() : this("", "") } Unbelievably verbose, isn’t it? :) There are a few things going on here: Using Kotlin’s very concise class declaration syntax, we are declaring a class, Book, which has two properties, name and description. We get the getters and setters for free since we declared the properties using the var keyword. We’re using Kotlin’s data class feature, which gets us several things (like equals()/hashCode() and toString()) for free. Since we’re defining this as a data class, we must have at least one primary constructor argument. However, for JAX-RS' built-in serialization/deserialization support, we need a no-args constructor, so we define a secondary constructor, using the constructor keyword, which delegates back to the primary. Next up is the resource itself: @Path("/books") class BookResource { @GET fun getBooks(): Array<Book> { return arrayOf( Book("Book 1", "Book 1"), Book("Book 2", "Book 2"), Book("Book 3", "Book 3")) } @GET @Path("\{id}") fun getBook(@PathParam("id") id: String): Book { return Book("Book " + id, "Description " + id) } } Kotlin syntax aside, this should look very familiar. We’re using Java annotations seamlessly, just as one would expect to see them in Java code. The method implementations themselves are very simple, demonstrating the conciseness of Kotlin’s collections support. Note also that creating class instances in Kotlin does not require the new keyword. Attempts to use it will result in a compilation error. Also note that semicolons are not used as line endings. Attempts to use them will result in a compilation error. :) Finally, let’s take a look at the JAX-RS Application class: @ApplicationPath("resources") class MyApplication : Application() { override fun getClasses(): MutableSet<Class<*>>? { val classes = HashSet<Class<*>>() classes.add(BookResource::class.java) return classes } } This class was the trickiest, as it requires direct Java interop. JAX-RS developers are likely familiar with Application.getClasses(). The tricky part here is satisfying this requirement in Kotlin, with the magic incantation being JavaClass::class.java. I can’t find this documented anywhere, so I can’t give a good explanation for it. I was given this tip by my brother, so feel free to pester him. :) Maybe a Kotlin dev will stumble across this and explain it in the comments. UPDATE: Documentation for ::class.java found here. And, like I said list time, that’s it. Build the app (mvn package) and deploy to your favorite container and see it in all of its glory: $ curl -H 'Accept: application/json' http://localhost:8080/Kotlin-RS-1.0-SNAPSHOT/resources/books [{"description":"Book 1","name":"Book 1"},{"description":"Book 2","name":"Book 2"},{"description":"Book 3","name":"Book 3"}] $ curl -H 'Accept: application/json' http://localhost:8080/Kotlin-RS-1.0-SNAPSHOT/resources/books/4 {"description":"Description 4","name":"Book 4"} With a couple of minor caveats, it’s all very straightforward, and very nice. We get all of the benefits of a modern JVM languague without having to learn a whole new ecosystem. ### [Kotlin Faces](/2015/kotlin-faces/) There’s a chance that at least some of you saw the blog title and thought: "Ah ha! A Kotlin wrapper/helper for JSF!" and rushed over to check it out. If so, mission accomplished. :) This really isn’t anything that ambitious. Sorry. :) At JavaOne this week, I spent a good deal of time talk to Hadi Hariri, Developer Advocacy Team Lead at JetBrains, about their Kotlin language. With my long background in Java webapps, I often reach for my webapp hammer when trying to learn a new language, so I asked Hadi what Kotlin library he would suggest. His answer, in a nutshell, was that the Java interop in Kotlin is so good, just use whatever you want, so I thought I’d put that to the test with a really simple JSF app. Here it is. First things first, you will probably want to use IntelliJ IDEA to help with the Kotlin syntax. Also being from JetBrains, IDE support is first rate. :) Before we get to the actual Kotlin, let’s get some minor details out of the way. First, the pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>KotlinFaces</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>KotlinFaces</name> <properties> <endorsed.dir>$\{project.build.directory}/endorsed</endorsed.dir> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <kotlin.version>1.0.0-beta-1038</kotlin.version> </properties> <repositories> <repository> <id>sonatype.oss.snapshots</id> <name>Sonatype OSS Snapshot Repository</name> <url>http://oss.sonatype.org/content/repositories/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>sonatype.oss.snapshots</id> <name>Sonatype OSS Snapshot Repository</name> <url>http://oss.sonatype.org/content/repositories/snapshots</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-web-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> <version>$\{kotlin.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>kotlin-maven-plugin</artifactId> <groupId>org.jetbrains.kotlin</groupId> <version>$\{kotlin.version}</version> <executions> <execution> <id>compile</id> <phase>process-sources</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>test-compile</id> <phase>process-test-sources</phase> <goals> <goal>test-compile</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> <compilerArguments> <endorseddirs>$\{endorsed.dir}</endorseddirs> </compilerArguments> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.3</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </build> </project> Pretty standard with the exception of the kotlin-maven-plugin and Kotlin runtime configuration and related repository entries. You’ll need one for the plugin, and another for runtime libs. Next, the Facelets page: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>JSF+Kotlin Example</title> </h:head> <h:body> <h2>JSF+Kotlin Example</h2> <h:form> <p>Text from a Kotlin-based bean: #\{myBean.text}</p> <h:inputText value="#\{myBean.text}"></h:inputText> <h:commandButton value="Change Me"></h:commandButton> </h:form> </h:body> </html> Nothing unusual there. And now, the moment we’ve all been waiting for: The Kotlin-based managed bean: @Named @SessionScoped class MyBean : Serializable { var text = "My Text" } That’s it. It’s a really dumb bean, but here’s an explanation: There are no parameters declared with the class, so we get a no arg ctor. This may or may not be idomatic Kotlin, but it’s good enough here. :) There’s a single property, text, defined. We give it a default value of "My Text" which also allows the compiler to infer the type, String. We are using Java EE annotations, @Named and @SessionScoped, seamlessly. Just add the imports and move along. And…​ that’s it. Build the app (mvn package) and deploy to your favorite container and see it in all of its glory. Not an exciting app, but that I can make it work with a Kotlin-based class with minimal extra work (just a build tweak) is really cool. With a proof-of-concept done, it’s time to try something more complex, but that’s a story for another time. :) ### [Bad Horse!](/2015/bad-horse/) If you’re a Doctor Horrible fan, here’s something fun and goofy to start your week. No clue how they did it, but it’s hilarious. :) (h/t to my brother) $ traceroute -m 255 bad.horse traceroute to bad.horse (162.252.205.157), 255 hops max, 52 byte packets 1 172.23.195.1 (172.23.195.1) 1.863 ms 1.193 ms 8.432 ms 2 172.23.192.14 (172.23.192.14) 1.251 ms 1.302 ms 2.180 ms 3 172.23.192.1 (172.23.192.1) 0.554 ms 0.401 ms 0.400 ms 4 cox-66-210-47-177-static.coxinet.net (66.210.47.177) 3.500 ms 3.563 ms 3.333 ms 5 cox-68-12-8-220-static.coxinet.net (68.12.8.220) 2.972 ms 2.963 ms 2.983 ms 6 dalsbprj01-ae1.0.rd.dl.cox.net (68.1.2.109) 29.083 ms 26.024 ms 29.997 ms 7 10ge6-9.core1.dal1.he.net (184.105.16.77) 16.917 ms 22.353 ms 17.668 ms 8 10ge12-6.core1.chi1.he.net (184.105.213.118) 29.513 ms 37.725 ms 25.116 ms 9 100ge10-1.core1.msp1.he.net (184.105.223.178) 32.957 ms 32.794 ms 32.878 ms 10 ip-house.gigabitethernet3-6.core1.msp1.he.net (216.66.78.110) 33.122 ms 33.239 ms 33.032 ms 11 c4500-1.mpls.iphouse.net (216.250.189.170) 33.936 ms 33.598 ms 33.692 ms 12 egw-iphouse.mplsc1.mn.us.sn11.net (209.240.64.149) 33.744 ms 33.605 ms 33.668 ms 13 sandwichnet.dmarc.lga1.atlanticmetro.net (208.68.168.214) 56.210 ms 56.156 ms 56.163 ms 14 bad.horse (162.252.205.130) 56.499 ms 56.783 ms 56.824 ms 15 bad.horse (162.252.205.131) 61.368 ms 61.363 ms 61.439 ms 16 bad.horse (162.252.205.132) 66.525 ms 66.505 ms 64.767 ms 17 bad.horse (162.252.205.133) 71.454 ms 71.391 ms 71.412 ms 18 he.rides.across.the.nation (162.252.205.134) 76.406 ms 75.851 ms 76.446 ms 19 the.thoroughbred.of.sin (162.252.205.135) 81.519 ms 81.448 ms 81.426 ms 20 he.got.the.application (162.252.205.136) 86.507 ms 86.381 ms 86.568 ms 21 that.you.just.sent.in (162.252.205.137) 91.715 ms 91.295 ms 91.773 ms 22 it.needs.evaluation (162.252.205.138) 96.556 ms 95.746 ms 96.438 ms 23 * so.let.the.games.begin (162.252.205.139) 101.632 ms 101.821 ms 24 a.heinous.crime (162.252.205.140) 106.578 ms 103.700 ms 106.612 ms 25 a.show.of.force (162.252.205.141) 111.822 ms 111.720 ms 111.808 ms 26 a.murder.would.be.nice.of.course (162.252.205.142) 116.950 ms 116.620 ms 116.451 ms 27 bad.horse (162.252.205.143) 121.838 ms 121.337 ms 122.248 ms 28 bad.horse (162.252.205.144) 126.569 ms 126.612 ms 126.250 ms 29 bad.horse (162.252.205.145) 131.561 ms 131.406 ms 131.673 ms 30 he-s.bad (162.252.205.146) 136.584 ms 136.540 ms 136.502 ms 31 the.evil.league.of.evil (162.252.205.147) 141.520 ms 141.335 ms 140.794 ms 32 is.watching.so.beware (162.252.205.148) 146.593 ms 146.525 ms 146.524 ms 33 the.grade.that.you.receive (162.252.205.149) 151.503 ms 151.561 ms 151.658 ms 34 will.be.your.last.we.swear (162.252.205.150) 156.368 ms 156.522 ms 156.493 ms 35 so.make.the.bad.horse.gleeful (162.252.205.151) 161.639 ms 161.546 ms 159.510 ms 36 or.he-ll.make.you.his.mare (162.252.205.152) 166.361 ms 166.409 ms 166.456 ms 37 o_o (162.252.205.153) 171.485 ms 171.530 ms 171.417 ms 38 you-re.saddled.up (162.252.205.154) 176.307 ms 176.493 ms 176.275 ms 39 there-s.no.recourse (162.252.205.155) 181.482 ms 181.329 ms 179.026 ms 40 it-s.hi-ho.silver (162.252.205.156) 186.695 ms 186.395 ms 185.716 ms 41 signed.bad.horse (162.252.205.157) 199.462 ms 186.534 ms 186.546 m ### [Be Careful with Statics](/2015/be-careful-with-statics/) I recently came across an interesting piece of code at work: private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); What struck me as odd was the private qualifier and that the fact that SimpleDateFormat is not thread-safe. Is the private some odd attempt to work around concurrency issues, or was thread safety just overlooked? That led me to this question: Is a private static still one instance per JVM, or does the private actually change anything? My understanding was that this was a bug, but I thought I’d write a test just to make sure. Let’s start with a class: public class SomeClass { private static int number; public SomeClass(int number) { this.number = number; } public int getNumber() { return number; } } and here’s our simple test: public class StaticTest { public static void main(String[] args) { SomeClass a = new SomeClass(1); SomeClass b = new SomeClass(2); System.out.println("a.number = " + a.getNumber()); System.out.println("b.number = " + b.getNumber()); } } As expected, here’s the output: a.number = 2 b.number = 2 If you’ve been around the block a few times, this probably doesn’t come as a surprise. If you’re newer, though, or haven’t ever had to give it thought, you might be mildly surprised. Either way, the bottom line is this: scope qualifiers don’t modify the behavior of a static, so if the type is not thread-safe, you’ll need a better (read as: correct) way to handle the concurrency concerns. ### [An Introduction to Programming with Minecraft at the Oklahoma City JUG](/2015/an-introduction-to-programming-with-minecraft-at-the-oklahoma-city-jug/) On Monday, July 13, I will be leading the monthly OKC JUG session, whose topic this month is "An Introduction to Programming with Minecraft Mods". We’ll be using a modified version of the curriculum Arun Gupta has developed for this Devoxx4Kids program, with examples taken from the book he and his son wrote, Minecraft Modding with Forge: A Family-Friendly Guide to Building Fun Mods in Java. Here is the announcement sent to the Oklahoma City tech community. If you’re in the area, come check it out! Greetings, Oklahoma City tech community! Do you have a son or daughter (or niece, nephew, grandchild, super-friendly neighborhood child) who loves Minecraft? Does said Minecraftian have an interest in learning how to program? If so, this is your lucky day. The Oklahoma City Java User Group would like to invite you and 0 or more of your pint-sized and precocious progeny to our July session where we’ll be offering an introduction to programming using Minecraft modding as the goal. What will we be doing? We’re going to be getting an introduction to various programming concepts (types, variables, loops, conditionals, classes, etc) using the Java programming language. Having a concrete, usable goal is always more interesting, so we’ll learn these concepts as we develop (and RUN!) simple Minecraft mods. Will my CHILD<Relationship> be an expert programmer or modder when we’re done? Probably not, but the hope is that this session will be enough to flatten the learning curve a bit, leaving each child well-equipped for further study, either self-directed or with you, as well as with a taste for how fun programming can be. How old does you mini-me need to be? That’s entirely up you. If you have, say, a 6 year-old who’s comfortable with compilers and API docs, then that’s old enough for us. Is there anything we need to install before we come? There certainly is! Our time will be limited, so it would be extremely helpful to have a basic, working environment already set up. While you are free to use any IDE you want, I will be using NetBeans, the Free (and TOTALLY AWESOME) IDE from Oracle, which can be downloaded from http://netbeans.org. You will also need a working Java environment, as well as a relatively current copy of the Minecraft Forge plugin development kit. I’ll have detailed instructions at the end of this email to help you set up your environment. This sounds great? When and where is it?! In a departure from our normal schedule (which will be significant only for normal JUG attendees), we will be meeting on Monday, July 13 at 11:30AM at Prototek, which is located at 10th and Hudson in Oklahoma City (https://goo.gl/maps/tD26c). You can park in the dirt lot Hudson, just north of Park Place. Do not park ON Park Place, as I own both that and Boardwalk, and my improvements there are guaranteed to ruin you. That’s right during lunch. What’s wrong with you people? Nothing that some free pizza can’t solve, so bring your appetite! What should we bring to the session? To participate, you will obviously need a laptop to work on, with one per laptop per child (no government organizations/programs, please) being ideal. If you are bringing multiple wee ones and need to share, that would be fine. If you don’t have a laptop and just want to come listen, that will work as well. :) Do I need a Minecraft license? For this session, you do not. The game will run just fine without a license. The only caveat is that you will not be able to connect to any servers without a valid license from Mojang. Is there anything else we need to know? That’s about it. Come prepared to have fun and learn. And don’t forget your questions! We’re pretty excited about this session and hope to see LOTS of kids come out for a fun time. Detailed Pre-Meeting Instructions I made that really large for two reasons: I really wanted to use that formatting bar in Thunderbird that I’ve ignored for so long, and I wanted to make sure you don’t miss this part. :) You can come and set up your laptop at the meeting, but we won’t have time to do that as a group, so we’ll have to keep moving while you’re setting up. If you have to do that, that’s fine. I hope to conscript a few of the JUG leaders to act as workshop assistants in case anyone needs help installing the various pieces. Another issue is bandwidth: Prototek will let us use their wifi, but regardless of their bandwidth, when two dozen people start downloading all of the dependencies, it probably won’t be very fast. :) What do you need to download then? These three things: Java - http://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html. You will need the Java SDK, and I would suggest the latest version, which is currently Java SE 8u45. Download the installer appropriate for your platform and install it. NetBeans - https://netbeans.org/downloads/ - You will need the Java SE version. Again, get the installer appropriate for your platform and install it. Minecraft Forge - http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.8-11.14.1.1341/forge-1.8-11.14.1.1341-src.zip - There are platform-specific installers, but I’d just get this zip With those downloaded and installed, extract the zip file (using the tool of your choice) in a directory. Mac and Linux users can do this: $ cd $ mkdir MinecraftMods $ cd MinecraftMods $ unzip $PATH_TO_ZIP/forge-1.8-11.14.1.1341-src.zip Wherever you’ve extracted the archive, you will need to open a shell (or command prompt) and run this command in that directory: $ ./gradlew setupDecompWorkspace --refresh-dependencies (Windows users can leave off the leading ./) Once that is done, open up NetBeans, then click File | Open Project and navigate to this directory. Hopefully, this directory will show up as a Gradle project. If it does not, you will need to install the Gradle plugin ( Go to Tools | Plugins and install "Gradle Support".) After a few seconds, you should see the project open in the Project view, with several nodes beneath it in the tree. To test things, click on the project node (it should be called MinecraftMods), click Tasks, Run, and runClient. After a few seconds, you should see Minecraft start up. Congratulations, you should be ready to go. Whew! That’s kind of hard to follow! Well, yeah. If you’re like me and like to see pictures, you can see these same instructions on the NetBeans blog at https://blogs.oracle.com/geertjan/entry/seamless_minecraft_forge_in_netbeans. But I don’t like NetBeans. I like pain! There may be some Eclipse fans out there. If you just have to use Eclipse, you can generate the Eclipse project files by running gradlew eclipse. NetBeans is nice and all, but I prefer to buy things. Can I use IDEA? Sure! Just run gradlew idea to generate the project files. Is that "all"? Should be. Pretty simple, huh? :P If you run into problems, try to do as much as you can before you come, and you can either ask for help on the JUG mailing list (http://okcjug.org/contact-us) or, worst-case scenario, wait until the day of the JUG and get help there (though it would help to arrive early ;). ### [Running IDEA 14 on Java 8 on the Mac](/2015/running-idea-14-on-java-8-on-the-mac/) My team at work was having some issues with IDEA and the Checkstyle plugin. Based on the error message, and without actually looking at the JARs, it seemed pretty clear that the issue was a JDK version issue. While I think this issue has been resolved, when I set up my Mac months ago, I was forced to install Java 6 in order to install IDEA, but, apparently, the new version of the Checkstyle plugin was compiled with a newer JDK (as it should be). Whether or not the Java 6 issue still exists with IDEA, you can make IDEA run on Java 8 pretty easily, and I’ll show you how to do it. The first step, of course, is to install a more current JDK, which means (at the time of this writing), unless you have compelling reasons not to, Java 8 build 45. Because we all long for the glory days of Sun, you can download the JDK at http://java.sun.com. Once that’s done, you need to update the Info.list for IDEA, which is found at /Applications/IntelliJ IDEA 14.app/Contents/Info.plist. Open that file in your favorite editor (which we all know is vim), and find this entry: <key>JVMVersion</key> <string>1.6*,1.7+</string> It should look something the above. To enable Java 8, change that last line to something like this: <key>JVMVersion</key> <string>1.8*</string> Save the file, and restart IDEA 14. If you look at the application’s About dialog, you should now see that you are running on Java 8. Enjoy! :) ### [Changing the GlassFish Admin Users's Password Programmatically](/2015/changing-the-glassfish-admin-users-s-password-programmatically/) Recently, in the #glassfish channel on Freenode, a user was having trouble configuring GlassFish in a Docker environment. He was scripting the configuration of the server, but was having trouble setting the admin user’s password, since the change-admin-password command takes input from stdin. Fortunately, there’s REST API for that. This curl command will do what the user needs to do without any need for additional input: curl -X POST \ -H 'X-Requested-By: YeaGlassFish' \ -H "Accept: application/json" \ -d id=admin \ -d AS_ADMIN_PASWORD=password \ -d AS_ADMIN_NEWPASSWORD=password2 \ http://localhost:4848/management/domain/change-admin-password Once the password is set, this same command can be used to change the password, but --user admin:$PASSWORD must be added to authenticate the request. I should note that I don’t think this is an officially supported way to execute asadmin commands. It works, but it may change, or it may go away. I would say that Oracle may not support doing this either, but they don’t offer any support, so there’s no harm there. :) Also note that AS_ADMIN_PASWORD has a typo in it that may be fixed in future releases of the server. Caveat emptor! :) ### [Custom Maven Packaging Type](/2015/custom-maven-packaging-type/) As I’ve noted in a previous post, I recently moved my blog from Awestruct to JBake. This also allowed me to migrate the building and publishing of the blog contents to the toolchain that I know pretty well (Maven). What bothered me, though, was that my POM defined the project as a jar packaging type: the build produces no jar file and, in fact, doesn’t process any Java at all. What I wanted, then, was to be able to define the lifecycle in such a way the the compile phase didn’t try to compile anything, and the install phase didn’t try to put anything in my local repo. Unfortunately, either I’m a bit dense, or the documentation wasn’t very clear (it’s likely a combination of both :). At any rate, I finally had a eureka moment late last night and figured it out. Here is a distillation of my findings. To define a custom packaging type, you define a custom lifecycle and put the packaging type in the role-hint element. All of this is done in components.xml, which is found in src/main/resources/META-INF/plexus. This file can be in a project whose packaging is either pom or maven-plugin (others may be possible. I haven’t tried). At any rate, here is the components.xml which accomplishes my goal (no pun intended ;) for the JBake Maven plugin: <component-set> <components> <component> <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role> <role-hint>jbake</role-hint> [1] <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation> <configuration> <lifecycles> <lifecycle> <id>default</id> [2] <phases> <generate-resources></generate-resources> <process-resources></process-resources> <compile> $\{project.groupId}:$\{project.artifactId}:$\{project.version}:generate [3] </compile> <process-test-resources></process-test-resources> <test-compile></test-compile> <test></test> <package></package> <install></install> <deploy></deploy> </phases> </lifecycle> <lifecycle> <id>site</id> [2] <phases> <pre-site></pre-site> <site> $\{project.groupId}:$\{project.artifactId}:$\{project.version}:generate </site> <post-site></post-site> <site-deploy></site-deploy> </phases> </lifecycle> </lifecycles> </configuration> </component> </components> </component-set> [1] role-hint defines the new packaging type [2] We’re overriding the default and site lifecycles, providing goals only for the relevant phases. [3] Note how the desired goal is specified. On the plugin side, that’s literally all there is to it. When the target project is configured correctly, all the user must do to generate the site is issue a simple mvn, mvn compile, or mvn site, and the site is generated in target/$\{project.artifactId} (by default). The plugin build does, though, need one tweak: <build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build> This allows us to update the project metadata without having to edit components.xml. Bump the version? Change the artifactId? No problem, thanks to resource filtering. In the target project(s), you obviously need to configure the plugin. For my blog build, that looks like this: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>steeplesoft-blog</artifactId> <name>Steeplesoft Blog</name> <version>1.0-SNAPSHOT</version> <packaging>jbake</packaging> [1] <!-- ... --> <plugin> <groupId>br.com.ingenieux</groupId> <artifactId>jbake-maven-plugin</artifactId> <version>0.0.10-SNAPSHOT</version> <extensions>true</extensions> [2] <!-- ... --> Note that we’ve changed the packaging type now to jbake (1), and we’ve add the plugin to the build with extensions set to true (2). This is very important, as I understand it, as it instructs Maven to load the plugin early enough in the process so that our new lifecycles are applied to the project. And that’s all there is to it. For the curious, you can see this change in action in my fork of jbake-maven-plugin on GitHub. I’ve submitted a PR, but the main project doesn’t seem to be too active, so we’ll what happens and go from there. At any rate, I hope this adds some clarity to the topic of custom Maven packaging types. If you have questions, comments, criticisms, etc., hit the form below. ### [From Awestruct to JBake](/2015/from-awestruct-to-jbake/) For some time now, I have been using awestruct to power my blog, and, for the most part, I’ve been happy. However, I have found, especially on the Mac, the Ruby-based environment more difficult to setup than I would like. While I have solved this problem before, it presented itself once again when I was issued a Mac upon joining NetSuite. I can, of course, muddle through it, but I’m tired of fighting it, so I started looking around for an alternative and found JBake. JBake, described by Dan Allen as the "jekyll of the JVM", is a Java-based static site generator. While the language the tool is written in is not all that relevant in terms of site generation, it is important to me as a developer who has, from time to time, "needed" to extend the tool in one way or another. Being Java-based also makes it a bit easier to integrate with my toolchain (NetBeans, Maven/Gradle, Hudson/Jenkins) for composing and publishing posts. Long story short (too late!), I’ve taken the plunge and migrated my site to JBake. Naturally, as these things usually happen to be, JBake didn’t support everything I needed, namely, pagination, so I did what all geeks do: I started coding. Currently, pagination lives in my fork. A pull request has been created to integrate this into JBake proper, but, for now, you must build and use my fork. Also note that, while pagination requires no external changes for a user not interested in pagination, things may change as the PR is considered and processed. Of course, the PR could ultimately be rejected, but I’ll cross that bridge if I ever get there. :) To build it, I used the JBake Maven Plugin. Sadly, again, I needed to fork the plugin to update it to use the current JBake API, so, again, a local build and install. Neither of these is ideal, but, hopefully, these requirements will go away shortly. There is one more piece that awestruct provides that JBake does: deployment. For that, I simply added a stanza to my Maven POM, which I control/hide behind a profile: <profiles> <profile> <id>deploy</id> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>properties-maven-plugin</artifactId> <version>1.0-alpha-2</version> <executions> <execution> <phase>initialize</phase> <goals> <goal>read-project-properties</goal> </goals> <configuration> <files> <file>site.properties</file> </files> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.3.2</version> <executions> <execution> <id>deploy-blog</id> <phase>install</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>rsync</executable> <workingDirectory>$\{project.build.directory}/$\{project.build.finalName}</workingDirectory> <arguments> <argument>-aP</argument> <argument>--delete</argument> <argument>-e ssh</argument> <argument>.</argument> <argument>$\{blog.username}@$\{blog.host}:$\{blog.dir}</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> It was a bit more work than I’d anticipated, but, in the end, I think it’s been worth it. The only change in the site itself is the feed link has change from feed.atom to feed.xml. If you happen to see other issues, though, please let me know. ### [Multitenant PostgreSQL](/2015/multitenant-postgresql/) As more and more of our applications move into "the cloud", multi-tenancy has become a pretty big thing these days. In a nutshell, "multi-tenancy" means handling multiple customers data using, say, a single server. This concept scales, of course, to clusters, etc., but the concept is the same: a bunch of people’s data all mixed together in one big bucket. The problem, then, for the development team is isolating one customer’s data from another’s, disallowing, for example, the viewing or editing of another customer’s information. There are a myriad of ways to accomplish this, but I’d like to discuss here a way to accomplish this using a single database. While the concept can certainly be applied on just about any database, for this discussion, we’ll use PostgreSQL, my favorite database (and, yes, as a geek I’m allowed to say things like that). The concepts we’ll use are views, triggers, and session variables. To keep things simple, our entity/model will be a very simple one called Item, which has one column, data. The DDL for its table might look something like this: CREATE TABLE items ( id SERIAL, data text ); It’s not very exciting, but that’s OK. I’m probably not either. In thinking about multiple customers, though, we need a way to discriminate between one customer’s Items and another, so we’ll add a company ID: CREATE TABLE items ( id SERIAL, company_id int not null, data text ); But how do we restrict customer #1 from seeing customer #2’s data? We’ll do that with a view: CREATE OR REPLACE VIEW company_items AS SELECT * FROM items WHERE company_id = ... As you can tell, that’s not quite going to work. Where does the value for company_id come from? The answer to that is session variables. Unfortunately, as best as I can tell, Postgres doesn’t support this idea natively, so we have to roll our own, which we’ll do using plperl, the Postgres extension which allows writing stored procedures in Perl. There are other languages available, and perhaps I’ll port this to, say, Python, because Perl is pretty nasty stuff. :) Nevertheless, this is working code: CREATE OR REPLACE FUNCTION set_var(name text, val text) RETURNS text AS $$ if ($_SHARED{$_[0]} = $_[1]) { return 'ok'; } else { return "cannot set shared variable $_[0] to $_[1]"; } $$ LANGUAGE plperl; CREATE OR REPLACE FUNCTION get_var(name text) RETURNS text AS $$ return $_SHARED{$_[0]}; $$ LANGUAGE plperl; This creates two functions, set_var and get_var, whose functionality should be apparent from the function names. With these in place, we can update the view as follows: CREATE OR REPLACE VIEW company_items AS SELECT * FROM items WHERE company_id = cast (get_var('company_id') AS NUMERIC); To get the value from a function in Postgres, you SELECT from it, which we’ve added to the query that builds the view. You’ll also notice that get_var and set_var deal with strings, so the value needs to be cast to NUMERIC or the view creation will fail. With all of this in place, we can test this using psql: (1) mydb=# insert into items (company_id, data) values (1, 'Company 1 data 1'); mydb=# insert into items (company_id, data) values (1, 'Company 1 data 2'); mydb=# insert into items (company_id, data) values (1, 'Company 1 data 3'); mydb=# insert into items (company_id, data) values (2, 'Company 2 data 1'); mydb=# insert into items (company_id, data) values (2, 'Company 2 data 2'); (2) mydb=# select * from company_items; id | company_id | data ----+------------+------ (0 rows) (3) mydb=# select set_var('company_id', '2'); set_var --------- ok (1 row) (4) mydb=# select * from company_items; id | company_id | data ----+------------+------------------ 4 | 2 | Company 2 data 1 5 | 2 | Company 2 data 2 (2 rows) (5) mydb=# select set_var('company_id', '1'); set_var --------- ok (1 row) (6) mydb=# select * from company_items; id | company_id | data ----+------------+------------------ 1 | 1 | Company 1 data 1 2 | 1 | Company 1 data 2 3 | 1 | Company 1 data 3 (3 rows) 1 Create the data 2 Select from the view 3 Set the current company ID 4 Select from the view again and see data 5 Change the company ID 6 Select from the view again and see different data As you can see, the contents of the view company_items is controlled by the current state of the session variable company_id. It’s also clear that if it’s not set, then the view is empty, clearly indicating that the app must take care to set this session variable on each use. In the context of a web app, this would be done per request, just after authentication: the user’s credentials are verified, the company to which the user belongs is identified, and the session variable is set. One thing to be careful about that I have not yet had the chance to test is this: in a pooled connection environment, is the value of the session variable cleared when the connection is returned to the pool? My guess is that it is not. How to manage that, though, is beyond the scope of this post. One final nugget. In such an environment, it would be nice if the application didn’t have to remember to set the company ID on the Company_Item explicitly. We can, in fact, handle that in the database layer with a trigger: CREATE OR REPLACE FUNCTION set_item_company() RETURNS trigger AS $$ BEGIN NEW.company_id = (select cast (get_var('company_id') AS NUMERIC)); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER set_item_company BEFORE INSERT OR UPDATE ON items FOR EACH ROW EXECUTE PROCEDURE set_item_company(); With this trigger in place, whenever a client inserts into either company_items or items, the field company_id is set automatically to whatever the current state of the session variable company_id is. Depending on your application’s architecture, frameworks, etc., this may not be necessary, but, if it’s helpful (and possible), this is an approach for handling it. There you have it. The seeds, at least, of a fairly robust multitenant database approach that doesn’t involve separate databases or schemas for each tenant. As long as your application operates on only the views (exercise for the reader: can access to the tables be restricted at the database-level, leaving only the views accessible?) you should have a nice, clean segregation of customer data that is easy to maintain and migrate. Find any holes? Problems? Brain dead ideas? Let me know below! 8-) ### [Merry Christmas 2014](/2014/merry-christmas-2014/) To all of my readers, I wish you all a very Merry Christmas. My hope, as always, is that even in the busyness and the hustle of the Christmas season, you will find the peace and joy of God brought to us so many years ago in the birth of the Christ child. Christmas Time Again by Smalltown Poets ### [Book Review: RESTful Java Patterns and Best Practices](/2014/book-review-restful-java-patterns-and-best-practices/) I recently received a copy of RESTful Java Patterns and Best Practices, by Bhakti Mehta for review. Here are my thoughts on the book. Bhakti Mehta is a former coworker of mine from Sun/Oracle. We both worked on the GlassFish project, though not on the same team. RESTful Java Patterns and Best Practices is a short book, covering many topics. If I had to pick one main issue, that would be this: it felt a bit short to me. That said, the book is well-written, with plenty of examples. The topics covered in the book are: An introduction to REST Resource design Security and traceability Performance Advanced design principles (rate limiting, pagination, i18n/l10n, and HATEOAS) Emerging standards Each of the chapters introduces the topic at hand, then gives an example or three of the options a developer has in that area. For example, in the resource design chapter, Mehta discusses content negotiation, then shows how it can be done using both HTTP headers and URL patterns. Advice is given on which option to choose and why. The security chapter discusses SAML and OAuth, describing how each approach works. I would have liked to see much more depth here, as this is an area that I, personally, would like a more solid understanding of, but an adequate, thorough discussion of that topic could probably be a book by itself. The book closes with an appendix that briefly describes three different public APIs: GitHub, Facebook Graph, and Twitter. I thought this was a good addition, as it gives concrete examples of some of the topics discussed in the book, allowing the reader to see what the ideas might look like in practice. Overall, this was a pretty good book. As I noted at the start, I would really have liked to see more depth in each of the sections. However, Packt has positioned with book as a "Starting" level: "Accessible to readers adopting the topic, these titles get you into the tool or technology so that you can become an effective user." So, despite what I would like to see, I think the book ably accomplishes the goal of the publisher. Four stars. ### [Contract-First REST APIs with RAML](/2014/contract-first-rest-apis-with-raml/) Yesterday, at the OKC JUG, I presented on the topic of Contract-first REST API development with RAML. This post is a rough blogification of that discussion. For those of you who were at the meeting, the preamble to the source demo (introduction, background, options discussion, etc) have been not been reproduced here. tl;dr: You can find the demo source here and play around with it. Introduction RAML is a specification for describing REST interfaces with the intention of generating servers, clients, and documentation. It’s a product of the RAML Workgroup. One of the first questions that may pop up for anyone who has been working with REST (especially in the Java space) is, "What about Swagger?" Mulesoft answers that question: Mulesoft originally started with Swagger but realised that standard was best suited to documenting an existing API, not for designing an API from scratch. RAML evolved out of the need to support up-front API design in a succint, human-centric language. The Root Section That said, let’s take a look at a sample RAML spec file. We’ll start with the basics: #%RAML 0.8 title: "JUG - RAML" version: v1 baseUri: https://localhost:8080/raml/resources protocols: [ HTTPS ] mediaType: application/json documentation: - title: Home content: | JUG - Contract-first with RAML This "root" section describes some top-level metadata for the API. Of the values here, only title and baseUri are required, and should be self-explanatory. The mediaType value describes the default media type for the resources described in the spec. Schemas Typically, when designing a system, I like to think in terms of data models first, as it helps me grasp exactly what I’ll be working with, so we’re going to take a look at how we describe models in a RAML document, which happens under the schemas key: schemas: - author: | { "$schema": "http://json-schema.org/draft-03/schema", "type": "object", "description": "A single author", "properties": { "id": { "type": "integer", "required": true}, "name": { "type": "string", "required": true }, "books": { "type": "array", "items": { "$ref":"book" } } } } - book: | { "$schema": "http://json-schema.org/draft-03/schema", "type": "object", "description": "A single book", "properties": { "id": { "type": "integer", "required": true}, "name": { "type": "string", "required": true }, "isbn": { "type": "string", "required": true }, "author_id" : { "type": "integer" } } } - authors: | { "$schema": "http://json-schema.org/draft-03/schema", "type": "object", "description": "a collection of authors", "properties": { "size": { "type": "integer", "required": true }, "authors": { "type": "array", "items": { "$ref": "author" } } } } - books: | { "$schema": "http://json-schema.org/draft-03/schema", "type": "object", "description": "a collection of books", "properties": { "size": { "type": "integer", "required": true }, "books": { "type": "array", "items": { "$ref": "book" } } } } Here, we have a list of schemas: author, book, authors, and books. The first thing you may notice is that the schema definitions look and awful lot like JSON, and that’s because they are. Internally, the RAML tools use jsonschema2pojo to generate the Java classes for the models. Looking at the author example, we see that the model will have three properties: id, which will be the primary key name, which is the author’s name books, which is an array of book instances. Note the value for the items property in the schema definition. The $ref key tells the schema generator that the array will hold references to book instances. We’ll see that type show up in the generated code: /** * A single author * */ @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({ "id", "name", "books" }) public class Author { /** * * (Required) * */ @JsonProperty("id") @NotNull private Integer id; /** * * (Required) * */ @JsonProperty("name") @NotNull private String name; @JsonProperty("books") @Valid private List<Book> books = new ArrayList<Book>(); @JsonIgnore private Map<String, Object> additionalProperties = new HashMap<String, Object>(); /** * * (Required) * * @return * The id */ @JsonProperty("id") public Integer getId() { return id; } /** * * (Required) * * @param id * The id */ @JsonProperty("id") public void setId(Integer id) { this.id = id; } public Author withId(Integer id) { this.id = id; return this; } /** * * (Required) * * @return * The name */ @JsonProperty("name") public String getName() { return name; } /** * * (Required) * * @param name * The name */ @JsonProperty("name") public void setName(String name) { this.name = name; } public Author withName(String name) { this.name = name; return this; } /** * * @return * The books */ @JsonProperty("books") public List<Book> getBooks() { return books; } /** * * @param books * The books */ @JsonProperty("books") public void setBooks(List<Book> books) { this.books = books; } public Author withBooks(List<Book> books) { this.books = books; return this; } @JsonAnyGetter public Map<String, Object> getAdditionalProperties() { return this.additionalProperties; } @JsonAnySetter public void setAdditionalProperty(String name, Object value) { this.additionalProperties.put(name, value); } public Author withAdditionalProperty(String name, Object value) { this.additionalProperties.put(name, value); return this; } } There are a lot of unexpected (to me) annotations in the generated class, but those are Jackson annotations, as we instructed the Maven plugin (which we’ll look at below) to use Jackson as the JSON mapper. Notice also that each property has some Javadoc for it. If you want to provide a more helpful description, you can specify that in your schema definition: "name": { "type": "string", "required": true, "description": "The author's full name" } which generates /** * The author's full name * (Required) * * @return * The name */ @JsonProperty("name") public String getName() { return name; } The authors and books schemas deserve a special mention. If you walk through the official RAML tutorial, this is the pattern they use. For the collection resources (those that return all of the author and book instances, for example), they wrap the list in a simple model which exposes two properties: the size of the list, and the list itself. While I can’t say why they did that, I can say that in my attempts to "fix" that ran into an issue: the POJO mapping feature in Jersey that I used in the demo does not know how to serialize a List (or a Map) as the root object type. Obviously, it can handle a List as a property as the books properties are both mapped as List s. Either I’m missing something in terms of configuring the feature, or using a List here would require a custom MessageBodyWriter to handle. For the sake of simplicity, I opted to follow the example from the RAML tutorial. Resources Now that we’ve defined the data we’ll be working with, let’s expose those models via REST resources. To define an endpoint, you start the key name with a /: /authors: get: description: Get a list of all the authors in the system responses: 200: body: application/json: schema: authors post: description: Add author body: application/json: schema: author responses: 201: body: application/json: schema: author /id/\{authorId}: uriParameters: authorId: displayName: Author ID type: integer get: description: Retrieve a specific author responses: 200: body: application/json: schema: author post: description: Update an author body: application/json: schema: author responses: 200: body: application/json: schema: author delete: description: Delete an author responses: 200: /books: get: description: Get a list of all of the books in the system responses: 200: body: application/json: schema: books post: description: Create a book body: application/json: schema: book responses: 201: body: application/json: schema: book /id/\{bookId}: uriParameters: bookId: description: Book ID type: integer get: description: Get a book responses: 200: body: application/json: schema: author We’ve defined 4 resources here: 2 root-level, and 2 sub-resources. Taking the /books resource as an example: The resource supports the GET method, which can return the HTTP status code 200. The response body will be a books instance encoded as JSON. The resource also supports the POST method. It takes a book instance, encoded as JSON, as the payload. Upon success, it will return a 201 (Created) and the newly created book instance, also encoded as JSON. The resource also has a sub-resource, identified by /id/{bookId}. This subresource will return a specific book, identified by its id. The book’s ID is specified as a path parameter via a syntax that should be familiar to JAX-RS users. We also describe that parameter, called a uriParameter in the RAML spec, as an integer whose description is "Book ID". When this spec is processed, you’ll get a class that looks like this: @Path("books") public interface Books { /** * Get a list of all of the books in the system * */ @GET @Produces({ "application/json" }) Books.GetBooksResponse getBooks() throws Exception ; /** * Create a book * * @param entity * */ @POST @Consumes("application/json") @Produces({ "application/json" }) Books.PostBooksResponse postBooks(Book entity) throws Exception ; /** * Get a book * * @param bookId * Book ID */ @GET @Path("id/\{bookId}") @Produces({ "application/json" }) Books.GetBooksIdByBookIdResponse getBooksIdByBookId( @PathParam("bookId") Long bookId) throws Exception ; public class GetBooksIdByBookIdResponse extends com.steeplesoft.jug.raml.support.ResponseWrapper { private GetBooksIdByBookIdResponse(Response delegate) { super(delegate); } /** * * @param entity * */ public static Books.GetBooksIdByBookIdResponse jsonOK(Author entity) { Response.ResponseBuilder responseBuilder = Response.status(200).header("Content-Type", "application/json"); responseBuilder.entity(entity); return new Books.GetBooksIdByBookIdResponse(responseBuilder.build()); } } public class GetBooksResponse extends com.steeplesoft.jug.raml.support.ResponseWrapper { private GetBooksResponse(Response delegate) { super(delegate); } /** * * @param entity * */ public static Books.GetBooksResponse jsonOK(com.steeplesoft.jug.raml.model.Books entity) { Response.ResponseBuilder responseBuilder = Response.status(200).header("Content-Type", "application/json"); responseBuilder.entity(entity); return new Books.GetBooksResponse(responseBuilder.build()); } } public class PostBooksResponse extends com.steeplesoft.jug.raml.support.ResponseWrapper { private PostBooksResponse(Response delegate) { super(delegate); } /** * * @param entity * */ public static Books.PostBooksResponse jsonCreated(Book entity) { Response.ResponseBuilder responseBuilder = Response.status(201).header("Content-Type", "application/json"); responseBuilder.entity(entity); return new Books.PostBooksResponse(responseBuilder.build()); } } } Notice that this is a Java interface, so we’re not quite ready to deploy this just yet. The code generator also creates several ResponseWrapper subclasses and uses those as the return types for the Java methods. These classes handle building the Response to hand off to the JAX-RS runtime. This might be a slightly different approach than you may be used to using in your JAX-RS resources, but that’s the price you pay when have a third party handle code generation. :) Resource Types If you look back at the RAML file, you’ll see a lot of duplication (e.g., the post fields on the root-level resources are almost identical, with the only difference being the schema type). Fortunately, RAML provides a way to avoid a lot of this duplication via the concept of resourceTypes: resourceTypes: - collection: get: responses: 200: body: application/json: schema: <<schema>> post: body: application/json: schema: <<schema>> responses: 201: body: application/json: schema: <<schema>> - member: get: responses: 200: body: application/json: schema: <<schema>> post: body: application/json: schema: <<schema>> responses: 200: body: application/json: schema: <<schema>> delete: responses: 200: In looking at our resources, you can see we have two types: one returns a collection of a certain type, and the other returns a specific, single instance of that type. We have, then, collection and member resources, which we’ve modeled in our RAML spec above. The first type, collection, defines two methods, GET and POST, with the types of expectations and behaviors we described above. Note, though, that the schema definition looks a bit different. The value [schema] declares a variable whose value will be defined when we use the resourceType. The member type does the same thing, mirroring what we did for our subresource above. So how do we do these? It requires one small addition to the resource definition, and allows us to remove quite a bit at the same time. Here is the /books resource, modified to use the appropriate resource types: /books: displayName: BooksResource type: { collection: { schema: books } } get: description: Get a list of all of the books in the system post: description: Create a book /id/\{bookId}: type: { member: { schema: book } } uriParameters: bookId: displayName: Book ID type: integer get: description: Get a book Notice that we’ve added type key to the root resource, as well as the subresource. Taking the first instance, we’re telling RAML that this resource’s type is collection, and its schema (which is the variable we declared in the resource type definition) is books. The subresource is member type and uses book as its schema. Any other variables you may wish to define in the resource type would be defined inside the innermost block (where schema is defined). Having made this change, we can regenerate the source and see that we haven’t change a thing there. We’ve simply moved some of the boilerplate out of the resource definition, making them much simpler. This concept of resource types is, I think, really significant, as it lets us describe what all resources of this type will look like. In my experience with writing the Java code first, things tend to get out of sync overtime: a number of Java resources are written, then a new requirement is handed to development, requiring, say, certain query parameters to be added to each resource to enable some fancy new feature. The developers then have to change the code for each resource, making sure to change each and every method. While there are other ways to mitigate that some in Java-first approaches, this contract-first approach, coupled with the resourceTypes concept, makes it much easier: the appropriate type is updated as needed, the Java interface s are generated, and the code refuses to compile until the implementation is updated. We catch the changes at compile-time, rather than letting them slip through to QA or, even worse, production to be discovered by accident when someone tries to use the new feature. I think that’s a pretty handy feature. :) Traits Let’s take a look at one more concept in RAML: traits. If you’re familiar with traits or mixins in languages like Scala, this will be pretty simple. Bascially, you’re defining some added characteristics you want to expose. For example, let’s say you want to allow the user to page through a collection (if this were an Amazon API, you certainly wouldn’t want all of the authors or books in the system). To do that, we’d describe the trait like this: traits: - paged: queryParameters: start: displayName: start description: The first page to return type: integer pages: displayName: pages description: The number of pages to return type: integer This trait adds two query parameters: start and pages, which related metadata. To apply the trait, add the is key to the resource or resource type: resourceTypes: - collection: get: is: [ paged ] Now, all resources of type collection will have paging support: /** * Get a list of all the authors in the system * * @param pages * The number of pages to return * @param start * The first page to return */ @GET @Produces({ "application/json" }) AuthorsResource.GetAuthorsResponse getAuthors( @QueryParam("start") Long start, @QueryParam("pages") Long pages) throws Exception ; A trait can also declare variables: - searchable: queryParameters: query: description: | JSON array [{"field1","value1","operator1"},{"field2","value2","operator2"},...,{"fieldN","valueN","operatorN"}] <<description>> example: | <<example>> which can be defined using a child object in the is usage: is: [ searchable: { description: "with valid searchable fields: name", example: "[\"name\", \"Wheel of Time\"]" } ] In this example, we see the value of is is an array, albeit with one value. If you want to apply multiple traits, you’d simple add more items to this array, separating them by commas: is: [ trait1, trait2: { foo: "bar" } ] Documentation Documentation generation, something developers have a love/hate relationship with, is pretty simple to generate from the RAML spec. I prefer to have the documentation generated as part of the build process, but I have not found a Maven (or Gradle) plugin to handle that. I did find, however, a nice command line tool, raml2html, which produces nice, clean output: $ npm i -g raml2html $ raml2html src/main/resources/raml/spec.raml You can see a sample of the output here: The Build While not the point of this entry, I do want to show you the relevant portions of my pom.xml to help get you going: <plugin> <groupId>org.raml.plugins</groupId> <artifactId>raml-jaxrs-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <sourceDirectory>$\{basedir}/src/main/resources/raml</sourceDirectory> <basePackageName>com.steeplesoft.jug.raml</basePackageName> <jaxrsVersion>2.0</jaxrsVersion> <useJsr303Annotations>true</useJsr303Annotations> <jsonMapper>jackson2</jsonMapper> <removeOldOutput>true</removeOldOutput> </configuration> <executions> <execution> <goals> <goal>generate</goal> </goals> <phase>generate-sources</phase> </execution> </executions> </plugin> This will output the generated sources in $\{project.build.directory}/generated-sources/raml-jaxrs and update the project model accordingly, so any IDE with decent Maven support should pick up your changes seamlessly. Conclusion As I noted in my presentation, I haven’t used this in anger yet, but it certainly looks promising. There are certainly some code style issues I either need to solve or get over (e.g., I’d love to see JPA annotations on the models, and I’d rather see subresources emitted as classes rather than methods on the parent). Overall, though, I think this is definitely a tool (and an approach) worth keeping an eye on. While clearly still under development (the current version is 0.8), RAML is already showing a good deal of promise for clean, simple, contract-first development. The YAML syntax is concise and readable, and the code generation seems to be ### [So long, and thanks for all the fish](/2014/so-long-and-thanks-for-all-the-fish/) As so many of my friends and peers have done before me, it’s time to use that admittedly overplayed Douglas Adams quote and announce my departure from Oracle. I joined Sun Microsystems in July of 2008 as a member of the GlassFish team, working primarily on the Administration Console. Over time, I would add REST to my work load, which has been my primary responsibility for the past few years. I’ve had the opportunity and honor to work with some very smart and talented people over the last six years. I’ve learned a lot from them, and made some great friends. While it’s nothing as drastic as the destruction of the Earth to make way for an intergalactic highway, the time has come, though, to bid farewell to those friends and the job that’s offered me so much opportunity and growth and move on to a new venture and more great opportunities and chances to learn and grow. It’s been a pleasure. ### [Can I Use Dropwizard for This?](/2014/can-i-use-dropwizard-for-this/) I’ve been toying with using DropWizard as my…​ deployment platform for a personal project, but I need/want JAX-RS 2 and CDI, which is a problem for the the stable DW. There is a branch that is migrating to JAX-RS 2 (and Jersey 2.9), and it sort of works, but trying a simple injection is causing a failure I can’t quite figure out: Caused by: A MultiException has 1 exceptions. They are: 1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=SayHelloService,parent=HelloWorldResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,288169102) at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74) at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:838) at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:890) at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:880) at org.glassfish.jersey.server.ApplicationHandler.initialize(ApplicationHandler.java:517) at org.glassfish.jersey.server.ApplicationHandler.access$500(ApplicationHandler.java:163) at org.glassfish.jersey.server.ApplicationHandler$3.run(ApplicationHandler.java:323) at org.glassfish.jersey.internal.Errors$2.call(Errors.java:289) at org.glassfish.jersey.internal.Errors$2.call(Errors.java:286) at org.glassfish.jersey.internal.Errors.process(Errors.java:315) at org.glassfish.jersey.internal.Errors.process(Errors.java:297) at org.glassfish.jersey.internal.Errors.processWithException(Errors.java:286) at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:320) at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:285) at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:310) at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:170) at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:358) at javax.servlet.GenericServlet.init(GenericServlet.java:244) at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:540) ... 36 more Caused by: org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=SayHelloService,parent=HelloWorldResource,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,288169102) ... 55 more If I create the Weld runtime and request the beans specifically, I get to good objects (instances of both A and B, with B having an injected instance of A), but once I tell DW to fire things, the app dies: Weld weld = new Weld(); WeldContainer container = weld.initialize(); container.instance().select(SayHelloService.class).get(); SayHelloService service = WeldContext.INSTANCE.getBean(SayHelloService.class); final HelloWorldResource resource = container.instance().select(HelloWorldResource.class).get(); resource.setTemplate(configuration.getTemplate()); resource.setDefaultName(configuration.getDefaultName()); final TemplateHealthCheck healthCheck = new TemplateHealthCheck(configuration.getTemplate()); environment.healthChecks().register("template", healthCheck); environment.jersey().register(resource); It seems, then, my deployment environment will be, at least for now, a Java EE app server. They’re small enough these days that it really shouldn’t matter. I was just curious to see if DW might be viable for me, and it appears that the answer is "not yet". I’ll check back later. ### [Book Review: JavaFX 8: Introduction by Example](/2014/book-review-javafx-8-introduction-by-example/) Carl Dea, this time with the help of Mark Heckler, Gerrit Grunwald, José Pereda, and Sean Phillips, recently published an updated and greatly expanded introductory work on JavaFX, with both the title and content updated to reflect the updates in the JDK and library. tl;dr: A solid introduction with a plethora of usable examples. You can purchase it here. To start with, let’s take a quick glance at the table of contents: Getting started JavaFX Fundamentals Java 8 Lambda Expressions Layout & UI Controls Graphics with JavaFX Custom Controls Media with JavaFX JavaFX on the Web JavaFX 3D JavaFX and Arduino JavaFX on the Raspberry Pi Gesture-based Interfaces Appendix A. References As you can see, there is wide array of topics, starting with some very fundamental topics (covering JavaFX and Java 8 fundamentals), then moving on to more complex topics. If you’re familiar with the updates in Java 8, then chapter 3 can probably be safely skipped, but chapter lays the foundation on which the rest of the book is read. Rather than walking through each chapter, I’ll say this: each chapter is clear and well-written, providing copious amounts of sample code. One of the things I really liked about the examples is that, usually, each example source/application was shown in its entirety, then the authors walk through each significant section of code explaining the whats and whys, repeating the source for easy viewing. Furthermore, whether by luck or design, the code is formatted very neatly and displays perfectly on my Android tablet. I’ve read a lot of technoical books, and, more often than not, the code wraps oddly and is hard to read. With very few exceptions, the code was all neatly formatted so that it displayed cleanly on the ereader, which made it much easier to read. The book ends with what I would consider a bit more advanced topic: JavaFX and the Internet of Things (IoT. As an aside, I really hate that term :). To be honest, I only lightly skimmed these chapters, as I’m not even thinking of working in this area at the moment. From the scan, though, the chapters look pretty solid, with plenty of advice in selecting and setting up your board, to getting your application to run on it. Should I ever venture into this realm, I’ll definitely have to revisit this section. The last chapter (actually an appendix), is called "References", and it is exactly that: 16 pages of links, and it might be one of the best parts of the book. Being an introduction to JavaFX, there’s no way the authors can cover everything you need to know about the topic, so Appendix A comes to the rescue with link after link to help you go deeper. Topics include: Java 8 SDK and APIs, IDEs, Properties and Bindings, Layouts, Tools, Enterprise GUI Frameworks, and on and on. If my count is correct, there are links to 210 difference resources. I don’t remember the last time I saw such an exhaustive list in a book like this. As I said at the beginning, this is a very solid introduction to JavaFX. The prose is well-written and easy to follow, and there are ample, ready to use examples for each topic. If you are interested in JavaFX in even the slightest way, this is a great place to start. In case you missed the link earlier, you can purchase the book direct from the publishers here. ### [LiveJournal Export](/2014/livejournal-export/) I have a personal LiveJournal blog that I’d like to migrate to Awestruct. Unfortunately, LiveJournal’s export tool is really limited, allowing the export of only one month at a time. There are tools to work around that, but the only ones I’ve seen require Windows, which rules me out. In typical geek fashion, then, I wrote my own tool, ljexport, a very quick-and-dirty JavaFX 8 application. All this does is export each month to its own file. Once you have the data, you’re on your own. :) ### [JavaFX and Maven](/2014/javafx-and-maven/) I’ve been tinkering with a couple of different JavaFX projects for a while now. Due to other commitments, they’ve been largely ignored recently, but I made some time this weekend to return to them. Since I last looked at them, Java 8, and, thus, JavaFX 8, have been release, so I decided to see how the tooling in NetBeans has changed to stay apace with the development of the libraries. While there are certainly updates, it seems new projects are still built using Ant. Yuck. :P I knew Adam Bien had a Maven archetype for his igniter.fx project, so I took a look to see what that POM does to support JavaFX. As it turns out, it’s pretty simple. For those interested, I have extracted here the basic POM: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>MY_GROUP</groupId> <artifactId>MY_ARTIFACT</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>ARTIFACT_NAME</name> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> <build> <defaultGoal>clean package</defaultGoal> <plugins> <plugin> <artifactId>maven-dependency-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>unpack-dependencies</id> <phase>package</phase> <goals> <goal>unpack-dependencies</goal> </goals> <configuration> <excludeScope>system</excludeScope> <excludeGroupIds>junit,org.mockito,org.hamcrest</excludeGroupIds> <outputDirectory>$\{project.build.directory}/classes</outputDirectory> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <id>package-jar</id> <phase>package</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>$\{env.JAVA_HOME}/bin/javafxpackager</executable> <arguments> <argument>-createjar</argument> <argument>-nocss2bin</argument> <argument>-appclass</argument> <argument>MAIN_CLASS</argument> <argument>-srcdir</argument> <argument>$\{project.build.directory}/classes</argument> <argument>-outdir</argument> <argument>.</argument> <argument>-outdir</argument> <argument>$\{project.build.directory}</argument> <argument>-outfile</argument> <argument>$\{project.artifactId}-app</argument> <argument>-v</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project> The interesting parts are the two plugins, maven-dependency-plugin and exec-maven-plugin. The first takes all of the non-system-scoped dependencies, and extracts the jars into $\{project.build.directory}/classes. This makes the dependencies available to the application without having to manage a bunch of jars, which is helpful when distributing the app. Speaking of which, the next plugin, exec-maven-plugin, packages the application as a JAR using the javafxpackager tool in JAVA_HOME (make sure you change MAIN_CLASS ;). Once you package the app, it can be run with a simple java -jar target/ARTIFACT_NAME-app.jar. While this POM differs a bit from Adam’s POM (e.g., I keep the resources, such a .fxml files, in the standard Maven location), NetBeans is more than happy with it, and my JavaFX hacking is a bit simpler. ### [14 NetBeans Web Development Tips in 7 Minutes](/2014/14-netbeans-web-development-tips-in-7-minutes/) Recently, Geertjan Wielenga, Principal Product Manager in the Oracle Developer Tools group, posted a video on his blog showing "14 NetBeans Web Development Tips in 7 Minutes", which showed off several nice tips for the IDE (#1 and #5 are my favorites). If you’re like me, sometimes you don’t have (or don’t want to make) time to watch a video, so I thought I’d make a table of contents for the video, with links to relevant portion of it for those that would like to read the list and watch only the parts that interest them. Tip Video Link 1 You can quickly drag and drop resources from the Projects window into HTML files watch 2 You can use predefined code templates to generate chunks of HTML. Press TAB to expand the template watch which can be easily configured and you can create new ones. watch 3 "scr" expands to "script", which has a hidden feature: code completion when you press Ctrl-Space. watch 4 Hold down the CTRL key and the selected references is a hyperlink that can be clicked to open the file. watch 5 Select the content of a tag and press CTRL-R, if you want to change both sides of the tag at once. watch 6 Ctrl-Shift-Up/Down and Alt-Shift-Up/Down copy/move lines up and down. watch 7 Splitting a document window is easy…​ watch …​and you can also drag a document to split the editor area. watch 8 Use the Options window to configure the editors for all the languages you use. watch 9 You can change the tab position, e.g, make all the tabs in the editor be displayed in the bottom of the editor. watch 10 The Terminal Window can be very useful. No need to switch of NetBeans to the command line anymore. watch 11 Each HTML5 project integrates with the standard HTML5 technologies, e.g., SASS, Cordova, Karma, etc. watch 12 Block selection lets you change code across multiple lines. watch 13 Press Ctrl-Shift-Enter to create a "notepad look and feel", i.e., a very simplified version of the IDE, without toolbars, etc. watch 14 Want to see the spaces and tabs? That can be done too. watch If you have time, of course, watch the whole thing. If you’d just like to see the list of tips, there you have it. :) ### [File Uploads with JAX-RS 2](/2014/file-uploads-with-jax-rs-2/) If you search for how to upload a file to a JAX-RS 2 endpoint, most suggestions will point you to implementation-specific approaches. While that works, it defeats one of the purposes of a spec: portability. There are some posts out there that will point you in the right direction, though. What I’ll do here, then, is present a clear, portable solution to the problem. In this example, we’re going to upload arbitrary, binary data. Let’s think of this in HTML terms: we have a form on a page that has a number of text input fields, and at least one file field. In this example, we’ll use two fields: name, and attachment. A Java model (which will become more important later), might look like this: public class Example { private String name; private byte[] attachment; public String getName() { return name; } public void setName(String name) { this.name = name; } public byte[] getAttachment() { return attachment; } public void setAttachment(byte[] attachment) { this.attachment = attachment; } } One way of getting the data passed to a JAX-RS resource would be to use @FormParam. Normally, this will work fine, but since we’re wanting a file to be part of the payload, the request must be of type multipart/form-data, which @FormParam doesn’t seem to like. Fortunately, the Servlet 3 spec provides an implementation-independent way of dealing with multipart requests: javax.servlet.http.Part, which we’ll use here. First, the resource method itself: @POST @Consumes(MediaType.MULTIPART_FORM_DATA) public Response formPost(@Context HttpServletRequest request) { MultipartRequestMap map = new MultipartRequestMap(request); Example example = new Example(); example.setName(map.getStringParameter("name")); example.setAttachment(readFile(map.getFileParameter("attachment"))); return Response.ok(buildMessage(example.getName(), example.getAttachment().length)).build(); } Before looking at where things actually get done, just a quick note here. We are asking the JAX-RS runtime to inject the HttpServletRequest, which we pass to MultipartRequestMap (see below). We then pull the fields we want from our Map, build a model object that we don’t do much with, then return a simple String response to show that we did something. Pretty simple. And now, the details: public class MultipartRequestMap extends HashMap<String, List<Object>> { private static final String DEFAULT_ENCODING = "UTF-8"; private String encoding; private String tempLocation; public MultipartRequestMap(HttpServletRequest request) { this(request, System.getProperty("java.io.tmpdir")); } public MultipartRequestMap(HttpServletRequest request, String tempLocation) { super(); try { this.tempLocation = tempLocation; this.encoding = request.getCharacterEncoding(); if (this.encoding == null) { try { request.setCharacterEncoding(this.encoding = DEFAULT_ENCODING); } catch (UnsupportedEncodingException ex) { Logger.getLogger(MultipartRequestMap.class.getName()).log(Level.SEVERE, null, ex); } } for (Part part : request.getParts()) { String fileName = part.getSubmittedFileName(); if (fileName == null) { putMulti(part.getName(), getValue(part)); } else { processFilePart(part, fileName); } } } catch (IOException | ServletException ex) { Logger.getLogger(MultipartRequestMap.class.getName()).log(Level.SEVERE, null, ex); } } public String getStringParameter(String name) { List<Object> list = get(name); return (list != null) ? (String) get(name).get(0) : null; } public File getFileParameter(String name) { List<Object> list = get(name); return (list != null) ? (File) get(name).get(0) : null; } private void processFilePart(Part part, String fileName) throws IOException { File tempFile = new File(tempLocation, fileName); tempFile.createNewFile(); tempFile.deleteOnExit(); try (BufferedInputStream input = new BufferedInputStream(part.getInputStream(), 8192); BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(tempFile), 8192);) { byte[] buffer = new byte[8192]; for (int length = 0; ((length = input.read(buffer)) > 0);) { output.write(buffer, 0, length); } } catch (Exception e) { e.printStackTrace(); } part.delete(); putMulti(part.getName(), tempFile); } private String getValue(Part part) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), encoding)); StringBuilder value = new StringBuilder(); char[] buffer = new char[8192]; for (int length; (length = reader.read(buffer)) > 0;) { value.append(buffer, 0, length); } return value.toString(); } private <T> void putMulti(final String key, final T value) { List<Object> values = (List<Object>) super.get(key); if (values == null) { values = new ArrayList<>(); values.add(value); put(key, values); } else { values.add(value); } } } This class is based on one by BalusC, though I’ve simplified it some (e.g., removing any EL concerns), so his very well may be more robust. This works well enough, though, for demonstration purposes. The most interesting part (no pun intended :) is in this loop: for (Part part : request.getParts()) {. In a nutshell, we’re looping though each Part returned by the server. If the Part has a file name, we assume (!!!) it’s a binary part, so we handle it accordingly. Otherwise, we’ll store the value as a simple String. Note that a key might be given more than once in a request, so we store the values for each key in a List. This Map implementation, though, provides convenience methods to get the first value in the List, which is what we’re interested in. If you’re curious about how the binary data is read off the request, look at processFilePart. If you deploy the application now, you’ll get an error at runtime because you need to configure multipart support. It’s a bit obnoxious that there aren’t sensible defaults, but that’s the way it is. In this example, we don’t have any other configuration requirements, we’ll just use the JAX-RS standard application: <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <servlet-name>javax.ws.rs.core.Application</servlet-name> <multipart-config> <location>/tmp</location> <max-file-size>35000000</max-file-size> <max-request-size>218018841</max-request-size> <file-size-threshold>0</file-size-threshold> </multipart-config> </servlet> <servlet-mapping> <servlet-name>javax.ws.rs.core.Application</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> The area of interest is the <multipart-config> element. Feel free to tweak the values as you see fit. It might be possible to use annotations (e.g., @ApplicationPath, @MultipartConfig, etc) to register all of this without the deployment descriptor, but I haven’t figured out the correct incantation yet, so I use web.xml. :) We’re now ready to deploy and test, which we’ll do using curl: $ curl -X POST -H 'Accept: application/json' \ -F 'name=Form Upload Example' \ -F 'attachment=@src/main/resources/java.jpg' \ http://localhost:8080/upload-1.0-SNAPSHOT/upload You uploaded an Example named 'Form Upload Example' with an attachment that is 9425 bytes long. And there it is! POSTing a binary file to a JAX-RS resource. As I mentioned earlier, there is another, perhaps better way. If you’re using "real" models, there’s no extra magic required: @POST @Consumes(MediaType.APPLICATION_JSON) public Response jsonPost(Example example) { return Response.ok(buildMessage(example.getName(), example.getAttachment().length)).build(); } which can be called with: curl -X POST -H 'Content-type: application/json' \ -H 'Accept: application/json' \ -d '{"attachment":"binary data here","name":"JSON Example"}' \ http://localhost:8080/upload-1.0-SNAPSHOT/upload For this method, JAX-RS (possibly Jersey. I haven’t tested that.) unmarshalls the JSON for us, building the Example instance, and calling the resource method. It’s much easier and cleaner, so if you can go that route, I’d certainly recommend it, but that’s not always possible. Now, though, you should be equipped to do it either way. ### [Book Review: Java EE and HTML5 Enterprise Application Development](/2014/book-review-java-ee-and-html5-enterprise-application-development/) I was recently sent a copy of Java EE and HTML5 Enterprise Application Development by John Brock, Arun Gupta, and Geertjan Wielenga. This is my review of the book. SY300.jpg" alt="Cover" width="162" height="300"> While this a fairly short book (176 pages), the authors managed to work a fair amount in. As you probably guessed from the title, the book covers Java EE in the context of an HTML5 application. Given the size of the book and the fairly large and expansive scope of Java EE, not every Java EE topic is covered. What the authors have done, however, is cover some of the basic Java EE concepts that one might need to get started with an HTML5 application in an EE environment. The topics covered in detail are JPA (persistence), JAX-RS (REST), and Java API for WebSocket, all discussed in just enough detail to get you going, but no so much that you’re buried in details. The first chapter is an introduction to tools being used, HTML5, Java EE 7, and NetBeans. With this book being from Oracle Press (disclaimer: I work for Oracle as well), one might expect to see a slant toward Oracle tools (in fact, two of the authors, Brock and Wielenga, work directly on NetBeans). What we find in the book, however, is the use of NetBeans not as a marketing tool, but as a way to simplify the development effort. Before any steps are shown in the IDE, the code-by-hand approach is shown first, followed by how to accomplish the same thing using the IDE. A developer is free to choose any IDE he wants, of course, but showing "all" of them (or at least the three major players) isn’t practical, so a choice had to be made. Given that Oracle is the primary contributor to NetBeans, its choice makes perfect sense. As it turns out, in my opinion, it just so happens that NetBeans is a great tool for the job, so it works out well. :) Others may wish that a different IDE had been used, so, if you’re one of those people, you’ve been warned. :) The book then spends a chapter each on persistence, REST, and websockets, covering each of the server-side technologies in turn, giving, as I stated earlier, a just-enough amount of information to get you going. To truly master each of these will likely take some more reading and certainly more experience, but the text covers enough to give a solid, if basic, understanding of how techonology works. Chapter 5 is a discussion of HTML5 and related/supporting technologies, such Twitter Bootstrap, jQuery, Knockout.js, SASS/SCSS. It’s in this chapter, I think, that things really start to come together. Having spent three chapters discussing the server-side, including lots of example code, we finally get to see how to tie everything together on the client. There is an extensive discussion regarding the REST calls, along with some very helpful tips regarding testing and testability. Being primarily a server-side guy these days, I found the discussion of two-way data binding and Model-View-ViewModel (MVVM) via Knockout very instresting and helpful. There is a lot of HTML and JS in the chapter, and, honestly, staring at it on the printed page can get a bit overwhelming for the longer HTML examples, but it is helpful to see the context of the code/markup being discussed. You (or at least I) have to read a bit more carefully. After each example, though, the authors do a great of breaking down the code, explaining all of the important/immediately relevant areas, so if you’re having trouble parsing some of that, you should be OK to skip ahead to the discussion, then come back later when you understand things better. The last chapter in the book might be the most important: web application security. This topic, like Java EE and HTML5 separately, can be a very complex, long-winded discussion. That it’s included at all, though, is very nice, as it’s a strong hint to the reader that application security is something to designed into the app at the earliest stage possible, rather than bolted on later. Much like the Java EE technologies earlier in the book, this chapter doesn’t provide a deep dive into each topic, but does explain various security concerns (such as cross-site scripting (XSS), cross-site request forgery (CSRF), and clickjacking) in enough detail to help you understand what’s going, but also provides some code and guidelines to help mitigate the risks that these attacks represent. The chapter ends with a discussion of authentication and authorization, complete with code and tips to help get you going on both sides of the application. This is a short book, but the authors managed to pack in it a very clear, easy-to-read introduction to a number of technologies and concerns. If you have a lot of experience in writing these kinds of apps, there may not be much here for you. If, however, you’re strong on the client but weak on the server (or vice-versa), this is a great, quick read that should get you moving in the right direction in no time. ### [Book Review: 50 Android Hacks](/2014/book-review-50-android-hacks/) 50 Android Hacks by Carl Sessa is, as you may have deduced from the title, a collection of 50 tips and tricks to help Android developers of all skill levels handle a variety of problems. For the most part, I found the book very helpful. Before I get to that, I have a minor quibble: I’m not sure "hacks" was the best choice of words. I understand the marketing aspect of it, but when I hear "hack", I think of a piece of code I’m embarrassed to share with someone else, of something I’d prefer to hide. These "hacks" seem anything but. Clean, clear, efficient, something to be proud of. It’s a minor quibble, of course, but there it is. :) The book itself is pretty easily laid out. If you’ve read a "cookbook", then you should be comfortable and familiar with the basic layout. Each chapter is a different tip, which range from the "easy" (e.g., centering text in a view) to the more advanced (e.g., using the SyncAdapter). The topics covered include layouts, animations, build tools and more. I read this, appropriately enough, using the Kindle App on my Android tablet, and the experience was very good. I’ve read several programming books on my tablet, and they usually have issues with unreadable source code, large blanks due to content flow issues, etc. Some of this is affected, of course, by the font size and is fixable, but I saw none of those issues here. All of the source, both XML and Java, were neatly formatted and readable, with no odd, jarring line wrap issues. The graphics were crisp and readable, and the pages were neat and clean. This is a great book, especially for beginning to intermediate Android developers, but I’d wager that there’s something here for just about everyone. ### [CLI Libraries Compared](/2014/cli-libraries-compared/) I recently ran across a couple of pretty cool libraries for creating command-line tools: Airline from the Airlift project, and crest from Tomitribe. Having spent the last few years working on administration for GlassFish, this is an area near and dear to my heart, so I thought I’d cobble together a quick example using each to see how usable they are. Before we look at the code, I need to lay out a few caveats. First, both of these projects seem to be pretty new. Neither has reached a 1.0 release, and crest, in fact, was "cobbled" together rather recently it seems (though if it were just cobbled together, it seems very feature rich and well-coded). Second, I’m very new to both of these projects, so my implementations may be non-optimal. Neither project has very much documentation (though the READMEs in the respective GitHub repos seem to have enough to get you started). Lastly, to keep things simple yet a bit more interesting than the projects' examples, we’ll interact with an existing system, a GlassFish 4 server; we’ll implement a very basic REST-based deploy command. With that said, let’s get started. Contents Airline Crest Build Notes Closing Airline Each Airline-based command is coded as a class which implements Runnable. In the example in the README, some basic, shared functionality is implemented in a base class (which implements Runnable) and each command extends this class. Let’s see how this looks in our scenario: public class AirlineGlassFish { public static void main(String[] args) { CliBuilder<Runnable> builder = Cli.<Runnable>builder("glassfish") .withDescription("Sample airlift-based CLI for managing GlassFish") .withDefaultCommand(Help.class) .withCommands(Help.class, Deploy.class); Cli<Runnable> gitParser = builder.build(); gitParser.parse(args).run(); } public abstract static class GlassFishCommand implements Runnable { @Option(type = OptionType.GLOBAL, name = "-h", description = "host") public String host = "localhost"; @Option(type = OptionType.GLOBAL, name = "-p", description = "port") public int port = 4848; protected final Client client; protected GlassFishCommand() { client = ClientBuilder.newClient(); } protected WebTarget getBaseTarget() { return client.target("http://" + host + ":" + port) .path("/management") .path("domain"); } } @Command(name = "deploy", description = "Deploy an application") public static class Deploy extends GlassFishCommand { @Arguments(description = "Archives to deploy", required = true) List<String> fileNames; @Override public void run() { WebTarget target = getBaseTarget().path("applications") .path("application"); MultivaluedMap props = new MultivaluedHashMap(); props.add("id", fileNames.get(0)); Response r = target.request(MediaType.APPLICATION_JSON) .header("X-Requested-By", "airlift") .post(Entity.entity(props, MediaType.APPLICATION_FORM_URLENCODED), Response.class); try { if (r.getStatus() != Status.OK.getStatusCode()) { final JSONObject entity = new JSONObject(r.readEntity(String.class)); System.err.println("Deploy failed: " + entity.getString("message")); throw new RuntimeException(); } else { System.out.println("The application has been deployed."); } } catch (JSONException ex) { Logger.getLogger(AirlineGlassFish.class.getName()) .log(Level.SEVERE, null, ex); } } } } Looking first at GlassFishCommand, we have a base class that exposes some options that will be shared amongst the various GlassFish-related commands, name host and port. Using the Option annotation, we can specify the type (COMMAND, GLOBAL, or GROUP), the option name, and the option description. There doesn’t appear to be a way to have long and short names (-h and --host). Default values, it seems, are handled by initializing the instance variable as I’ve done here. The class Deploy is annotated with @Command, which specifies the name and description for the command. Using @Arguments, we are able to specify that the command, in addition to the options listed above, takes a list of arguments at the end of the command line. The actual implementation of the command lives in the run() method specified by the Runnable interface. I’ll not go through the details of that, as that’s outside the scope of this post. Finally, if you look back at main(), you see how Airline is made aware of our new command(s). Using a builder patter, we specify the description, default command, and list of command classes. We then build the CLI parser, parse the args, and run the command. A sample invocation might look like this: $ java -jar target/airline-demo-1.0-SNAPSHOT.jar deploy /path/to/myapp.war The application has been deployed. Crest Command implmentation in crest is a bit different. Crest uses methods annotated with @Command rather than classes: public class CrestGlassFish { public static void main(String... args) throws Exception { final Main main = new Main(CrestGlassFish.class); main.main(new SystemEnvironment(), args); } @Command(value = "deploy") public String hello( @Option("host") @Default("localhost") String host, @Option("port") @Default("4848") int port, @Option("archive") @Required URI archive) { Client client = ClientBuilder.newClient(); WebTarget target = getBaseTarget(client, host, port) .path("applications").path("application"); MultivaluedMap props = new MultivaluedHashMap(); props.add("id", archive.toString()); props.add("force", "true"); Response r = target.request(MediaType.APPLICATION_JSON) .header("X-Requested-By", "airlift") .post(Entity.entity(props, MediaType.APPLICATION_FORM_URLENCODED), Response.class); try { if (r.getStatus() != Response.Status.OK.getStatusCode()) { final JSONObject entity = new JSONObject(r.readEntity(String.class)); System.err.println("Deploy failed: " + entity.getString("message")); throw new RuntimeException(); } else { return "The application has been deployed."; } } catch (JSONException ex) { Logger.getLogger(CrestGlassFish.class.getName()) .log(Level.SEVERE, null, ex); } return "error"; } protected WebTarget getBaseTarget(Client client, String host, int port) { return client.target("http://" + host + ":" + port) .path("/management").path("domain"); } } Let’s look at hello() first. Note that the method name is not the same as the command name. It can be, of course, but crest (as does Airline) allows the developer to override the command name. The command options are implemented as annotated method parameters (as opposed to Airline’s instance variables). Crest’s annotations seem to be a bit more robust, as it offers @Default and @Required. This is a nice approach, clearly exposing the JAX-RS influence that creator David Blevins talks about, but I haven’t figured out how to have shared parameters (e.g., host and port). Exposing the command to crest can be in two ways, currently. The first, I demonstrate here: I create an instance of org.tomitribe.crest.Main, passing a list of classes that contain commands, then I call Main.main(Environment env, String[] args). This isn’t currently documented anywhere (I had to read the crest source, and it’s very pretty, in my opinion, but it’s fast and works. :) The other option, which is not as fast, is to use xbean-based classpath scanning by adding org.tomitribe:tomitribe-crest-xbean:$\{crest.version} to your build file. Build Notes To make these easy to run, I borrowed the use the Maven shader plugin from the crest README to make an executable "uberjar": <build> <defaultGoal>install</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass> org.tomitribe.crest.Main </mainClass> <!-- <mainClass> com.steeplesoft.clis.crest.GlassFish </mainClass> --> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> The mainClass will vary, of course, based on which library you’re using and how it’s configured. For both Airlift and the first crest configuration, the mainClass will be the one where you configure and run the libraries. If you’re using crest+xbean, mainClass will be org.tomitribe.crest.Main. Closing If I had to choose a library right now, it would be a touch choice, though I lean a bit toward Crest. The libraries have slightly different approaches to exposing commands (classes vs methods), so since neither is inherently better than the other, personal preference will be a large factor here. I like the method-based approach used by Crest, but, so far, there doesn’t seem to be a way to share options between commands, which the Class-based approach of Airline makes very clean and simple. This lack, if indeed it is, in Crest can be fixed of course. The library is fairly new, and David is more than happy to take pull requests, so that’s an option. Neither library seems to offer very good support for returning error messages and codes to the command line. Currently, it seems pretty clumsy and opaque. Airline seems to be a bit lighter in terms of dependencies (the final jars, including my Jersey deps, were 3.9M for Airline and 5.5M for crest), but crest seems to offer a bit more for it e.g., Bean Validation support for the options). Disk space is cheap, of course, so that may not be an issue for some, but it is certainly something to keep in mind, especially if you’re adding one of these libraries to an already large project. Regardless of which library you choose, they both offer great libraries for creating command line utilities with minimum effort. Both being very young products, they also present a lot of growth potential, as well as a great opportunity to get involved in open source development for interested parties. You can find the source for these demos in my Bitbucket repo. ### [Integrating Bitbucket and Jenkins](/2014/integrating-bitbucket-and-jenkins/) If you’re like me, you have your source code hosted in a hosted environment (such as Bitbucket), but you have a local continuous integration server (such as Jenkins). It would be really nice if you could have Jenkins build your project every time you commit, but without the heavy requirement of polling your repo. In this post, I’ll show you how to integrate the two to do just that. The first step is to get Jenkins set up (the zeroth step, of course, is to have your code hosted by Bitbucket. I’ll leave that as an exercise for the reader ;). The basic job set up will vary, based on your project’s needs (Maven, Gradle, etc), so I’ll also leave that up to you. Once the project is setup, though, we need to configure remote access. This is done by selecting "Trigger builds remotely" under Build Triggers (and deselecting everything else). You will now be prompted to enter an Authentication Token. You can either create this yourself, or use, e.g., a password generator to do it for, which I would suggest, as it needs to be secure: Once that is done, you might kick off a build to verify your Jenkins configuration. Before we leave Jenkins, we need to get an API token for the user who will do the builds. This assumes, of course, that you have your instance secured, which I think is a reasonable assumption to make. To do that, from the Jenkins home page, click on People, click on the desired user, click configure on the left, then, finally, click on the API Token button. Copy that value and save it somewhere. With that done, we need to configure our Bitbucket repo now. Start by going to your project’s administrative area and clicking on hooks (https://bitbucket.org/{user}/{project}/admin/hooks). From the dropdown, select Jenkins, click Add Hook, then click on the edit link next to the newly created hook and fill in the form: The endpoint, as shown in the image, will be {user}:{token}@\{jenkins URL}. The module name must match exactly what you called it Jenkins, so I would suggest avoiding spaces in the name unless you don’t mind URL-encoding the module name. The token, of course, is the authentication token created above. Click save, and you should now be ready to test the integration by pushing a change to the Bitbucket repo. Within just a few seconds, you should be able to see the build job running on your local Jenkins server. That assumes, of course, that that machine is addressable from outside your firewall. If it’s not, you’re probably stuck with either polling or building on a schedule. If your network supports it, though, this is a great way to get continuous builds when you need them without having to hammer the Bitbucket servers. ### [Android Lifecycles](/2014/android-lifecycles/) I’ve been getting a number of bug reports from my app Cub Tracker that had me stumped. I was getting NullPointerExceptions where I shouldn’t be. After some digging, I think I finally found the culprit: device rotation. While rotating the device does, indeed, trigger the error, it goes deeper than that. My problem is that the app doesn’t correctly save the state of the view, which becomes problematic when, for example, the device is rotated. In trying to fix that, I discovered I don’t understand the Android lifecycle as well as I should, so I set out to fix that. First off, for those that may not realize it, when an Android device is rotated, the current Activity is destroyed and recreated. This is done, at least in part, in case the Activity wants to use a different layout for the new screen dimensions. This is clearly documented for anyone interested in read the documentation. Ahem. At any rate, I cranked out a very simple app that logs when certain lifecycle events happen: Table 1. Android Lifecycles User Action Lifecycle Event Bundle? App Start onCreate No onStart - onPostCreate No onResume - onPostResume - Home onSaveInstanceState Yes onPause - onStop - App Restart onRestart - onStart - onResume - onPostResume - Rotate Screen onSaveInstanceState Yes onPause - onStop - onDestroy - onCreate Yes onStart - onRestoreInstanceState Yes onPostCreate yes onResume - onPostResume - Back/App Shutdown onPause - onStop - onDestroy - Something that surprises me is that when the user presses home, the state is saved in onSaveInstanceState, but when the app is restarted, onRestoreInstanceState is not called, nor is any other lifecycle method that takes a Bundle as far as I can tell. Maybe that’s the way it’s supposed to be, or maybe I’m missing something. In the meantime, though, it seems that I need to implement onSaveInstanceState and onRestoreInstanceState in each of my activities (as well as any Fragments, as they follow a similar lifecycle). That should cover the majority of my state-related NPEs, which is an improvement. I’ll have to keep digging to figure out state handling in the Home/Restart scenario. ### [Merry Christmas 2013](/2013/merry-christmas-2013/) As is my custom, I want to thank all of my readers, especially those who have joined the discussion, and wish you all a merry Christmas. In all the hustle of the season, it is my hope and prayer that the joy and peace brought to us in the person of Jesus Christ will be an ever-present blessing in your lives. " ### [Ceylon: a First, Quick Take](/2013/ceylon-a-first-quick-take/) Last week at Devoxx, Red Hat announced the release of Ceylon 1.0, "a modern, modular, statically typed programming language for the Java and JavaScript virtual machines." A fan of learning languages, I started taking the tour. In no particular order, and without any lengthy rumination, here are my initial thoughts on the language. Mixin inheritance Mixin inheritance looks pretty interesting. While I’m no Scala expert, it strikes me as being very similar to what Scala’s traits offer. It also seems pretty close to the default methods Java 8’s interface will now make possible. These comparisons could be way off, and in the case that they’re not, I can’t say at this point how they differ, but I find this a very interesting feature. Over the years, I’ve found myself creating utility classes with static methods for a specific purpose. Over time that class usually turns into a dumping ground for utility methods, killing cohesiveness and making the class hard to maintain. Intersection Types The Ceylon docs describe an intersection type as: An expression is assignable to an intersection type, written X&Y, if it is assignable to both X and Y. They give this example: Iterable<String>&Correspondence<Integer,String> strings = ["hello", "world"]; String? str = strings.get(0); //call get() of Correspondence Integer size = strings.size; //call size of Iterable There are more resources available on the topic (like this one), which I’ll definitely need to read, because it’s just not clicking at the moment. :) No NullPointerExceptions In Ceylon, they claim, it’s impossible to get NPEs at runtime. While I’m always a bit skeptical when someone says something is impossible, I’m willing to give them the benefit of the doubt. If a variable is nullable, it must be declared as such: String? name = getName(); Without the ?, one can not assign null to the variable, so it’s always safe to access it without checking. With the ?, the compiler forces the code to check for null before it will compile code that accesses it: if (exists name) { …​. It seems that this may require a variable be checked for null multiple times if it’s passed around to methods, but that’s probably not a big enough problem to worry about. Regardless, no more embarrassing NPEs in production, meaning other exceptions will finally get some time at bat. :P Type narrowing In Java, when dealing with subclasses, we use if (…​ instanceof …​), then cast. In Ceylon, it’s done in one step: if (is Foo bar) { bar.someFooMethod(); } It’s nice that the cast is not necessary, since, as the docs point out, it’s clear we intended to interact with bar as an instance of Foo. I think the is {type} {variable} syntax reads oddly, but I’m sure it’s something I’d get used to. Enumerated Subtypes I’ll confess right up front: there’s a good chance that I don’t understand enumerated subtypes correctly. The docs seems to say that enumerated types are not subclassable (and I might be making up words now :). For example: abstract class Point() of Polar | Cartesian { // ... } The docs then say, 'Now the compiler won’t let us declare additional subclasses of Point, and so the union type Polar|Cartesian is exactly the same type as Point.' Are enumerated subtypes necessary? Probably not. Either way, this doesn’t seem like something you’d in a public API, but I could be wrong. I’ll have to read some more on it. First class and higher order functions This feature looks very nice. It is, of course, nothing new, but it’s good to see this designed in from the start, rather than bolted on later. Ceylon also supports named argument method invocation. My initial reaction to it is fairly positive. It’s a bit verbose, but very readable, and I would think would lead to more clearly self-documenting code, though I would imagine its use would taper off as one becomes more fluent in the language. Tuples Ceylon has built-in support for tuples, "a linked list which captures the static type of each individual element in the list". Tuples seem to have no built-in length limit, and they can handle more than one type (otherwise it would be a List<T>, right? :) You can also 'spread' a tuple, meaning you can specify that the contents of a tuple be used to satisfy method parameters: [String,Float] args = ["%5.2f", 1.0]; print(format(*args)); In this example, a tuple of String and Float is declared, then, prefixing the variable name with a *, the elements in the tuple are spread across the parameters for format (which are String, Float…​). Really cool. Case Restrictions In Ceylon, "[t]he case of the first character of an identifier is significant. Type (interface, class, and type parameter) names must start with an initial capital letter. Function and value names start with an initial lowercase letter or underscore." While this happens to mirror what I do anyway, it strikes me as an odd choice to codify in the language spec. It’s quite possible, though, that this will be a lot like spaces in python: it causes an initial adverse reaction, followed by acceptance when you realize you were going to do it anyway. There may be some, though, thought don’t code like that, so it’s going to bite them. Heads up! ;) Mandatory Braces One of my big pet peeves (and it’s always with someone else’s code ;) is the omission of braces around code blocks: if (condition) return; That’s just asking for bugs if you ask me. Fortunately, the Ceylon team agrees with me: the language requires braces for all control structures. The code snippet above, while valid Java, will fail to compile in a Ceylon program. Hip. Hip. Hooray. :) Packages I remember years ago when I was first learning Java that I got burned by a mismatch between the package name declared (or not?) in my Java source with the implied package found in the directory name. I don’t remember the details, but it seems like I kept getting CNFEs when trying to run my code. Ceylon neatly avoids this by not having package declarations; the package is inferred based on its location in the filesystem (relative to the source root, of course). My gut reaction is that I like this, but I wonder if there are some unintended consequences I’m missing. Conclusion As I said at the start, this is just a random smattering of things that stood out to me as I read the tour. I’m by no means a language design expert, so any critiques on the language should be taken with that in mind, but, so far, I like what I’ve seen. I’ve been working on a small proof-of-concept-type application to kick the tires, which has resulted in a few cuts and bruises, so we’ll see how it goes, but I think I’ll stick with it a while and give a good chance. If nothing else, the learning has been fun. :) Have you looked at Ceylon? What are you thoughts? Have I gotten something wrong here? Please let me know below! :) ### [Import Maven Artifacts to Ceylon Repos](/2013/import-maven-artifacts-to-ceylon-repos/) In trying to come up to speed on Ceylon, I’ve run into some issues with module import dependencies. I’m pretty sure they’re all pilot error, but it was suggested that I import the jars into the Ceylon repository and specify the dependencies between the modules. This would, effectively, be functionally the same as the <dependencies> element in the Maven POM. In classic geek, over-engineer-the-solution fashion, I cobbled together this shell script. It could be more elegant, but it seems to work, and it was much simpler than a Java implementation using the Maven APIs. :) Here’s the script: mvnimport.sh #!/bin/bash FILE=deps BASE=http://search.maven.org/remotecontent?filepath= function download() { curl --remote-name -s $1 } function getRepoDir() { GROUP=$1 ARTIFACT=$2 VERSION=$3 REPODIR=`getDir $GROUP/$ARTIFACT` echo $HOME/.ceylon/repo/$REPODIR/$VERSION } function getUrl() { G=$1 A=$2 V=$3 GPATH=`echo $G | sed -e 's/\./\//g'` echo "$\{BASE}$GPATH/$A/$V/$A-$V" } function getDir() { echo $1 | sed -e 's/\./\//g' } function downloadFiles() { GROUP=$1 ARTIFACT=$2 VERSION=$3 URL=`getUrl $GROUP $ARTIFACT $VERSION` download $URL.pom download $URL.jar } function importJar() { GROUP=$1 ARTIFACT=$2 VERSION=$3 ceylon import-jar --out $HOME/.ceylon/repo $GROUP.$ARTIFACT/$VERSION $ARTIFACT-$VERSION.jar } function getDeps() { mvn dependency:tree -f *.pom | grep "\- " | grep -v ":test" | grep "\[INFO\] +- " | cut -c 11- > $FILE } function processDeps() { REPODIR=$1 for DEP in `cat $FILE` ; do DGROUP=`echo $DEP | cut -f 1 -d ":"` DARTIFACT=`echo $DEP | cut -f 2 -d ":"` DVERSION=`echo $DEP | cut -f 4 -d ":"` echo "$DGROUP.$DARTIFACT=$DVERSION" >> $REPODIR/module.properties DEPREPODIR=`getRepoDir $DGROUP $DARTIFACT $DVERSION` processArtifact $DGROUP $DARTIFACT $DVERSION done } function processArtifact() { GROUP=$1 ARTIFACT=$2 VERSION=$3 REPODIR=`getRepoDir $GROUP $ARTIFACT $VERSION` if [ ! -e $REPODIR ] ; then echo "Processing $GROUP:$ARTIFACT:$VERSION" #read -p "Press enter to continue: " mkdir -p "$ARTIFACT" cd "$ARTIFACT" downloadFiles $GROUP $ARTIFACT $VERSION importJar $GROUP $ARTIFACT $VERSION getDeps processDeps $REPODIR rm -rf "./$ARTIFACT" else echo "A module for $GROUP:$ARTIFACT:$VERSION has been found. Skipping." fi } if [ $# -lt 3 ] ; then echo "Usage: mvnimport.sh <groupId> <artifactId> <version>" exit -1 fi processArtifact $1 $2 $3 To import a Maven artifact, all you have to do is specify the group ID, artifact, and version: $ mvnimport.sh com.google.guava guava 14.0.1 Processing com.google.guava:guava:14.0.1 Processing com.google.code.findbugs:jsr305:1.3.9 It will import the artifact, record its immediate dependencies, then recursively process each dependency. If a module for the given coordinates has been found, the script currently skips it. As I said, this seems to work, but if there are bugs are ways to improve it, I’m all ears. :) ### [Book Review: Instant Vert.x](/2013/book-review-instant-vert-x/) I recently acquired a copy of Instant Vert.x (Kindle version here) by Simone Scarduzio. It’s a short book (54 pages), so here’s my short-ish review. :) Your first question might be, "What is Vert.x"? From its web site, Vert.x is a lightweight, high performance application platform for the JVM that’s designed for modern mobile, web, and enterprise applications. http://vertx.io/ While that description says it’s for the JVM, the library itself is polyglot, supporting Java, JavaScript, CoffeeScript, Ruby, Python or Groovy, or a combination thereof. With that out of the way, so you’ll have an idea of what’s being discussed (and thus be able to decide if you care to keep reading :), let’s turn to the book. The book starts off with an introduction much more robust than what I just gave. :) The author gives a good description of what the platform offers, as well as a good introduction to some of the basic terms associated with Vert.x. After the introduction, the author then walks his reader through setting up the environment: Java, Jython (optional), JRuby (optional), and, finally, Vert.x itself. While Vert.x modules, or "verticles" can be written in a number of different languages, they all run eventually on the JVM. The steps for installing Jython and JRuby, then, are simply to make the reader’s life a little easier, should he be interested in using one of those two languages. The installation section closes with one small example, implemented in each of the support languages, giving the reader a good sampling of what that would look like. The rest of the book uses Javascript exclusively. The next two chapters walk the reader through writing simple, but complete implementations (meaning working, but not necessarily feature-rich or robust) of a web server and an "IRC-style" chat server. The chat server example is a bit more complex than the web server, due, in part, to the more complex nature of the system, introducing handler functions and a pub/sub even bus. The next-to-last chapter discusses the "top 8 features you need to know about": HTTP server, HTTP clients and event bus Transport layer security (SSL) for HTTP Asynchronous requests with SockJS-based EventBus bridge EventBus bridge: breaking out of the request-response model Using all the cores - multiple instances and shared data Cache max size and eviction policies Scaling out - clustering Creating a module Installing third-party modules Finally, we end with a list of people and places you should get to know. With all that said, my take on the book: Not knowing anything about Vert.x when I started this book, I really enjoyed it’s brevity, and it’s pace. There seems to be a tendency with technical books to jump straight to the gory details of subject (for which there is a time and place :), leaving newcomers a bit dazed and confused. This book, though, as I’m sure all the books in Packt’s "Instant" series are designed to do, gives a great, surface-level introduction to the technology, explaining just enough to get you going. Now, having read the book and having a better, high-level understanding of what Vert.x is, I feel better-prepared to start digging through it’s web site or a bigger, more complete text on the subject. I do have a few nits, though. As a Java guy, I would have liked to see the examples in Java. The problem with that, though, is I’m sure there’s a Python guy somewhere going to make a similar statement. :) Also, it could very well be that the best practice amongst Vert.x officiandos to use Javascript. I know Javascript, but I found myself having to read the code a little more slowly than I would have had to with Java. The flip side is that if he had used Java, the book would probably be twice as long. :P On a nontechnical note, the text also could have used a little better editing. There were some parts of the text that read really oddly. Those tend to jump out at me and give me a bit of heartburn (I know. I’m sure regular readers of my blog are currently forming the word "kettle" in their minds ;). That kind of thing may or may not be an issue for you, but, in case it is, you’ve been warned. Lastly, the Kindle edition (and I’m sure the print edition, as well) just ends. No summary, etc. I found myself wildly swiping and poking at my tablet trying to find the next page before I realized there wasn’t one. Neither of these "issues" are real problems, of course, but I mention them just to be a fair. Overall, I enjoyed the book. The examples were clean and small, and the explanations of what was being done and why were sufficient to help me understand what was going on. While all of the topics in the book can be found for free on the internet (as with every technical book), it’s nice to have all of those ideas aggregated in one place, and this is a good place to start if you’re interested in Vert.x. ### [Awestruct NetBeans Plugin](/2013/awestruct-netbeans-plugin/) Several weeks ago, I posted blurb about a JavaFX project I had cobbled together, DoctorFX. It is an effort to build a semi-graphical editor for Asciidoc, but it is, currently, very basic. I had some spare time last week, so I decided to add some features to it. As I thought about what needed to be added and what that would require, I thought that, perhaps, an architectural change was warranted. With some time and an itch, I pulled out the sledge hammer and out came a NetBeans plugin. This plugin though, does more than Asciidoc: it offers full(-ish) support for the Awestruct framework. There are a lot of features I’d like to add still, but, currently it supports only basic project loading and editing. It technically has code to preview Asciidoc files, though I’m having issues getting the rendered page from displaying. (In case you want to take a crack at it, that code is here.) I’d also like to add preview support for Slim and Haml, but that may have to wait a bit. If you’d like to lend a hand to the effort, you can find the current source on Bitbucket. This is, of course, a bit heavier than DoctorFX, but most of my work with Asciidoc is, currently, in the context of Awestruct, so this fits my needs better, and it was fun dipping my toes into the NetBeans Platform API. :) ### [Book Review: Beginning Java EE 7](/2013/book-review-beginning-java-ee-7/) Java Champion and JUG leader Antonio Goncalves recently released his third book on Java EE, Beginning Java EE 7. Just from the title and the table of contents, it’s clear that Antonio set a very ambitious goal for this book, and I think he delivered what he promised. Java EE is, of course, a large, diverse set of technologies, so the book itself, to do the platform justice, must also be pretty wide-ranging. At a high level, here is what the book covers (taken from the table of contents): Java EE 7 at a Glance Context and Dependency Injection Bean Validation Java Persistence API Object-Relational Mapping Managing Persistent Objects Enterprise JavaBeans Callbacks, Timer Service, and Authorization Transactions JavaServer Faces Processing and Navigation XML and JSON Processing Messaging SOAP Web Services RESTful Web Services The book doesn’t cover all of Java EE 7 (batch processing, for example, is not covered), but it does cover a good deal of the platform, focusing primarily, as the title suggests, on those technologies most likely needed to get started with Java EE development. Each section gives enough background to give the user a good understanding of where we were prior to each specification’s creation. While some may scoff at the brig history lessons, I find it helpful to understand the technology in its historical context, as it tends to explain many of the design decisions and trade-offs made. Antonio then breaks down each area bit by bit in what I found to be pretty clear, concise language. He then walks the reader through building a small, working example so you can see all the pieces in place. Technically, I found the book to be very solid and easy to read. It’s structured in a way that a reader can pick it up and read only what he needs, then come back later if, say, he decides to add a SOAP web service to the application. Also, while all of this information can be found on the web somewhere, Antonio has done a nice job of summarizing and explaining the technologies, allowing you to get started quickly and easily without having to fumble all over the web for details. When starting with something as large as Java EE 7 can be, that’s a real plus. The few dollars this book costs is far less than the cost of time spent with a search engine. The book is not, I think, only for beginners. I’ve been using JavaServer Faces, JPA, and JAX-RS for many years now, and I still found things in the book I didn’t know, or learned better ways of doing things as I read. There are a few quirks in the book, though, that may or may not bother you, depending on how picky you are. There are a few typos here and there, and, as some reviewers on Amazon have noted, the formatting on ereaders can be a bit funny at times, though I found that most of the formatting can be easily fixed by rotating your device to landscape. At any rate, these are minor quibbles that should only be an issue if you let them. :) Overall, a very solid, helpful book. If I were onboarding a developer, especially a junior developer or one new to Java EE, intended to help develop any sort of Java EE 7 system, this book would be on my short list of must haves. ### [Gradle Tip: Better Test Debugging](/2013/gradle-tip-better-test-debugging/) In a recent post, I showed how to attach a debugger to tests run from the command line via Gradle. While it worked, it turns out that it’s a bit over kill. Try this instead: $ gradle -Dtest.debug test :compileJava :processResources UP-TO-DATE :classes :compileTestJava :processTestResources :testClasses :test Listening for transport dt_socket at address: 5005 Attach your debugger to port 5005, and off you go. No need to modify your build. Kudos to the NetBeans debugger output for helping me find that. ;) ### [Gradle Tip: Running a Single Test](/2013/gradle-tip-running-a-single-test/) Using Maven, to run a single test (class), you would issue mvn -Dtest=MyTest. Gradle has similar functionality (gradle -Dtest.single=MyTest), though it seems to be much more powerful. You can get all the details here. ### [Gradle + Arquillian + GlassFish Embedded](/2013/gradle-arquillian-glassfish-embedded/) I’ve recently been migrating all of my personal projects to Gradle. Since I use Arquillian, that means migrating that part of the build as well. However, being still fairly new to Gradle, how to handle that integration wasn’t immediately obvious. Thanks to Benjamin Muschko and Aslak Knutsen, I’ve finally gotten a working setup. While there is a Gradle plugin, as I understand things, it only supports the container lifecycle. All of the test deployment, etc. is work yet to be done. Fortunately, you don’t need the plugin if you don’t mind a little more work in your build. Here is my current build file, which only supports GlassFish Embedded and JBoss AS 7 Managed (paritally) at the moment: build.gradle apply plugin: 'war' apply plugin: 'idea' version = '1.0-SNAPSHOT' ext.libraryVersions = [ arquillian: '1.1.1.Final', arquillian_glassfish: '1.0.0.CR4', glassfish: '4.0', hamcrest: '1.2', javaee: '7.0', jbossAS7: '7.1.1.Final', jbossJavaeeSpec: '1.0.0.Final', junit: '4.11', postgresql: '9.2-1003-jdbc4', shrinkwrapDesc: '2.0.0-alpha-3' ] repositories { mavenCentral() mavenLocal() mavenRepo url: 'http://repository.jboss.org/nexus/content/groups/public' mavenRepo url: 'http://repository.jboss.org/nexus/content/repositories/deprecated' } configurations { provided integrationTestCompile.extendsFrom testCompile integrationTestRuntime.extendsFrom testRuntime // [1] jbossAS7ManagedTestRuntime { extendsFrom integrationTestRuntime, provided } glassfishEmbeddedTestRuntime { extendsFrom integrationTestRuntime } } sourceSets { main { compileClasspath = configurations.compile + configurations.provided } integrationTest { // [2] java { srcDir 'src/integrationTest/java' } resources { srcDir 'src/integrationTest/resources' } compileClasspath += main.output + configurations.provided runtimeClasspath += main.output + configurations.provided } } dependencies { provided "javax:javaee-api:$libraryVersions.javaee" testCompile "junit:junit:$libraryVersions.junit" testCompile "org.hamcrest:hamcrest-core:$libraryVersions.hamcrest" // [3] integrationTestCompile "org.jboss.arquillian.junit:arquillian-junit-container:$libraryVersions.arquillian" integrationTestCompile "org.jboss.shrinkwrap.descriptors:shrinkwrap-descriptors-api-javaee:$libraryVersions.shrinkwrapDesc" integrationTestRuntime "org.jboss.shrinkwrap.descriptors:shrinkwrap-descriptors-impl-javaee:$libraryVersions.shrinkwrapDesc" glassfishEmbeddedTestRuntime "org.jboss.arquillian.container:arquillian-glassfish-embedded-3.1:$libraryVersions.arquillian_glassfish" glassfishEmbeddedTestRuntime "org.glassfish.main.extras:glassfish-embedded-all:$libraryVersions.glassfish" glassfishEmbeddedTestRuntime "org.postgresql:postgresql:$libraryVersions.postgresql" jbossAS7ManagedTestRuntime "org.jboss.as:jboss-as-arquillian-container-managed:$libraryVersions.jbossAS7" jbossAS7ManagedTestRuntime "org.jboss.spec:jboss-javaee-6.0:$libraryVersions.jbossJavaeeSpec" } // [4] task glassfishEmbeddedTest(type: Test) task jbossAS7ManagedTest(type: Test) tasks.withType(Test).matching({ t-> t.name.endsWith('Test') } as Spec).each { t -> t.testClassesDir = project.sourceSets.integrationTest.output.classesDir t.classpath = project.configurations.getByName(t.name + 'Runtime') + project.sourceSets.main.output + project.sourceSets.integrationTest.output } There’s quite a bit going on here — and I’ll be honest here — I understand about half of it. :) I will do my best, though, to explain what I think is going on. We start at [1] by declaring a few new configurations, one for a generic integrat test, one for GlassFish Embedded, and the other for JBoss AS 7 Managed. The first new configuration we’ll use for defining dependencies shared across the containers, specifically, the Arquillian dependencies. With the last two, we extend integrationTestRuntime to pick up those dependencies and to which we’ll add container-specific dependencies later. I wanted to keep my Arquillian-based integration tests separate from any conventional unit tests I may write, so I put them all in a new directory, src/integrationTest. At [2], I tell Gradle about his new directory with a custom SourceSet, integrationTest. We have to add the output from the main configuration to this one, so that it picks up our application classes. Next, at [3], we declare the dependencies for the integration tests. The first three entries, as I noted, declare the dependencies each of the containers we’ll use will share. Next, we declare the container-specific dependencies. The project from which I pulled this build uses a Postgresql database. While I should probably use something in-memory (which I’ll eventually do), at the moment, I’m using a local pgsql install, so I need to declare the dependency on the Postgresql JDBC driver. The JBoss dependencies are fairly straightforward. Finally, at [4], we declare two new tasks, one for each supported container. Immediately after that, we loop over each task of type Test and configure them. This could be done in the task declaration, of course, but this approach, of which I can’t claim authorship, allows us to code it once for all test tasks. The rest of the project is a fairly straightforward Arquillian setup. For the curious, I’ll share a couple more files in case it helps anyone out. The first is my arquillian.xml: src/integrationTest/resources/arquillian.xml <?xml version="1.0" encoding="UTF-8"?> <arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd"> <engine> <property name="deploymentExportPath">build/libs</property> </engine> <container qualifier="glassfish-embedded" default="true"> <configuration> <property name="resourcesXml"> src/integrationTest/resources/glassfish-resources.xml </property> </configuration> </container> <container qualifier="jbossas-managed-7"> <configuration> <property name="jbossHome">jboss7</property> </configuration> </container> </arquillian> src/integrationTest/resources/glassfish-resources.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd"> <resources> <jdbc-connection-pool datasource-classname="org.postgresql.xa.PGXADataSource" res-type: "javax.sql.XADataSource" name="FrenchPressPool"> <property name="user" value="frenchpress"></property> <property name="password" value="fp"></property> <property name="databaseName" value="frenchpress"></property> <property name="serverName" value="localhost"></property> </jdbc-connection-pool> <jdbc-resource pool-name="FrenchPressPool" jndi-name="jdbc/frenchpress"/> </resources> You can find the entire app in my BitBucket repo. If you have any questions, suggestions, improvements, etc. in either this Gradle build or the app itself, I’ll happily take pull requests. :) ### [Gradle Tip: Attaching a Debugger](/2013/gradle-tip-attaching-a-debugger/) Maven offers a nice script to allow for attaching a debugger to your build, mvnDebug. Gradle does not. Again, though, Gradle makes it pretty easy to add this to your build. Let’s say you want to debug your tests: build.gradle test { if (System.getProperty('DEBUG', 'false') == 'true') { jvmArgs '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009' } } From the command line, issue gradle -DDEBUG=true test: $ gradle -DDEBUG=true test :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :compileTestJava :processTestResources UP-TO-DATE :testClasses :test Listening for transport dt_socket at address: 9009 > Building > :test When you see that line, you can attach the debugger of your choice, using port 9009. This also works if you’re building a command line application: build.gradle run { if (System.getProperty('DEBUG', 'false') == 'true') { jvmArgs '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009' } } and run: gradle -DDEBUG=true run :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :run Listening for transport dt_socket at address: 9009 > Building > :run To add this all of your projects, you can make this change to init.gradle: $HOME/.gradle/init.gradle allprojects { tasks.withType(Test) { if (System.getProperty('DEBUG', 'false') == 'true') { jvmArgs '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009' } } tasks.withType(JavaExec) { if (System.getProperty('DEBUG', 'false') == 'true') { jvmArgs '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009' } } } ### [Gradle Tip: Seeing Standard Streams During Tests](/2013/gradle-tip-seeing-standard-streams-during-tests/) I’m not a real big fan of using standard out as a debugging strategy (I prefer an IDE and break points, for what it’s worth), but there are times when it’s either necessary or just convenient. The standard Gradle configuration, though, makes this a bit more difficult than it probably should be. Fortunately, Gradle also makes it easy to change: build.gradle test { testLogging.showStandardStreams = true } If you’d like to make this change globally, that’s also easy: $HOME/.gradle/init.gradle allprojects { tasks.withType(Test) { testLogging.showStandardStreams = true } } ### [Building "Fat Jars" with Gradle](/2013/building-fat-jars-with-gradle/) Sometimes, such as when building command line Java apps, it would be nice to bundle all of the app’s dependencies in a single jar so that the user need not collect and manage these. With Gradle, that can be easily accomplished with the following lines: build.gradle jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } } } When you run gradle assemble, you should find your now very hefty jar in build/libs. ### [Filtering Mail using JavaMail](/2013/filtering-mail-using-javamail/) At the Lee House, we have an email problem: there’s just too much of it. Over the years of signing up for contests, coupons, and other things, we seem to have amassed a giant number of subscriptions to various lists, which gives us a lot of (usually) junk email. The simple solution, of course, is just to unsubscribe, but some of those are actually occasionally useful. Throw in a pinch of proscratination and laziness, and, well…​ it all just keeps coming. Email clients can help manage this by providing email filters to move these emails out of the inbox, but, in the case of Thunderbird, there are only so many rules you can add to one filter, so you either create multiple rules, or give up trying. Several months back, I moved these rules to a perl-based system, but, thanks to a hard drive crash, I lost all of those. Rather than rebuild that setup, which had its own limitations, I did what every good geek would do: I wrote my own, and here it is. :) The system itself is really pretty simple. It’s not pretty, probably not too terribly efficient, and may be, generally speaking, not as flexible as some would like it to be, but, so far, it works well for me, and, to be honest, I had fun writing it, so I’m happy. :) The rules are expressed in a JSON file that might look something like this: rules.json [ { "serverName": "imap.myserver.com", "serverPort": "993", "useSsl": true, "userName": "myaddress@example.com", "password": "mypassword", "rules": [ {"destFolder": "Ads","matchingText": "deals@somesite.com"}, {"type": "delete", "sourceFolder": "Ads", "olderThan" : 90} ] } ] The system knows of two types of objects: Acccount and Rule. Each Account gives the server’s name and port, whether or not to use SSL (though this is currently ignored), and the user name and password. The Account also has a list of Rule objects. Each Rule can have a type (whose default is "move"), a source folder (whose default is "INBOX"), a desination folder, a matching text field, and/or an "olderThan" field. In this example, we have two rules. The first moves all email from "deals@somesite.com" from the inbox to a folder called Ads. The second will delete all emails in Ads that are older than 90 days. Multiple accounts are supported as well. All you have to do is add a new Account object to the top-level list: rules.json [ { "serverName": "imap.myserver.com", "serverPort": "993", "useSsl": true, "userName": "myaddress@example.com", "password": "mypassword", "rules": [ {"destFolder": "Ads","matchingText": "deals@somesite.com"}, {"type": "delete", "sourceFolder": "Ads", "olderThan" : 90} ] }, { "serverName": "imap.myserver.com", "serverPort": "993", "useSsl": true, "userName": "mysecondaddress@example.com", "password": "mypassword", "rules": [ // ... ] } ] The build generates a fat jar, so running it can be done simply with $ java -jar /path/to/mailfilter.jar /path/to/rules.json Deleted 0 message(s) for account myaddress@example.com Moved 0 message(s) for account myaddress@example.com Add that to cron, for example, and you’re all set. As I said, it’s not necessarily pretty, but it works (for me) and I thought someone might like to see the JavaMail API in action (even if amateurishly), so I thought I’d share. You can find the source for this cleverly named project on Bitbucket. Suggestions, critiques, pull requests, etc. are always welcome. :) ### [WebJars and JSF](/2013/webjars-and-jsf/) WebJars, for those that haven’t heard, is a project that takes popular client-side web libraries and packages them in JARs to make their use in Java-/JVM-based web apps simpler. The web site notes that you can easily see which libraries a project is using simply by looking at its dependencies, and that transitive dependencies automatically appear. It’s a pretty compelling project, but, for some reason, it doesn’t show how to integrate it with JSF. I’d like to think it’s because it’s so trivial, but I’ll show it here anyway. :) The first step is to add it to your build. We’ll use Bootstrap 3.0 in our example: build.gradle dependencies { // ... compile 'org.webjars:bootstrap:3.0.0' // ... } pom.xml <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.0.0</version> </dependency> The next step is adding it to the page: index.xhtml <h:head> <h:outputStylesheet library="webjars/bootstrap/3.0.0/css" name="bootstrap.min.css"/> <h:outputScript library="webjars/bootstrap/3.0.0/js" name="bootstrap.min.js"/> </h:head> That’s it. Build and deploy your app, and Bootstrap (or the library of your choice) is ready to use. ### [A Quick-start for Scala and Gradle](/2013/a-quick-start-for-scala-and-gradle/) For those interested, here’s a quick and simple project to get you started using Gradle and Scala together: build.gradle apply plugin: 'scala' repositories{ mavenCentral() mavenLocal() } dependencies{ compile 'org.slf4j:slf4j-api:1.7.5' compile "org.scala-lang:scala-library:2.10.1" testCompile "junit:junit:4.11" } task run(type: JavaExec, dependsOn: classes) { main = 'Main' classpath sourceSets.main.runtimeClasspath classpath configurations.runtime } src/main/scala/Main.scala object Main extends App { println("Hello, world") } You can run the app using the custom task run: $ gradle run :compileJava :compileScala :processResources :classes :run Hello, world BUILD SUCCESSFUL Total time: 9.79 secs Remember to add --daemon for faster startup times for your Gradle builds. Have fun! ### [Gradle, 'provided' scope, and Java EE 7](/2013/gradle-provided-scope-and-java-ee-7/) Maven has a dependency scope, provided, that indicates that the dependency should not be in the archive. Gradle does not provide such a scope out of the box, but it’s easy enough to add. The following Gradle build demonstrates a very bare-bones Java EE 7 web application setup: build.gradle apply plugin: 'war' repositories { mavenCentral() mavenLocal() } configurations { provided } sourceSets { main { compileClasspath += configurations.provided } } dependencies { provided 'javax:javaee-api:7.0' } ### [A Simple OAuth2 Client and Server Example: Part II](/2013/a-simple-oauth2-client-and-server-example-part-ii/) In the last post, we took a look at the server side of our OAuth2 system. In this post, we’ll take a quick look at the unit tests that will act as TheUser. Let’s get right to the code: @RunAsClient public class AuthTest extends Arquillian { @ArquillianResource private URL url; private Client client = JerseyClientBuilder.newClient(); @Deployment public static WebArchive createDeployment() { WebArchive archive = ShrinkWrap.create(WebArchive.class) .addPackages(true, "com.steeplesoft.oauth2") .addAsWebInfResource( new FileAsset( new File("src/main/webapp/WEB-INF/beans.xml")), "beans.xml") .addAsWebInfResource( new FileAsset( new File("src/main/webapp/WEB-INF/web.xml")), "web.xml") .addAsLibraries(Maven.resolver() .loadPomFromFile("pom.xml") .importRuntimeDependencies() .resolve() .withTransitivity() .asFile()); return archive; } @Test public void authorizationRequest() { try { Response response = makeAuthCodeRequest(); Assert.assertEquals(Status.OK.getStatusCode(), response.getStatus()); String authCode = getAuthCode(response); Assert.assertNotNull(authCode); } catch (OAuthSystemException | URISyntaxException | JSONException ex) { Logger.getLogger(AuthTest.class.getName()) .log(Level.SEVERE, null, ex); } } @Test public void authCodeTokenRequest() throws OAuthSystemException { try { Response response = makeAuthCodeRequest(); Assert.assertEquals(Status.OK.getStatusCode(), response.getStatus()); String authCode = getAuthCode(response); Assert.assertNotNull(authCode); OAuthAccessTokenResponse oauthResponse = makeTokenRequestWithAuthCode(authCode); assertNotNull(oauthResponse.getAccessToken()); assertNotNull(oauthResponse.getExpiresIn()); } catch (OAuthSystemException | URISyntaxException | JSONException | OAuthProblemException ex) { Logger.getLogger(AuthTest.class.getName()) .log(Level.SEVERE, null, ex); } } @Test public void directTokenRequest() { try { OAuthClientRequest request = OAuthClientRequest .tokenLocation(url.toString() + "api/token") .setGrantType(GrantType.PASSWORD) .setClientId(Common.CLIENT_ID) .setClientSecret(Common.CLIENT_SECRET) .setUsername(Common.USERNAME) .setPassword(Common.PASSWORD) .buildBodyMessage(); OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); OAuthAccessTokenResponse oauthResponse = oAuthClient.accessToken(request); assertNotNull(oauthResponse.getAccessToken()); assertNotNull(oauthResponse.getExpiresIn()); } catch (OAuthSystemException | OAuthProblemException ex ) { Logger.getLogger(AuthTest.class.getName()) .log(Level.SEVERE, null, ex); } } @Test public void endToEndWithAuthCode() { try { Response response = makeAuthCodeRequest(); Assert.assertEquals(Status.OK.getStatusCode(), response.getStatus()); String authCode = getAuthCode(response); Assert.assertNotNull(authCode); OAuthAccessTokenResponse oauthResponse = makeTokenRequestWithAuthCode(authCode); String accessToken = oauthResponse.getAccessToken(); URL restUrl = new URL(url.toString() + "api/resource"); WebTarget target = client.target(restUrl.toURI()); String entity = target.request(MediaType.TEXT_HTML) .header(Common.HEADER_AUTHORIZATION, "Bearer " + accessToken) .get(String.class); System.out.println("Response = " + entity); } catch (MalformedURLException | URISyntaxException | OAuthProblemException | OAuthSystemException | JSONException ex) { Logger.getLogger(AuthTest.class.getName()) .log(Level.SEVERE, null, ex); } } void testValidTokenResponse(HttpURLConnection httpURLConnection) throws Exception { InputStream inputStream; if (httpURLConnection.getResponseCode() == 400) { inputStream = httpURLConnection.getErrorStream(); } else { inputStream = httpURLConnection.getInputStream(); } String responseBody = OAuthUtils.saveStreamAsString(inputStream); assert (Common.ACCESS_TOKEN_VALID.equals(responseBody)); } private Response makeAuthCodeRequest() throws OAuthSystemException, URISyntaxException { OAuthClientRequest request = OAuthClientRequest .authorizationLocation(url.toString() + "api/authz") .setClientId(Common.CLIENT_ID) .setRedirectURI(url.toString() + "api/redirect") .setResponseType(ResponseType.CODE.toString()) .setState("state") .buildQueryMessage(); WebTarget target = client.target(new URI(request.getLocationUri())); Response response = target.request(MediaType.TEXT_HTML).get(); return response; } private String getAuthCode(Response response) throws JSONException { JSONObject obj = new JSONObject(response.readEntity(String.class)); JSONObject qp = obj.getJSONObject("queryParameters"); String authCode = null; if (qp != null) { authCode = qp.getString("code"); } return authCode; } private OAuthAccessTokenResponse makeTokenRequestWithAuthCode(String authCode) throws OAuthProblemException, OAuthSystemException { OAuthClientRequest request = OAuthClientRequest .tokenLocation(url.toString() + "api/token") .setClientId(Common.CLIENT_ID) .setClientSecret(Common.CLIENT_SECRET) .setGrantType(GrantType.AUTHORIZATION_CODE) .setCode(authCode) .setRedirectURI(url.toString() + "api/redirect") .buildBodyMessage(); OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); OAuthAccessTokenResponse oauthResponse = oAuthClient.accessToken(request); return oauthResponse; } } The first thing you should notice is that we’re using TestNG and Arquillian. I won’t go into the details on the Arquillian set up here, other than to note that we need our test to @RunAsClient, and to point out the @Deployment method that builds our test archive for us. Moving on to authorizationRequest, we can see (in makeAuthCodeRequest) how the Oltu library makes it easy to build the request for an authorization code. Utlimately, the library helps use create the request URI, which we then pass to the JAX-RS client as it makes the actual request. To be honest, there’s a bit here (such as the state field) that I don’t understand. Any expert help here would be appreciated. :) The next method, authCodeTokenRequest, shows the flow of getting an authorization code, then using it to get the access token. That’s followed by an example of a direct request for token via the password grant type. Finally, we have an end to end example, from authorization code to accessing our protected resource. That’s all there is to it. As you can see in the POM and arquillian.xml, the only container currently supported is GlassFish, which the tests expect to find in glassfish4/ in the project’s base directory. Once that’s installed, the tests can be run with the normal mvn test. If you have any questions about the code, I can try to answer them, but as should be clear by now, I’m still learning all of this. If I’ve made any mistakes in the code or my description of the protocol, please don’t be shy about correcting me. We’re all hear to learn. :) ### [Setting Up Droidium for Android Testing](/2013/setting-up-droidium-for-android-testing/) Many know Arquillian as a great integration, functional, acceptance testing platform. Until recently, I thought of it solely as a great Java EE tool, but an Arquillian extension, known as Droidium, allows you to use Arquillian to help drive your Android testing. I spent some time tonight trying to get it set up for Cub Tracker and thought I’d share what (little) I have so far. Rather than use Ant as the Android SDK currently does, we’re going to build this test app using Maven. My POM currently looks something like this: <?xml version="1.0"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.steeplesoft.cubtracker</groupId> <artifactId>cubtracker-parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>cubtracker-arquillian-tests</artifactId> <description>Cub Tracker Arquillian Droidium</description> <!-- Properties --> <properties> <version.drone>1.2.0.Alpha2</version.drone> <version.arquillian.core>1.0.4.Final</version.arquillian.core> <version.droidium>0.0.1-SNAPSHOT</version.droidium> <android.avd.name>Nexus7</android.avd.name> <!-- maven-compiler-plugin --> <maven.compiler.target>1.6</maven.compiler.target> <maven.compiler.source>1.6</maven.compiler.source> </properties> <!-- Dependency Management --> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian</groupId> <artifactId>arquillian-bom</artifactId> <version>$\{version.arquillian.core}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Arquillian Drone BOM --> <dependency> <groupId>org.jboss.arquillian.extension</groupId> <artifactId>arquillian-drone-bom</artifactId> <version>$\{version.drone}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.arquillian.extension</groupId> <artifactId>arquillian-drone-webdriver-depchain</artifactId> <type>pom</type> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.arquillian.junit</groupId> <artifactId>arquillian-junit-container</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.arquillian.container</groupId> <artifactId>arquillian-droidium-container-depchain</artifactId> <version>$\{version.droidium}</version> <type>pom</type> <scope>test</scope> </dependency> <dependency> <groupId>org.arquillian.extension</groupId> <artifactId>arquillian-droidium-native-depchain</artifactId> <version>$\{version.droidium}</version> <type>pom</type> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <phase>process-test-resources</phase> </execution> </executions> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>$\{maven.compiler.source}</source> <target>$\{maven.compiler.target}</target> </configuration> </plugin> </plugins> <!-- for filtering properties from this pom into arquillian.xml --> <testResources> <testResource> <directory>src/test/resources</directory> <filtering>true</filtering> <includes> <include>**/arquillian.xml</include> </includes> </testResource> </testResources> </build> </project> There’s much of interest here, and, to be honest, I copied it mostly wholesale from here, which is pretty much the story for the other items we’ll look at. :P Next up, arquillian.xml: <?xml version="1.0"?> <arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd"> <!-- Container configuration --> <group qualifier="containers" default="true"> <container qualifier="android" default="true"> <configuration> <property name="avdName">$\{android.avd.name}</property> <property name="droneHostPort">8080</property> <property name="droneGuestPort">8080</property> </configuration> </container> </group> <extension qualifier="droidium-native"> <property name="serverApk">selendroid-server-0.4.2.apk</property> </extension> <extension qualifier="webdriver"> <property name="browserCapabilities">android</property> <property name="remoteAddress">http://localhost:8080/wd/hub</property> </extension> </arquillian> This file is also copy and paste from the repo, with no changes made. A word of warning, though. If you look at the Droidium test project, you will see two .apks checked in: selendroid-server-0.4.2.apk, and selendroid-test-app-0.4.2.apk. The first is for the Selendroid project, which Droidium is built around. The second is the application we intend to test. I’m always bothered by libraries (jars, apks, etc) checked into source control, so I thought I’d be clever and have the build download that APK from Maven Central. Long story short, it doesn’t work as expected. The APK in Central and that found in the Droidium repo are not the same thing, so just paly along and check in this file (or script its download at build time :). Next up, the test case: @RunWith(Arquillian.class) @RunAsClient public class CubTrackerTest { @Deployment(name = "android") @TargetsContainer("android") public static Archive<?> createDeployment() { File archiveFile = new File("../app/bin/cubtracker-debug.apk"); return ShrinkWrap.createFromZipFile(JavaArchive.class, archiveFile); } @Test @OperateOnDeployment("android") public void dumbTest(@ArquillianResource AndroidDevice android, @Drone WebDriver driver) { driver.findElement(By.id("menu_add_scout")).click(); try { Thread.sleep(5000); } catch (InterruptedException ex) { Logger.getLogger(CubTrackerTest.class.getName()) .log(Level.SEVERE, null, ex); } } } The @Deployment method is pretty simple; we just point to the APK of the app to test. Whereas the Droidium test checked that into source control, in my context, the file is built as part of the larger process, so I provide a relative path to the APK. Finally, in my test, all I have it doing here is clicking on the "Add Scout" menu. Interestingly, rather than specify the text of the menu, I look up the widget at runtime via its ID. As you should know, though, Android IDs are numeric, but I’m passing a string, so it seems that Selendroid is smart enough to take "menu_add_scout" and find R.id.menu_add_scout (which is probably just simple reflection, but still. That’s pretty cool. :). The Add Scout activity should show, the test waits 5 seconds so I can see that it actually did something, and then everything shuts down: the test, the emulator. Everything. I can manually start and stop the emulator if I want, in which case Droidium doesn’t shut it down, but, just like Arquillian can start and stop your app server instance for you, it can do the same for your Android emulator. And that’s pretty cool too. This just scratches the surface, of course, as now Selendroid needs to be explored and understood, but that’s a different topic. Hopefully, what I’ve presented here will be enough to get you going with Droidium so you can quit worrying about emulator management and focus on writing tests, which is what Arquillian is all about. :) ### [A Simple OAuth2 Client and Server Example: Part I](/2013/a-simple-oauth2-client-and-server-example-part-i/) When implementing web site security, OAuth2 almost always comes up. We’ve had requests to implement OAuth2 in the GlassFish REST interface, and, it turns out, I have a similar need on a personal project. Looking at the spec, though, OAuth2 can be pretty daunting. Fortunately, you don’t need to understand it all, and Apache has a project, Oltu (nee Amber) that handles most of the implementation. Before we get too excited, I need to qualify the statements I’m about to make: I am very new to OAuth2 and, then, by no means an expert. What I’m going to present here is my current understanding of part of what the spec offers. Hopefully, it’s accurate and helpful. As with everything you read on the internet, though, it never hurts to verify. :) With that out of the way, we’re going to implement a very simple token-based authorization system. This will allow a third-party app to interact with your service on behalf of a user. Here’s the basic flow in English: A user logs in to new application on the web, which we’ll call TheApp. TheApp offers integration with a service you provide, TheService. In order to achieve this integration, TheService must authorize TheApp to act on behalf of TheUser, so TheApp redirects the user to TheService's authorization page. TheUser is presented with the option to grant or deny access to TheApp. He clicks "grant", and is redirected back to TheApp. When TheService redirects back to TheApp, it sends and authorization code. TheApp then takes that authorization code and asks TheService for the access token. TheService verifies the authorization code and returns the token to TheApp. Now, when TheUser asks TheApp to do something with TheService, either directly via the web interface or via a scheduled job, TheApp passes the token as part of the request, which TheService uses to authenticate the request. At any time, TheUser can visit TheService and revoke the token, which will break the integration between TheApp and TheService for that user. At no point does TheApp need to know the username and password for TheUser with TheService. Still with me? I hope so. I’ve put too much work into this to lose you now! :P With our basic workflow described, let’s look at an implementation. In this example, TheApp and TheService will be the same app, and TheUser will be unit tests. Let’s start with the authorization code resource: @Path("/authz") public class AuthzEndpoint { @Inject private Database database; @GET public Response authorize(@Context HttpServletRequest request) throws URISyntaxException, OAuthSystemException { try { OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request); OAuthIssuerImpl oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator()); //build response according to response_type String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE); OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND); // 1 if (responseType.equals(ResponseType.CODE.toString())) { final String authorizationCode = oauthIssuerImpl.authorizationCode(); database.addAuthCode(authorizationCode); builder.setCode(authorizationCode); } String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI); final OAuthResponse response = builder .location(redirectURI) .buildQueryMessage(); URI url = new URI(response.getLocationUri()); return Response.status(response.getResponseStatus()) .location(url) .build(); } catch (OAuthProblemException e) { // ... } } } While we’ve implemented this as a REST resource, this is the code that would back the authorization page, so it would most likely be, for example, a JSF or CDI managed bean. The user would click "authorize", and the authorize method would be called. In this case, our client (which we’ll look at in a bit), sends a request with a response type of code, so it’s handled via the block at [1]. Notice that we’re not doing any authentication for the request. If this were a real system, this method would be called in the context of an HTTP session, for which the client would already be authenticated. Probably. :) At any rate, to make things simple, we just return the authorization code via the redirect back to TheApp. Once TheApp has the authorization code, it can then request the actual token, sometimes referred to as a "bearer token". The server side of that can be implemented like this: @Path("/token") public class TokenEndpoint { @Inject private Database database; @POST @Consumes("application/x-www-form-urlencoded") @Produces("application/json") public Response authorize(@Context HttpServletRequest request) throws OAuthSystemException { try { OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request); OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator()); // check if clientid is valid if (!checkClientId(oauthRequest.getClientId())) { return buildInvalidClientIdResponse(); } // check if client_secret is valid if (!checkClientSecret(oauthRequest.getClientSecret())) { return buildInvalidClientSecretResponse(); } // do checking for different grant types if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE) .equals(GrantType.AUTHORIZATION_CODE.toString())) { if (!checkAuthCode(oauthRequest.getParam(OAuth.OAUTH_CODE))) { return buildBadAuthCodeResponse(); } } else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE) .equals(GrantType.PASSWORD.toString())) { if (!checkUserPass(oauthRequest.getUsername(), oauthRequest.getPassword())) { return buildInvalidUserPassResponse(); } } else if (oauthRequest.getParam(OAuth.OAUTH_GRANT_TYPE) .equals(GrantType.REFRESH_TOKEN.toString())) { // refresh token is not supported in this implementation buildInvalidUserPassResponse(); } final String accessToken = oauthIssuerImpl.accessToken(); database.addToken(accessToken); OAuthResponse response = OAuthASResponse .tokenResponse(HttpServletResponse.SC_OK) .setAccessToken(accessToken) .setExpiresIn("3600") .buildJSONMessage(); return Response.status(response.getResponseStatus()) .entity(response.getBody()).build(); } catch (OAuthProblemException e) { OAuthResponse res = OAuthASResponse .errorResponse(HttpServletResponse.SC_BAD_REQUEST) .error(e) .buildJSONMessage(); return Response .status(res.getResponseStatus()).entity(res.getBody()) .build(); } } // ... } This resource is actually a bit more complex. In a fully implemented OAuth2 system, TheApp would have had to register a client ID and a client secret. This done, as best as I can tell, to help control access to the number of apps that can use TheService, as well help prevent given out tokens to anyone except the intended client. Once the client ID and secret have been validated (which we’ve stubbed out here), we come to the meat of the resource, and the behavior is based on the "grant type" requested by the client (TheApp). The first grant type we check, "code", tells the service that we have an authorization code and would like a token. To make things interesting and mostly functional, I have implemented a simple datastore, called Database, that is simple a couple of Sets to store valid auth codes and tokens. If the auth code is valid, we continue. Otherwise, we return a BAD_REQUEST response. The next grant type we check is "password". One means of acquiring token, in addition to an authorization code, is using a username and password. This can be used, for example, where a mobile app redirects the user to a login page, where the user provides his credentials, which are then used to authenticate to generate the token. Once we validated the request, we can generate a token (using the Oltu class OAuthIssuer), which we store in our fake database, then generate an OAuthResponse for the client. TheApp, now equipped with the bearer token, can store it internally for use on behalf of TheUser. When requests are made to TheService, TheApp includes the token in the Authorization header: Authorization: Bearer <token> The resource must then validate the token: @Path("/resource") public class ResourceEndpoint { @Inject private Database database; @GET @Produces("text/html") public Response get(@Context HttpServletRequest request) throws OAuthSystemException { try { // Make the OAuth Request out of this request OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request, ParameterStyle.HEADER); // Get the access token String accessToken = oauthRequest.getAccessToken(); // Validate the access token if (!database.isValidToken(accessToken)) { // Return the OAuth error message OAuthResponse oauthResponse = OAuthRSResponse .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setRealm(Common.RESOURCE_SERVER_NAME) .setError(OAuthError.ResourceResponse.INVALID_TOKEN) .buildHeaderMessage(); //return Response.status(Response.Status.UNAUTHORIZED).build(); return Response.status(Response.Status.UNAUTHORIZED) .header(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse .getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)) .build(); } // [1] return Response.status(Response.Status.OK) .entity(accessToken).build(); } catch (OAuthProblemException e) { // Check if the error code has been set // Build error response.... } } } There’s quite a bit of boilerplate code there to validate the access token. It’s not until [1] that we actually do the work the resource was written to do (which is, in this case, simply returning the accessToken). Clearly, that’s too much work to be repeated, so that really should be factored out. For our purposes here, though, I’ll leave that as an exercise for the reader. If you watch the git repo for this example, though, you should find a solution for this at some point. :) That about covers the server side. In the next post, we’ll cover TheUser, which are the unit tests that drive/test our implementation. ### [What's the Deal With Containerless Frameworks?](/2013/what-s-the-deal-with-containerless-frameworks/) I’ve been spending some time with the Play Framework recently, and one of my first questions was, "Can I deploy this to an app server?", to which the answer is "No. Play is its own container". That (to be honest) somewhat disappointing answer reminded me of some discussions I recenlty saw but mostly ignored about "containerless frameworks". I’m afraid I’m going to have to let my dumb hang out (as my dad used to love to say) and confess that I guess I don’t get it. :) Before I go too far, let me say up front that I realize you don’t have to have an application server to deploy applications. Evidence at hand aside, we have, as an industry, done so for many, many years, clearly. What I don’t understand, though, and here I’m hoping those In the Know will help me out, is why doing so is A Good Thing. My guess is the common (sometimes justified, sometimes not) complaint that app servers are slow, heavy, etc. If you just want to deploy a simple to do list, then, yes, an app server is likely overkill. However, for larger (dare I say enterprise apps), it seems some sort of app server is worth the extra weight: high availability/load balancing, connection pooling, management, etc. It seems that with containerless approaches, all of these concerns are now pushed completely on to the developer (or in larger organizations, the release teams, etc), and that seems like a net loss to me. Clearly, I haven’t taken any of these types of systems to production, not even a small hobby app, so I’m hoping those of you who have can clue me in. How are these kinds of things handled outside of the app server realm? Is hosting more than one app on a server (and thus needing multiple ports) a hassle, etc? It seems like it’s just not worth all the extra effort, but people smarter than I seem to disagree. Anyone care to cure me of my ignorance? :) ### [Backing Up Your Data with Duplicity](/2013/backing-up-your-data-with-duplicity/) For those wanting to backup their data, there are a myriad of commercial products, ranging from economical to absurdly expensive, from basic to extremely flexible and robust. Depending on your needs, though, you need not spend any money at all to get a pretty poiwerful backup system. In this entry, I’ll show how I backup my workstation using duplicity. Installing duplicity should be as simple as telling yum or apt to install the package appropriate for your Linux distribution. Mac users can use MacPorts or homebrew. Windows users, you’re on your own. :) In a nutshell, duplicity will take the set of you files you specify, either implicitly via include-all pattern, or explicitly, through config files, pattern matches, etc. We’ll see and example of both in a bit. Given a backup set definition, duplicity will create the back up, either full or incremental, and upload it to the destination you specify, which can be a local drive, an FTP or SCP target, or even Amazon S3. Rather than walk through all of the options, I’ll share the script I’ve put together to manage my backups: #!/bin/bash BASE_DIR=file:///mnt/backups/duplicity DOW=`date +"%u"` REPORT_DATE=`date +%Y%m%d`; COMMON_OPTS="--asynchronous-upload --no-encryption --full-if-older-than=8D" LOG=$HOME/Documents/BackupLogs/Backup_Log_$REPORT_DATE.log # If it's Sunday, do a full backup if [ "$DOW" == "7" ] ; then TYPE=full fi # Create log directory mkdir -p $HOME/Documents/BackupLogs 2>&1 > /dev/null duplicity $TYPE $COMMON_OPTS \ --exclude-regexp '.*cache.*' \ --exclude-globbing-filelist=$HOME/local/etc/backup.exclude \ /home/jdlee/ \ $BASE_DIR/jdlee > $LOG duplicity $TYPE $COMMON_OPTS \ --exclude-regexp '.*cache.*' \ --include-globbing-filelist=$HOME/local/etc/backup.system.include \ --exclude '**' \ / \ $BASE_DIR/system >> $LOG # Clean up old backups /usr/bin/duplicity remove-older-than 14D --force $BASE_DIR/jdlee >> $LOG /usr/bin/duplicity remove-older-than 14D --force $BASE_DIR/system >> $LOG The interesting part of the script starts after the mkdir call. I have two backup sets, my home directory, and some system files. Since I call duplicity twice, I use the variable COMMON_OPTS defined above, which tells duplicity not to encrypt the files (which is fine for me), to perform an asynchronous upload to remote store, and to perform a full backup present if the last full is older than 8 days. It’s worth noting that I am saving these backup sets to a "local" file store (it’s actually a CIFS mount to a NAS device) via the file:/// (for lack of a better term) protocol. For the first backup fileset, I’ve gone with an opt-out type approach, as I generally want to back up my entire home directory. There are some things, though, such as MP3s, locally-installed software, etc., that I don’t want to back up, so I exclude them via --exclude-filelist, which takes the path to a file with the exclusions. Mine looks a bit like this: - /home/jdlee/Dropbox - /home/jdlee/Music - /home/jdlee/local/android-sdk There are more, of course, but this shows the basic format: a leading minus, a space, and the path of the file or directory. I then tell duplicity the base directory, and redirect the output to a log file. Note that any files excluded (or included) must be under the base directory you specify here. If there’s a mismatch, duplicity will complain and exit. The next backup set uses an opt-in approach, where I specify the files I want. That file looks like this: /etc/hosts /etc/fstab The format here is simpler, just the path of the file or directory to include. Again, these files must be under the base directory specified on the command line, which is / in this case, so we’re good. After the files are backed up, duplicity is told to remove anything older than 14 days. If that’s not done, the files will continue to build up. Whether or not that’s a good thing is up to you. One of the nice things about duplicity is that it won’t erase any file that’s needed by another. For example, any files from a full backup that are needed by subsequent incremental backups will not be deleted. Once another full back up is done and the incrementals have aged appropriately, though, they, too will be pruned. Restoring files is pretty simple as well, or seems to be based on the one time I’ve had to use it. :) Duplicity will not overwrite existing files, it seems, so you have restore to an empty directory, then copy/move the restore files to their original location, but that’s probably a good, safe approach anyway. With the script in place, you’re now ready to schedule the job via cron, for example, and get nice, incremental back ups on the cheap. You will, of course, need to make sure the backups are safe to be really secure, for which I use CrashPlan running on another system. ;) ### [JavaFX and AsciiDoctor: a Quick and Dirty Hack](/2013/javafx-and-asciidoctor-a-quick-and-dirty-hack/) You may or may not have noticed ([1], [2]), but I’ve been spending a lot of time with AsciiDoc lately. While it might simply be a case of noticing what you’re thinking about, it seems the tool has been gaining more and more momentum. From AsciiDoctor to Awestruct, to Jason Porter’s Maven plugin, it seems to be everywhere. At any rate, in need of a break, I wondered if I could leverage AsciiDoctor’s Java integration library and JavaFX to make a simple editor. It’s basic and ugly, but here’s what I have. To start, let’s create a basic JavaFX application. To do this, I made use of the built-in JavaFX support in NetBeans 7.3 by clicking File → New Project…​ → JavaFX → JavaFX FXML Application. I entered all of the appropriate information in the rest of the wizard, and I had my empty application. The next step was to remove all of the default/example controls in the app and create the user interface I wanted. To do this, I used the Early Access build of Scene Builder 1.1. This isn’t meant to be a Scene Builder tutorial, so I’ll leave out the details and just give you the resulting FXML file: <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.web.*?> <AnchorPane xmlns:fx="http://javafx.com/fxml" fx:controller="com.steeplesoft.doctorfx.DoctorFXController" id="AnchorPane" prefHeight="600.0" prefWidth="800.0" > <children> <SplitPane dividerPositions="0.5" focusTraversable="true" prefHeight="200.0" prefWidth="320.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <items> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> <children> <TextArea fx:id="editField" onKeyTyped="#handleKeyTyped" prefHeight="198.0" prefWidth="116.0" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> </children> </AnchorPane> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0"> <children> <WebView fx:id="preview" prefHeight="598.0" prefWidth="436.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> </children> </AnchorPane> </items> </SplitPane> </children> </AnchorPane> There’s a really good chance this is a bad pretty bad example, but I’m not JavaFX expert, so this is all I have for you. :) Next up, the Java controller class: public class DoctorFXController implements Initializable { private final Asciidoctor instance; private Map<String, Object> options; @FXML TextArea editField; @FXML WebView preview; public DoctorFXController() { options = OptionsBuilder.options() .compact(false) .headerFooter(true) .safe(SafeMode.UNSAFE) .backend("html") .asMap(); instance = Asciidoctor.Factory.create(); } @FXML protected void handleKeyTyped(KeyEvent event) { preview.getEngine().loadContent(instance.render(editField.getText(), options)); } @Override public void initialize(URL url, ResourceBundle rb) { } } Again, this probably sub-optimal code, but I’m dealing with a couple of APIs I don’t know all that well at the moment (this is a good example of "Release early. Release often" ;), so don’t get too hung up on things. When you run this application, you should see something like this: It’s not very pretty, but it "works". As you type on the left, the pane on the right is constantly updated, which is kinda cool. :P Currently, JavaFX builds are Ant-based and, to be honest, I really don’t want to muck around in that too much, so I just copied the AsciiDoc-related dependencies from Jason Porter’s Maven plugin and added those manually to the NetBeans project build path: asciidoctor-java-integration-0.1.2.jar jruby-complete-1.7.3.jar Perhaps once the JavaFX migrates the build system to Gradle, this can be made a bit prettier. For now, for a Q&D PoC app, it works just fine. The app clearly has a lot of work left. For example, note the period and the empty line at the top of the edit area. Without that, the first two lines of AsciiDoc markup are not rendered at all. If I change `= Hello, AsciiDoc` to `== Hello, AsciiDoc`, though, it renders just fine. I'm still trying to track that down. The app could also use some support (and related menus) for opening, saving, various edit actions, etc. For an hour’s worth of hacking, though, it’s not too shabby. My main interesting in this, though, was an excuse to play with the AsciiDoctor Java integration and JavaFX, and this let me do both at the same time. As I have time and energy, I’ll probably keep hacking on this. In time, a usable editor might just come of it. :) ### [Syncing Playlists with Android Devices](/2013/syncing-playlists-with-android-devices/) While I love my Android devices, one thing that has always bugged me is syncing music with them. Sure, there are some apps that claim to be able to do it, but I’ve never found one that will do what it says and be a decent music player at the same time (perhaps someone out there can point me to a good one). For the most part, then, I’ve settled on Banshee (which, as far as I can tell, doesn’t sync, but is a decent player1). Here, then, is my very manual process for syncing music. The first step is to create a playlist. You can, of course, sync all of your music, which is much easier, but my phone won’t hold all of my music, so I have to be selective. Once I’ve created my playlist, I then export it (Banshee seems to use a real database, so I have to export the .m3u manually), which I put in the root of my music directory. The only part of this post that might be of interest to anyone, is the shell script I run to sync, which looks like this: #!/bin/bash device=/media/jdlee/SD folder=Music if [ -d $device/$folder ]; then cp "$1" $device/$folder fi while read line; do song=$\{line} path=$\{song#*/music_folder/} # replace music_folder/ by your Music Folder (e.g. /home/foo/MUSIC -- use MUSIC/ instead) path=$\{path%/*} file=$\{song##*/} if [[ $\{song:0:1} != "#" ]]; then if [ -d $device/$folder ]; then mkdir -p "$device/$folder/$path" if [ ! -e "$device/$folder/$path/" ] ; then echo -e $song cp -r "$song" "$device/$folder/$path/" fi else echo "The destination directory does not exist" echo "Please check the destination directory" exit fi fi done < "$1" I found the original script here, and made some minor modifications. You will likely need to modify the values of $device and $folder, but the rest should run as is. It doesn’t remove any music not in the playlist (which I doubt is often desirable), but it will copy anything missing to the device, as well as putting the playlist on the device for consumption by your player of choice there. To run it, you just specify the name of the playlist file and watch it run: $ syncM3U NewMusic.m3u It’s very manual, but simple and clean, and it saved me some hacking of my own, so I thought I’d share. Ideally, my music player would do this for me, but I just haven’t found one I like yet, so I get to do it this way, which does have a much higher geek appeal. :P 1 It’s at least good enough that I decided to quit looking. :P ### [Setting Up an Awestruct-based Blog](/2013/setting-up-an-awestruct-based-blog/) In case you missed the announcement, I recently migrated my blog from Wordpress to Awestruct, the static site generation tool written by several JBoss engineers. As can be expected with a tool this new, there were some bumps and bruises along the way, but I managed — with lots of help — to make it to production with my efforts. To be a good open source citizen, then, I thought I’d explain my process and try to pass on what I learned. The first step is, of course, installing Awestruct, which is pretty simple: $ gem install awestruct $ awestruct -i -f bootstrap That will install Awestruct and bootstrap your site. The "bootstrap" used in the command line tells Awestruct to use the bootstrap javascript framework. The other options are 'blueprint' and '960'. I honestly can’t tell you what the differences are. I think I used blueprint, which seems to be the smallest starting point. Once that’s done, I would suggest deleting all of the .haml files. HAML seems to be Awestruct’s default/preferred markup language, but it seems "everyone" is moving toward slim. We’ll see what that looks like below. _config/site.yml Let’s start with the _config/site.yml. Something like this seems to be pretty common: title: My Blog author: Jason Lee local_tz: America/Chicago interpolate: false disqus: myblog.com base_url: http://localhost:1234 asciidoctor: :compact: true :eruby: erubis :attributes: idprefix: '' idseparator: '-' scss: :line_numbers: true :style: :expanded # if no profile is specified, the first with a deploy config is selected profiles: development: minify: false disqus_developer: true dev: true deploy: dummy: production: base_url: http://www.myblog.com #disqus_developer: false google_analytics: UA-1234567-1 minify: true deploy: host: user@myblog.com path: /home/user/path/to/site A lot of these properties should be self-explantory, so I’ll only discuss those that aren’t. The first is interpolate. Most people may not need this, but I do a lot of blogging about JSF (though not as much I used to, I guess :). As part of that, I have a lot of EL expressions, such as #\{someBean.someProperty}, in my posts. Without this option, Awestruct will try to "interpolate" the text, at which point that expression will be processed as if it were a Ruby string. Since someBean hasn’t been defined in the Ruby process, an error occurs and the build fails. If you don’t have EL expressions or something similar, it may be safe to leave this set to its default of true. I think the only one left that needs discussion is profiles.production.deploy. In my case, I have a shared host to which I want to deploy the generated site. With this configuration, when you tell Awestruct to deploy your site, it will rsync, via ssh, to myblog.com, logging in as user, and putting the files in /home/user/path/to/site. The nice thing is that it will remove files from the remote site if they are removed from the local build, so you don’t have to manage that manually. We’ll discuss (no pun intended), disqus and disqus_developer later. _ext/pipeline.rb The next important file is _ext/pipeline.rb. While site.yml configures your site, pipeline.rb configures Awestruct itself. Here you enable extensions and helpers, basically turning features on and off. As of the time of this writing, I have two Awestruct based sites, and their pipeline files look basically like this: require 'readmore' require 'erubis' require 'tilt' Awestruct::Extensions::Pipeline.new do extension Awestruct::Extensions::Posts.new( '/posts', :posts) extension Awestruct::Extensions::Paginator.new( :posts, '/index', :per_page => 10 ) extension Awestruct::Extensions::Tagger.new( :posts, '/index', '/posts/tags', :per_page => 10) extension Awestruct::Extensions::TagCloud.new( :tagcloud, '/posts/tags/index.html', :layout=>'base', :title: ">'Tags')" extension Awestruct::Extensions::Disqus.new extension Awestruct::Extensions::Indexifier.new extension Awestruct::Extensions::Atomizer.new( :posts, '/feed.atom', :feed_title: ">'Steeplesoft' )" helper Awestruct::Extensions::Partial helper Awestruct::Extensions::GoogleAnalytics helper Awestruct::Extensions::ReadMore end I don’t know Ruby (though I’ve learned some in this process), but this seems pretty straightforward to me: require is like a Java import, and the do block is configuring a new Pipeline object. Syntax questions aside, here’s my understanding of the file: The Posts extension is configured. We’re telling the system to look for the posts in file under the /posts directory. An array of post objects is then stored in the posts variable. The Paginator extension is added, using the posts array. It seems the paginator needs to know the location of the paginator, which is our index file, /index. I don’t know why it doesn’t seem to need the extension. Finally, we want to have 10 posts per page. The Tagger extension will build data based on the tags information at the top of each post (which we’ll see in a minute). It creates static tag navigation files under /posts/tags, and it also has only 10 posts per page. The TagCloud extension is here mainly to show you that it exists. I have not yet figured out how to make it work. Maybe someone can show me what I’m doing wrong. :P Since this is a static site, we can’t use a local database for comments, so we’re adding support for Disqus to our site. The Indexifier and Atomizer extensions are used to create the news feed for your site, which I still find important and helpful, even if Google disagress (R.I.P., Google Reader! :) The Partial helper allows us to define — hold on to your seats — reusable parts of a page. We’ll see this in more detail later. The GoogleAnalytics helper should be self-explanatory. ReadMore is an extension I wrote to duplicate the "read more" functionality of Wordpress. It’s in a file called readmore.rb and goes in _ext. It looks like this: module Awestruct module Extensions module ReadMore def truncate(content) index = content.index("<!-- Read More -->") if index != nil if index > -1 return content[0..index-1] end end return content end def filter(content) index = content.index("<!-- Read More -->") if index != nil if index > -1 content[index..index+11]= "" end end content end end end end Pages and posts should be able to put <!-- Read More -→ on a line by itself and things will work as expected: in page listing, the content stops at <!-- Read More -→, and on full posts, <!-- Read More -→ is removed from the output. The rest of the ugliness of the file is due to the fact that I don’t know Ruby, so I was shooting in the dark. Feel free to clean it up, but, if you do, I’d love to see your better version. :) Layouts With the site and Awestruct configured, we now need to create the look and feel for the site. This can, of course, be as fancy as you want. For this example, it’s going to be simple and ugly, but, hopefully, educational. :) Again, the Awestruct initialization will create a .haml file, which we want to delete. Instead, we want to create _layouts/base.html.slim: doctype 5 html head meta charset='utf-8' title: "(page.title ? [page.title, site.title] : [site.title]) * ' | '" link rel="stylesheet" href='/styles/style.css' script src='/scripts/some.js' javascript: someInlineJs(); css: .someInlineCss { } body class="someInlineCss" div.header h1 My Site div.content = content div.footer h3 I'm in the footer! javascript: - if site.google_analytics =google_analytics_async The slim syntax is pretty simple, but, more importantly, really clean and light. No angle brackets. Yea! Hopefully, this all pretty straightforward. For more information on the slim syntax, you can visit its home page. The import part here is the = content line. This is where the information from each page, or post, will be inserted. How do we do that? Let’s go back to the index file. index.html.slim My index pages look more or less like this: layout: base #content =partial('pagination.html.slim', :posts => page.posts) div style="clear: both" - page.posts.each do |post| =partial('entry.html.slim', :post => post, :listing => true) =partial('pagination.html.slim', :posts => page.posts) The text in between the --- markers provides metadata Awestruct needs, such as title, author, tags, publish date, etc. The #content line defines a div with an ID of content. The next line =partial…​, makes use of the Partial helper. In this case, we tell it to use the template pagination.html.slim, which is under _partials, and assign the variable posts the value of page.posts. We’ll look at the partial in a moment. The next line shows how to specify an HTML tag with arbitrary attributes. Next we have, as best as I can tell (and I’m just pulling a term from the air), a directive to Awestruct, which seems to be, more or less, straight Ruby code. Whatever the right term is, what we have is a loop over the array page.posts, and calls partial for each element, this time using entry.html.slim. Finally, we output the navigation partial again so we can have prev/next at the top and bottom. Partials Partials allow us to define a small snippet of…​parameterized HTML that we can reuse. We’ve already seen the usages of two: pagination and entry. These files are simple slim files: pagination.html.slim div.pagination div.previous style="width:50%; float: left" - if page.posts.previous_page a href=page.posts.previous_page.url Previous - if !page.posts.previous_page p Previous div.next style="width:50%; float: right; text-align: right" - if page.posts.next_page a href=page.posts.next_page.url Next - if !page.posts.next_page p Next In this partial, we use the variable page.posts, which we set in the call to partial above. entry.html.slim article.post header.entry-header h1.title a href=page.post.url =page.post.title h4 time.pubdate datetime=page.post.date.strftime('%FT%T%:z') =page.post.date.strftime "%A, %B #\{page.post.date.day}, %Y" .entry-content = truncate(page.post.content) footer.entry-footer - if page.post.tags .tags span.title | tags: - page.post.tags.each do |tag| a href="/posts/tags/#\{tag}" - if tag != page.post.tags.last ="#\{tag}, " - else ="#\{tag} " - if site.disqus #comments =page.post.disqus_comments This partial operates on a single element in our posts array, which we’ve assigned to post. Not also that, using an =, we can insert Ruby snippets to perform simple transformations. Here, I’m breaking the post date apart to generate a better looking date block. At the very end, we see Disqus come back up. When the Disqus plugin is properly configured as we did above, all the needs to be done to make use of on the page is to put =page.post.disqus_comments somewhere on your page. At build time, Awestruct does all the work required to generate the HTML and JS to do the actual integration. Site Content We can now look at the important part of this exercise, the site content itself. Personally, I’m a pretty big fan of Asciidoc, so we’re going to write our pages and post using that. Before we look at blog entries, let’s take a quick look at the simple page use case. For a "normal" page, such as an About page, for which you simply need to create a page called about.adoc: title: About author: Jason Lee h1 About This page is all about me! When the site is built, this page can be accessed via http://localhost:1234/about. Each .adoc file is compiled to a directory with the same name as the file, which contains the file index.html. Blog posts are only slight more complicated, as it seems there are conventions that need to be followed. Based on our configuration above, all blog posts must be put in the posts/ directory, and it seems, must follow the naming scheme yyyy-mm-dd-blog-post-title.adoc. Other than that, they look pretty much like any other page, with a couple more metadata entries: title: Blog Post Title author: Jason Lee date: 2013-04-19 tags: [tag1, tag2] Blog content If you know Asciidoc, you should be ready to author your post. It’s important to note that the value of tags must be an array, or the page will fail to compile. Testing Before we’re ready to push this site live, we need to test it. Awestruct comes with a simple server that should be sufficient for most cases. While starting is very simple, I have a small shell script I use, as I like to force a site clean up before I start the server, and I need to change the port on which the server listens: #!/bin/bash rm -rf _tmp _site awestruct --auto --server --port 1234 --profile development The site is now available at http://localhost:1234. For simple changes, such as page content changes, Awestruct will detect changes and recompile the page, making it more or less immediately available. For other changes, such as configuration changes, you will have to restart the server. Deployment Once we have our site set up and looking the way want it to, we’re ready to deploy. Again, Awestruct makes this very simple: $ awestruct -P production -g --force --deploy Here we’re telling Awestruct to use the production profile, to generate the site (forcing it to do so even if it thinks it doesn’t need to), and then to deploy the site using the configuration in _config/site.yml. In our case here, it will rsync the generated site with the remote host. Once that finishes, your very lightweight and, therefore, very fast web site is ready for public consumption. Final Notes As I’ve kind of hinted at, I’m still pretty new to Awestruct, so there’s a really good chance I have some things wrong: terms, techniques, other assumptions. What I’ve put together here, though, should, I hope, spare you some of the pain I went through in trying to come up to speed with tool. For things I’ve not made clear — or covered — or got completely wrong, the folks in #awestruct on Freenode are very helpful. I’ve gotten great support from Dan Allen, Aslak Knutsen, Jason Porter, and Bob McWhirter and others there. I try to hang out there as well, but as of right now, everything I know is in this document. :) Give it a go, then, and let me know if you run into problems with my instructions, and I’ll do my best to clarify and correct. Good luck! :) ### [Fairwell, WordPress!](/2013/fairwell-wordpress/) Last summer, I put up a quick entry about a new way to blog, which I’ve enjoyed using. After suffering through yet another WordPress security breach (which I’ll admit might be partly my fault through how I have my site set up and "maintained"), I’ve decided to take the next logical step and just move the whole thing to Awestruct. Overall, it’s been an enjoyable process, but it has certainly had it’s bumps and bruises. Luckily, Dan Allen, Aslak Knutsen, Jason Porter, and Bob McWhirter have been kind and patient with me. :P I’ll have more to say in the coming days about with it took, what I’ve learned, etc., but I wanted to post a quick note letting both of my readers know about the change. You should find the site faster, as it’s all static now, and much smaller (e.g., 16KB vs 47KB for the front page). Should you notice any issues, please let me know, as I still have a bit of cleaning up to do (e.g., images in older posts, implementing comments, etc). For now, though, enjoy the site. :) ### [DoctorFX](/2013/doctorfx/) Earlier today, I wrote about a quick and dirty hack I put together to create a very simple editor for AsciiDoc files. While I have no immediate plans to make this a full-featured editor, there’s a part of me that can’t help but hack on it. This evening, I added support for loading and saving files. In fact, I’m using the editor to write this post. :) For those interested in helping (or just need a good laugh :), you can find the code for this oh-so-cleverly-named project here. ### [Error Reporting for Android Apps](/2013/error-reporting-for-android-apps/) As every Android developer knows, application crashes are reported back to Google and can be view in the Play Developer’s Console. This is helpful, but, in my experience, sometimes you don’t get enough context. You also don’t get notifications when crashes are reported. Fortunately, there is a tool, called ACRA, that improves the situation quite a bit. In this post, I’ll give you a brief introduction to the tool, and how I use it in Cub Tracker. If you look at the ACRA home page, the quick start suggests a code snippet like this: import org.acra.*; import org.acra.annotation.*; @ReportsCrashes(formKey = "dGVacG0ydVHnaNHjRjVTUTEtb3FPWGc6MQ") public class MyApplication extends Application { @Override public void onCreate() { // The following line triggers the initialization of ACRA super.onCreate(); ACRA.init(this); } } In a nutshell, this configuration will tell ACRA to report all crashes to a Google Docs form. While helpful, I’ve found this less than optimal, as the spreadsheet the form feeds gets very hard to read. Then, there’s this, also from the ACRA home page: Since the recent update of Google Forms by Google, the usage of Google Docs as a storage engine for ACRA reports is becoming deprecated. — http://acra.ch/ So my advice is to skip it. :) What I’ve done in Cub Tracker is to configure an HttpPostSender instance: ACRA.init(this); ACRA.getErrorReporter().setReportSender(new HttpPostSender(ERROR_REPORTING_URL, null)); Now, rather than posting to a Google Form, it POSTS to my custom web service, which looks like this (please excuse the ugly PHP :) : <?php $message .= "PHONE_MODEL = " . $_POST["PHONE_MODEL"] . "\n"; $message .= "ANDROID_VERSION = " . $_POST["ANDROID_VERSION"] . "\n"; $message .= "PRODUCT = " . $_POST["PRODUCT"] . "\n"; $message .= "APP_VERSION_CODE = " . $_POST["APP_VERSION_CODE"] . "\n"; $message .= "APP_VERSION_NAME = " . $_POST["APP_VERSION_NAME"] . "\n"; $message .= "STACK_TRACE:\n" . $_POST["STACK_TRACE"] . "\n"; // Send mail('me@foo.com', 'Cub Tracker Error Report', $message); ?> That results in an email like this: PHONE_MODEL = Galaxy Nexus ANDROID_VERSION = 4.2.2 PRODUCT = mysid APP_VERSION_CODE = 19 APP_VERSION_NAME = 2.3 STACK_TRACE: java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetLong(Native Method) at android.database.CursorWindow.getLong(CursorWindow.java:507) at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75) ... That nicely demonstrates the flexibility of ACRA, as well as one the most frustrating and elusive bugs in my app, but, hopefully, my pain can help you with your app. :) ### [Initializing JAX-RS Sub-resources](/2013/initializing-jax-rs-sub-resources/) This morning, I was reading through the Proposed Final Draft for JAX-RS 2.0 specification, when I found a little nugget that could have saved me some work, specificially in initializing subresources. This is kind of sad to admit (though, surely — hopefully — I’m not alone in this :), but I have been initializing subresource manually. For example: public <T> T getSubResource(Class<T> clazz) { try { T resource = clazz.newInstance(); BaseResource br = (BaseResource)resource; br.uriInfo = uriInfo; br.securityContext = securityContext; br.requestHeaders = requestHeaders; return resource; } catch (Exception ex) { throw new WebApplicationException(ex, Status.INTERNAL_SERVER_ERROR); } } While this works, the problems should be pretty obvious: it’s extremely inflexible. Fortunately, the JAX-RS Expert Group, who has clearly thought about this more than I, has a better solution: ResourceContext. Take this example, pulled from the spec: @Path("widgets") public class WidgetsResource { @Context private ResourceContext rc; @Path("\{id}") public WidgetResource findWidget(@PathParam("id") String id) { return rc.initResource(new WidgetResource(id)); } } public class WidgetResource { @Context private HttpHeaders headers; public WidgetResource(String id) {...} @GET public Widget getDetails() {...} } Notice the method WidgetsResource.findWidget(). The parent resource, WidgetsResource, has an instance of ResourceContext injected, which is then used to initialize the subresource instantiated in findWidget(). The benefit of this approach over the approach above is that everthing is injected, regardless of what I’m expecting to find. I’ve been working with JAX-RS for over 3 years now, and I’m just now learning this. Shows that there’s always something to learn, and that reading specs pays off. :) ### [Writing Bash Scripts with Parameters](/2013/writing-bash-scripts-with-parameters/) In the course of my work, I often find myself writing a script to automate a routine task. Almost invariably, there are cases where I need the script to behave in slightly different fashion, but only occassionally. My early scripts rather crudely used one if after, which is not very elegant. Finally, after tiring of this clumsy approach, I searched for a better way and found one: getopts. In this shortish entry, I’ll give a very brief introduction to getopts, and show how I write my scripts now. Let’s start with a simple example: #!/bin/bash OPT_A=false OPT_C=0 function usage() { echo "USAGE:" echo " myscript [-a] [-b <value>] [-c]" exit -1 } while getopts ab:c opt do case "$opt" in a) OPT_A=true ;; b) OPT_B=$OPTARG ;; c) OPT_C=1 ;; *) usage ;; esac done echo "OPTIONS:" echo " OPT_A : $OPT_A" echo " OPT_B : $OPT_B" echo " OPT_C : $OPT_C" This simple script takes three parameters, a, b, and c. Parameters a and c are simple parameters, but b takes a value. The parameters themselves are processed in the while loop. Note that the condition for the loop is a call to getopts, whose parameters are the valid parameter list and a variable into which to store each parameter found. Note also that b has a collon following it, which signifies that this parameter takes a value. Inside the loop, we have a case statement to process the parameters as getopts returns them. In this case, we’re simply setting variables to a specific value, which we can then process later. I have also made function calls directly from the case statement, as you can see with the catchall * case. How and where you implement/call the functionality for a given parameter is, I think, a matter of style and taste. I tend either to set a variable and then test it later with if or call a function, like usage, rather than putting a lot of logic in the case block. You can put as much as you want in the block (note the ;; terminators, by the way), but I’ve found that can quickly get ugly and hard to manage. If we run this script now, say, `myscript -c b foo', we should see this output: OPTIONS: OPT_A : false OPT_B : foo OPT_C : 1 Bash scripting is, of course, extremly powerful and flexible, so there’s so much more that could be shown, but, hopefully, this will expose you to a very handy, built-in function that should make writing configurable scripts much simpler. ### [Simulating Swipes in Your Android Tests](/2013/simulating-swipes-in-your-android-tests/) As some of you may or may not know, I have small Android project, Cub Tracker, that I’ve been working on for quite some time now in my spare time. I’ve been trying to be better about quicker releases, but all the testing for the app is currently manual (and, therefore, hit-and-miss), so updates tend to be a bit slower and very cautious. (For the record, it used to have pretty decent tests, but I rewrote the app for version 2 and just never got around to porting/rewriting the tests.) My next change, though, will be pretty invasive, so I’ve decided it’s time to fix that. In doing so, though, I hit a snag pretty quickly. Cub Tracker now uses a ViewPager as the main form of navigation, and I quickly realized I didn’t know how to swipe from one page to another. It turns out there are several different ways to do it. Here are some…​ We’ll cover three, in descreasing order of complexity and pure geekiness. The first will programmatically simulate the swiping action: protected void swipe(Direction direction) { Instrumentation inst = getInstrumentation(); Point size = new Point(); activity.getWindowManager().getDefaultDisplay().getSize(size); int width = size.x; long downTime = SystemClock.uptimeMillis(); float xStart = ((direction == Direction.Left) ? (width - 10) : 10); float xEnd = ((direction == Direction.Left) ? 10 : (width - 10)); // The value for y doesn't change, as we want to swipe straight across inst.sendPointerSync(MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, xStart, size.y / 2, 0)); inst.sendPointerSync(MotionEvent.obtain(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE, xEnd, size.y / 2, 0)); inst.sendPointerSync(MotionEvent.obtain(downTime, SystemClock.uptimeMillis() + 1000, MotionEvent.ACTION_UP, xEnd, size.y / 2, 0)); } In this implementation of our swipe() method, we simulate the physical act of swiping by using MotionEvent objects. While I’m not going to pretend to understand every last nuance here, we start by determining the size of the screen, then setting our starting position 10 pixels from the edge. The ending position is then set 10 pixels away from the other edge. With those values set, we obtain tree MotionEvent objects for ACTION_DOWN, ACTION_MOVE, and ACTION_UP, passing them each to Instrumentation.sendPointerSync() in turn. With that, we’ve completed our swipe. For completeness' sake, here is the super simple enum I used to make the method signature more self-explanatory: public enum Direction { Left, Right; } While that approach is pretty fun, there’s a simpler way, which, oddly enough, actually uses the ViewPager API. :) protected void swipe(final Direction direction) { activity.runOnUiThread(new Runnable() { public void run() { int current = pager.getCurrentItem(); if (direction == Direction.Right) { if (current > 0) { pager.setCurrentItem(current - 1, true); } } else { if (current < pager.getChildCount()) { pager.setCurrentItem(current + 1, true); } } } }); } In this implementation, we make sure that we can safely swipe to the left or right, as appropriate, then set the current item index on the ViewPager to "current" plus or minus one. We pass true as the second argument to setCurrentItem() so that we can see the animation in the UI; otherwise, it just changes in a blink, and where’s the fun in that. Note that this must run on the UI thread, so I’ve wrapped all of that in a Runnable, which is pass to Activity.runOnUiThread(). Lastly, we deviate from the ViewPager API usage, and look at another, simpler take on our first implementation, this time using Robotium protected void swipe(final Direction direction) { Point size = new Point(); activity.getWindowManager().getDefaultDisplay().getSize(size); int width = size.x; float xStart = ((direction == Direction.Left) ? (width - 10) : 10); float xEnd = ((direction == Direction.Left) ? 10 : (width - 10)); // The value for y doesn't change, as we want to swipe straight across solo.drag(xStart, xEnd, size.y / 2, size.y / 2, 1); } Again, we do our endpoint calculations, but we use them in a single call to solo.drag(). Much simpler. Assuming you need to do something like this, I guess the implementation is a matter of preference. I tend to prefer option #2, as it seems a more proper use of the API and is a little less hacky than options #1 and #3, but I did enjoy learning those. In a more general sense, though, if you need to perform a swipe in a test and you don’t have a control you can directly (and easily) manipulate like the ViewPager, these two options show how it can be done, either directly with the Android APIs, or with the very nice Robotium wrapper. Have you found another/better way to do all of this? Hit the comment box and show me the error of my ways! :) ### [Oracle JDK and the Linux Alternatives System](/2013/oracle-jdk-and-the-linux-alternatives-system/) For both work and fun, I run Linux. I’m also a Java guy, which poses some interesting challenges, as most Linux distributions have a long, sad tale regarding shipping Java. Things are a bit better, I guess, with OpenJDK, but I’ve always liked running the "real thing", which historically meant the Sun JDK, and now Oracle’s JDK (Note: current employment has no bearing on that choice ; ). If I were running an RPM-based distribution, I would be set. At the moment, though, I’m running Linux Mint, so I get to use the tarball. Most of the time that works fine, but for reasons I don’t remember, OpenJDK was installed on my system, and now everything is using that (which is at Update 7, and not the recently released and more secure Update 11 that I want). I’d rather not monkey with changing PATH and all that, so I turned to the Linux alternatives system to handle things. Sadly, it wasn’t quite that easy, as alternatives needs to know about your alternatives, so before I could change things, I had to educate it, which turned out be easier than I feared. With Java 7 Update 11 installed in /opt/java/jdk1.7.0_11 and symlinked from /opt/java/latest, I had to do two things. First, it seems the actual update script, update-java-alternatives, needs a .jinfo file in /usr/lib/jvm. Mine looks like this: name=java-7-latest alias=java-1.7-latest priority=10 section=main hl java /opt/java/latest/jre/bin/java hl keytool /opt/java/latest/jre/bin/keytool hl pack200 /opt/java/latest/jre/bin/pack200 hl rmid /opt/java/latest/jre/bin/rmid hl rmiregistry /opt/java/latest/jre/bin/rmiregistry hl unpack200 /opt/java/latest/jre/bin/unpack200 hl orbd /opt/java/latest/jre/bin/orbd hl servertool /opt/java/latest/jre/bin/servertool hl tnameserv /opt/java/latest/jre/bin/tnameserv hl jexec /opt/java/latest/jre/lib/jexec jre policytool /opt/java/latest/jre/bin/policytool jdk appletviewer /opt/java/latest/bin/appletviewer jdk extcheck /opt/java/latest/bin/extcheck jdk idlj /opt/java/latest/bin/idlj jdk jar /opt/java/latest/bin/jar jdk jarsigner /opt/java/latest/bin/jarsigner jdk javac /opt/java/latest/bin/javac jdk javadoc /opt/java/latest/bin/javadoc jdk javah /opt/java/latest/bin/javah jdk javap /opt/java/latest/bin/javap jdk jcmd /opt/java/latest/bin/jcmd jdk jconsole /opt/java/latest/bin/jconsole jdk jdb /opt/java/latest/bin/jdb jdk jhat /opt/java/latest/bin/jhat jdk jinfo /opt/java/latest/bin/jinfo jdk jmap /opt/java/latest/bin/jmap jdk jps /opt/java/latest/bin/jps jdk jrunscript /opt/java/latest/bin/jrunscript jdk jsadebugd /opt/java/latest/bin/jsadebugd jdk jstack /opt/java/latest/bin/jstack jdk jstat /opt/java/latest/bin/jstat jdk jstatd /opt/java/latest/bin/jstatd jdk native2ascii /opt/java/latest/bin/native2ascii jdk rmic /opt/java/latest/bin/rmic jdk schemagen /opt/java/latest/bin/schemagen jdk serialver /opt/java/latest/bin/serialver jdk wsgen /opt/java/latest/bin/wsgen jdk wsimport /opt/java/latest/bin/wsimport jdk xjc /opt/java/latest/bin/xjc plugin mozilla-javaplugin.so /opt/java/latest/jre/lib/amd64/libnpjp2.so Next, I needed to "install" my alternatives option. The script I used to do that looks like this: update-alternatives --install /usr/bin/java java /opt/java/latest/jre/bin/java 10 update-alternatives --install /usr/bin/keytool keytool /opt/java/latest/jre/bin/keytool 10 update-alternatives --install /usr/bin/pack200 pack200 /opt/java/latest/jre/bin/pack200 10 update-alternatives --install /usr/bin/rmid rmid /opt/java/latest/jre/bin/rmid 10 update-alternatives --install /usr/bin/rmiregistry rmiregistry /opt/java/latest/jre/bin/rmiregistry 10 update-alternatives --install /usr/bin/unpack200 unpack200 /opt/java/latest/jre/bin/unpack200 10 update-alternatives --install /usr/bin/orbd orbd /opt/java/latest/jre/bin/orbd 10 update-alternatives --install /usr/bin/servertool servertool /opt/java/latest/jre/bin/servertool 10 update-alternatives --install /usr/bin/tnameserv tnameserv /opt/java/latest/jre/bin/tnameserv 10 update-alternatives --install /usr/bin/jexec jexec /opt/java/latest/jre/lib/jexec 10 update-alternatives --install /usr/bin/policytool policytool /opt/java/latest/jre/bin/policytool 10 update-alternatives --install /usr/bin/appletviewer appletviewer /opt/java/latest/bin/appletviewer 10 update-alternatives --install /usr/bin/extcheck extcheck /opt/java/latest/bin/extcheck 10 update-alternatives --install /usr/bin/idlj idlj /opt/java/latest/bin/idlj 10 update-alternatives --install /usr/bin/jar jar /opt/java/latest/bin/jar 10 update-alternatives --install /usr/bin/jarsigner jarsigner /opt/java/latest/bin/jarsigner 10 update-alternatives --install /usr/bin/javac javac /opt/java/latest/bin/javac 10 update-alternatives --install /usr/bin/javadoc javadoc /opt/java/latest/bin/javadoc 10 update-alternatives --install /usr/bin/javah javah /opt/java/latest/bin/javah 10 update-alternatives --install /usr/bin/javap javap /opt/java/latest/bin/javap 10 update-alternatives --install /usr/bin/jcmd jcmd /opt/java/latest/bin/jcmd 10 update-alternatives --install /usr/bin/jconsole jconsole /opt/java/latest/bin/jconsole 10 update-alternatives --install /usr/bin/jdb jdb /opt/java/latest/bin/jdb 10 update-alternatives --install /usr/bin/jhat jhat /opt/java/latest/bin/jhat 10 update-alternatives --install /usr/bin/jinfo jinfo /opt/java/latest/bin/jinfo 10 update-alternatives --install /usr/bin/jmap jmap /opt/java/latest/bin/jmap 10 update-alternatives --install /usr/bin/jps jps /opt/java/latest/bin/jps 10 update-alternatives --install /usr/bin/jrunscript jrunscript /opt/java/latest/bin/jrunscript 10 update-alternatives --install /usr/bin/jsadebugd jsadebugd /opt/java/latest/bin/jsadebugd 10 update-alternatives --install /usr/bin/jstack jstack /opt/java/latest/bin/jstack 10 update-alternatives --install /usr/bin/jstat jstat /opt/java/latest/bin/jstat 10 update-alternatives --install /usr/bin/jstatd jstatd /opt/java/latest/bin/jstatd 10 update-alternatives --install /usr/bin/native2ascii native2ascii /opt/java/latest/bin/native2ascii 10 update-alternatives --install /usr/bin/rmic rmic /opt/java/latest/bin/rmic 10 update-alternatives --install /usr/bin/schemagen schemagen /opt/java/latest/bin/schemagen 10 update-alternatives --install /usr/bin/serialver serialver /opt/java/latest/bin/serialver 10 update-alternatives --install /usr/bin/wsgen wsgen /opt/java/latest/bin/wsgen 10 update-alternatives --install /usr/bin/wsimport wsimport /opt/java/latest/bin/wsimport 10 update-alternatives --install /usr/bin/xjc xjc /opt/java/latest/bin/xjc 10 update-alternatives --install /usr/lib/mozilla/plugins/mozilla-javaplugin.so mozilla-javaplugin.so /opt/java/latest/jre/lib/amd64/libnpjp2.so 10 Once that ran (Hint: i put that in a text file, which I ran via sudo bash foo), I was able to issue sudo update-java-alternatives -s java-1.7-latest and test my change: java -version java version "1.7.0_11" Java(TM) SE Runtime Environment (build 1.7.0_11-b21) Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode) Voila! Now all I need to do to update Java is install a new version and update the symlink. That was probably a lot more work than adding a PATH entry to point to my new JAVA_HOME, but it was also a lot more fun. :) I also have no idea, to be honest, if this is the "best" approach, or if everything I did is correct (especially the plugin part), but it works for now, and that was my goal. If I come across a more correct approach, I’ll likely revisit this. In the meantime, I can finally run the JDK I want, and that’s all I care about at the moment. :) ### [Merry Christmasi 2012](/2012/merry-christmasi-2012/) Merry Christmas! “Do not be afraid; for behold, I bring you good news of great joy which will be for all the people; for today in the city of David there has been born for you a Savior, who is Christ the Lord.” — Luke 2:1-20 ### [Asynchronous JAX-RS](/2012/asynchronous-jax-rs/) Recently, I had to add support for asynchronous REST calls to the GlassFish REST interface to satisfy some customer requirements. In process of doing so, I learned something pretty interesting: while asynchronous REST may mean different things to different people (e.g., I’m pretty sure Atmosphere provides some sort of REST asynchrony, but I’m not sure what UPDATE #1: As noted in the comments, I know next to nothing about Atmosphere. I mention it here only as some weak attempt at completeness that is, in hind sight, a really bad choice), implementing an async REST resource with JAX-RS is really quite simple. In this post, we’ll take a look at two different approaches to "asynchronous" REST. For the second post in a row, I have scare quotes in my teaser. For the second post in a row, let me explain why. :) In terms of JAX-RS, "asynchronous" really has two different…​meanings, depending on the context in which it’s used. There’s server-side, and there’s client-side, and they’re not quite the same thing. Let me quote from a conversation I had with the Jersey team: The type of asynchrony supported in JAX-RS is not something observable on the wire (e.g. if your resource method is asynchronous, it does not result in a client connection being closed with an HTTP 201 response which would force client to actively poll for the actual response later). The asynchrony is only an "implementation" detail of either party - client or server and relates to the threading model of that party. Since threading models of client and server do not directly influence the programming model of the other party, it does not matter whether you consume asynchronous service with a synchronous client and vice versa - the communication between the two is not affected. — Marek Potociar Makes sense? Let’s dive in and clear things, with a look at server-side first: Server-side To start, let’s look at an "asynchronous" REST resource: @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) public void async(final String text, @Suspended final AsyncResponse ar) { getExecutorService().submit(new Runnable() { @Override public void run() { String result = doSomethingReallySlow(text); ar.resume(result); } }); } UPDATE #1: Please see Gerard’s comments below about performance regarding the ExecutorService UPDATE #2: Based on reader feedback, I have hidden the details of the ExecutorService creation as I don’t want to distract from the main point. Despite what it may sound like, server-side asynchrony does not mean (at least in the JAX-RS context) that the server disconnects from the client, then pushes the result to it eventually. What this resource does, though, is accept the request, then, through the use of the java.util.concurrent.Executors framework, pushes the request processing to a background thread. This allows the selector thread, the one handling network requests, to wait for an answer another request. Once the processing is finished, the Runnable we created will return the response to the client using the AsyncResponse object we injected as a method parameter. In a nutshell, the REST resource does its work on a separate thread, then tells JAX-RS that it has a response. The client, though, continues to block. There is no on the wire difference. Update #3 After talking to the Jersey team, they suggested this: @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.TEXT_PLAIN) @ManagedAsync public void async(final String text, @Suspended final AsyncResponse ar) { ar.resume(doSomethingReallySlow(text)); } That’s much smaller and simpler than the example above. The only caveat is that @ManagedAsync is a Jersey-specific feature, so this code is not portable to other JAX-RS implementations. If you’re OK with that, then feel free. If not, I’d suggest implementing getExecutorService() with something production-ready. That was pretty easy. What about client-side? Is that more like what we usually think of when we say "asynchronous"? Client-side The short answer is, "Yes". :) Like what we saw on the server-side, though, there’s not on-the-wire difference here, and the asynchronous nature is really a…​trick of the JAX-RS Client API. Let’s see some code, then I’ll explain: public void asyncRestClient() throws JSONException, InterruptedException { getClient() .target(restUrl) .request(MediaType.APPLICATION_JSON) .async() .post(Entity.entity("Here is some text", MediaType.TEXT_PLAIN), new InvocationCallback<Response>() { @Override public void completed(Response response) { processResponse(response.readEntity(JSONObject.class)); } @Override public void failed(ClientException ce) { // Do something } }); } In this simple example, we have a couple of changes to how we use the JAX-RS Client API. First, we make a call to async(), and, second, we pass an instance of InvocationCallback to post(). What happens here, then, is the Client creates a background thread to handle the request. This thread sends the request, then blocks, waiting for the response. Once the response is received, it calls completed() on our InvocationCallback object. At that point, we read the entity off the Response, and pass it along to a business method for processing. If an error occurs, the Client will call failure(), at which point we would handle the error in a manner appropriate for our context. In both of these case, server-side and client-side, adding asynchrony is pretty simple. While frameworks like Atmosphere (which calls JAX-RS' asynchronous API "strange" :) may provide much more sophisticated asynchronous support (and it seems to me, from what little I know of Atmosphere, to be more focused on SSE, though please correct me if I’m wrong. UPDATE #1: which JFA does in the comments), unless you really need it, you need not do much extra work. JAX-RS has nice (and easy) support built right into the framework. Give it a whirl and see if it fits your needs. And speaking of SSE, my next post will show a non-GlassFish-specific implementation of server-sent events and JAX-RS. Stay tuned. :P ### [Using Server Sent Events and the GlassFish REST Interface](/2012/using-server-sent-events-and-the-glassfish-rest-interface/) Wikipedia defines Server-Sent Events as "a technology for providing push notifications from a server to a browser client in the form of DOM events. The Server-Sent Events EventSource API is now being standardized as part of HTML5 by the W3C." It’s a great alternative to polling the server for updates. Long story short, thanks to the work of the Jersey team, we have "easy" access to this in GlassFish, and we’ve added support for it to our RESTful administration interface. Let’s take a look at a quick sample. I should explain my scare quotes above, before we get too far, and I’ll start with two brutally honest admissions: 1) I didn’t write most of the SSE support we’ll see today, 2) I don’t understand yet, some of the mechanics. Whew! I feel better. :P One more caveat: this is not intended to be a general REST/SSE how to (though I might try my hand at one later), but, rather, a GlassFish REST admin SSE discussion. If you’re not interested in managing GlassFish via our REST APIs, then this might not interest you much. Or it might. Either way, you’ve been warned. With that out of the way, I need to describe a few GlassFish architectural items. The first, and most important for our purposes here, is the primary way, fundamentally, of interacting with the various GlassFish backend subsystems is the AdminCommand. Every REST resource we expose is ultimately based on this building block. (There are a number of technical and historical reasons for this that are out of scope here). The second architectural item to note is a…​ type of REST resource we’ve termed "composite resources". These are not composites of other REST resources, but of 1 or more AdminCommand invocations. In GlassFish 3.x, each REST request was backed ultimately by a call to a single AdminCommand, which resulted in a very fine-grained API. For GlassFish 4.x, one of our goals is to provide a framework for quickly and easiliy writing management REST interfaces that expose a higher-level (more coarsely-grained) API. That, in a nutshell, is the goal of composite resources. I tell you all of that for two reasons. The first is that I’ve had people ask for more details on the background, and the second is that we’ll be dealing with both of those in this entry, so it will help to understand their backgrounds. With all of that said, let’s get to the code. The Server Side Currently, we don’t have any REST resources in the GlassFish repo to demonstrate this, but that’s not going to stop us: We’re going to write one right here! :P Let’s first, then, take a look at an AdminCommand. One of the main reasons to use SSE is that the REST request might take a while (take, for example, cluster creation). What this new SSE support will allow us to do is expose the functionality in such a way that will allow the client to send the request, then be notified, asynchronously, of the progress as the request is processed. That will allow the client to do other things, if it so chooses, while the request is being handled. What we need, then, is a long-running AdminCommand: @Service(name = "slow-command") @PerLookup @ExecuteOn(RuntimeType.DAS) @CommandLock(CommandLock.LockType.NONE) @Progress(totalStepCount = 5) public class SlowAdminCommand implements AdminCommand { public void execute(AdminCommandContext context) { ProgressStatus progressStatus = context.getProgressStatus(); ActionReport report = context.getActionReport(); for (int i = 1; i <= 5; i++) { sleep(); progressStatus.progress(i, "Finished step #" + i); } report.appendMessage("Slow command completed."); } protected void sleep() { try { Thread.sleep(1000); } catch (InterruptedException ex) { Logger.getLogger(SlowAdminCommand.class.getName()) .log(Level.SEVERE, null, ex); } } } This is a pretty simple and boring AdminCommand, if you’re used to seeing them, but, in a nutshell, this command sleeps 5 times, for 1 second at a sime, updating the progress status after each sleep. Finally, it returns a message in the ActionReport, another Admin infrastructure artifact. All the bits and pieces of this are out of scope, but included here for the curious. Let’s take a look at how this might be exposed via REST, now. In short, we can add new REST resources to the system by doing two things: # Writing a JAX-RS class that extends CompositeResource # Annotating that class with @Service Here is how this might look: @Service @Path("/slow") public class SlowRestResource extends CompositeResource { public static final String MESSAGE = "It works!"; @GET @Produces(MediaType.TEXT_PLAIN) public String plain() { return MESSAGE; } @GET @Produces(SseFeature.SERVER_SENT_EVENTS) public EventOutput get() { return this.executeSseCreateCommand(getSubject(), "slow-command", Util.parameterMap(), new ResponseBodyBuilder() { public ResponseBody build(ActionReport report) { return Util.responseBody() .addSuccess(MESSAGE); } }); } } If you’re familiar with JAX-RS, this should look pretty familiar, apart from the RestModel defined at the end. That’s part of the composite component supports extensible data model support and is (say it with me!) out of scope here. :) This resource has a single method, get(), which returns an EventChannel. Note that EventChannel has been changed to EventOutput in more recent versions of the JAX-RS 2.0 specification (and EventChannel.SERVER_SENT_EVENTS becomes SseFeature.SERVER_SENT_EVENTS). The real meat of the SSE handling is hidden away nicely in the executeSseCreateCommand() method. The curious can find that in the GlassFish source repo, but it’s pretty heavily steeped in GlassFish internals. You’ve been warned. Again. :) The Client Side OK. So most of the server is of little interest to well over 99% of the people reading this. The interesting part is the client, and, well, it’s interesting. :) Here is our test client: public class SseClient { public static void main(String... args) throws IOException, JSONException { Client client = JerseyClientFactory.newClient(); client.configuration() .register(new AdminCommandStateJsonReader()) .register(new ProgressStatusDTOJsonReader()) .register(new ProgressStatusEventJsonReader()) .register(GfSseEventReceiverReader.class); GfSseEventReceiver eventReceiver = client.target("http://localhost:4848/management/slow"). request(EventChannel.SERVER_SENT_EVENTS). get(GfSseEventReceiver.class); boolean closeSse = false; GfSseInboundEvent event; ActionReport ar = null; String message = null; do { event = eventReceiver.readEvent(); if (event != null) { final String eventName = event.getName(); if (AdminCommandState.EVENT_STATE_CHANGED.equals(eventName)) { AdminCommandState acs = event.getData(AdminCommandState.class, MediaType.APPLICATION_JSON_TYPE); if (acs.getState() == AdminCommandState.State.COMPLETED || acs.getState() == AdminCommandState.State.RECORDED) { if (acs.getActionReport() != null) { ar = acs.getActionReport(); final JSONObject responseBody = new JSONObject((Map)ar.getExtraProperties().get("response")); JSONArray messages = responseBody.getJSONArray("messages"); message = ((JSONObject)messages.get(0)).getString("message"); } closeSse = true; } } } } while (event != null && !eventReceiver.isClosed() && !closeSse); if (closeSse) { try { eventReceiver.close(); } catch (Exception exc) { } } System.out.println(message); } } As you can see, there’s a lot going on here. First, we need to create and configure the client, which is the new JAX-RS Client. We register a few GlassFish-specific MessageBodyReader implementations, which are needed to deserialize the JSON responses from the server. (Note: a source comment on GfSseEventReceiverReader says "TODO: Temporary implementation until more features in Jersey client", so this requirement may go away before GlassFish 4.0 ships). Once we have our client instance, we can make the REST request, asking Jersey to return us a GfSseEventReceiver. With that, we start a loop. Inside the loop, we read an event from the receiver, and pull out its name. When calling an AdminCommand-backed, SSE-enabled GlassFish REST resource, you will always get at least three event types: AdminCommandInstance/stateChanged, ProgressStatus/state, and ProgressStatus/change. First, you will receive an AdminCommandInstance/stateChanged event, which will tell you (if you were to examine the JSON or the AdminCommandState object it becomes) that the command is "RUNNING". The next event, ProgressStatus/state will inform you of the initial state of the ProgressStatus object the server uses internal for, as you might guess, progress status. If you will look back at our AdminCommand, you’ll see a call to progressStatus.progress(). A long-running process can make these calls to denote steps in the overall process, which are then sent to the client via the ProgressStatus/change event. Finally, you will receive one last AdminCommandInstance/stateChanged event, informing you that the command has "COMPLETED". It might help to see the whole stream as JSON. You can request it from the server by issuing this command: curl -H 'Accept: text/event-stream' http://localhost:4848/management/slow: event: AdminCommandInstance/stateChanged data: {"state":"RUNNING","id":"1","empty-payload":true} event: ProgressStatus/state data: {"progress-status":{"name":"slow-command","id":"1","total-step-count":-1, "current-step-count":0,"complete":false}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["TOTAL_STEPS"],"progress-status": {"name":"slow-command","id":"1","total-step-count":5,"current-step-count":0,"complete":false}}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["SPINNER","STEPS"],"message": "Finished step #1","progress-status":{"name":"slow-command","id":"1", "total-step-count":5,"current-step-count":1,"complete":false}}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["SPINNER","STEPS"],"message": "Finished step #2","progress-status":{"name":"slow-command","id":"1", "total-step-count":5,"current-step-count":3,"complete":false}}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["SPINNER","STEPS"],"message": "Finished step #3","progress-status":{"name":"slow-command","id":"1", "total-step-count":5,"current-step-count":5,"complete":false}}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["SPINNER"],"message": "Finished step #4","progress-status":{"name":"slow-command","id":"1", "total-step-count":5,"current-step-count":5,"complete":false}}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["SPINNER"],"message": "Finished step #5","progress-status":{"name":"slow-command","id":"1", "total-step-count":5,"current-step-count":5,"complete":false}}} event: ProgressStatus/change data: {"progress-status-event":{"changed":["COMPLETED"],"progress-status": {"name":"slow-command","id":"1","total-step-count":5,"current-step-count":5, "complete":true}}} event: AdminCommandInstance/stateChanged data: {"state":"COMPLETED","id":"1","empty-payload":true,"action-report": {"message":"Slow command completed.","command":"slow-command AdminCommand", "exit_code":"SUCCESS","extraProperties":{"response":{"messages": [{"message":"It works!","severity":"SUCCESS"}]}}}} Under a "normal" synchronous REST request, when the entity is created, GlassFish REST Resource Guidelines, the server will return 201 (CREATED) status code, with the URI of the newly created entity in the Location header. Since this asynchronous, SSE-based interaction is so different, we have to return this data in a different manner. Currently, this is done via a ResponseBody object (another GlassFish model) that can hold messages, as well as the item/entity. Things in this area are likely to change as we continue to think about and stress test this functionality, so if you’re an early adopter, keep your eyes open. :) Caveats If you haven’t picked up it yet, "there are a few exceptions, a few provisos, and a couple of quid pro quos." Much of this code is brand new. There’s also quite a bit of time between now and when GlassFish 4.0 ships, so this code could change. I’m not real comfortable with the current mechanism for returning the desired repsonse, to be honest. For example: the client code seems a bit verbose, so we might be able to provide some client-side utilities to help encapsulate that; and the JAX-RS spec continues to change as that EG refines the new revision; just to name a few. The take away should be, then, that you can start playing with this now, with the code I’ve presented here, but you need to keep in mind that early adopters usually stub their toes a bit as products mature. :) In one form or another, though, this support will be present when GlassFish 4.0 ships, so you can count on that, though I can’t say at this point which resources, specifically, will support SSE. Time will tell on that. You can find the source here. If you have any questions or suggestions, see the box below. :) ### [Maven Project Version from the Command Line](/2012/maven-project-version-from-the-command-line/) A friend asked me today how to get a project’s version out of a Maven POM file without having to read and parse it. A quick Google search brought up the answer, which I thought I’d share here. The short answer is this: $ mvn help:evaluate -Dexpression=project.version [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building GlassFish Admin REST Service 4.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-help-plugin:2.1.1:evaluate (default-cli) @ rest-service --- [INFO] No artifact parameter specified, using 'org.glassfish.main.admin:rest-service:jar:4.0-SNAPSHOT' as project. [INFO] 4.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.468s [INFO] Finished at: Tue Oct 30 12:11:47 CDT 2012 [INFO] Final Memory: 11M/148M [INFO] ------------------------------------------------------------------------ There we have the version number for GlassFish’s rest-service module: 4.0-SNAPSHOT. Clearly, though, this isn’t optimal. There’s still all that Maven noise around the value we want. Let’s do this, then: $ mvn help:evaluate -Dexpression=project.version | grep -v "^\[" 4.0-SNAPSHOT And there’s our value, nice and clean. You’re probably scripting this, though, so you’d like to capture that value, so, for those not as familiar with bash scripting, here’s how that’s done: $ VERSION=`mvn help:evaluate -Dexpression=project.version 2>/dev/null| grep -v "^\["` $ echo $VERSION 4.0-SNAPSHOT Voila! The value of expression can be, it seems, any valid POM property. I’ve tried project.name, project.description, etc., and they’ve all worked. Even project.dependencies works, though its output might not be as useful to a script. ### [Yum Pseudo-Transactions](/2012/yum-pseudo-transactions/) If you follow me on Twitter, you may have seen that I’ve been looking for a good media player. This long, painful process involved installing project Foo, along with its 87 dependencies, only to see that I didn’t like it, then running into the same thing with Bar and Baz. Now I have a ton of packages installed that I don’t need, which will irritate me as I think of all the wasted disk space. This morning, I decided to give Cinnamon a try. After seeing its long list of dependencies, I decided to tackle that problem and (the sadly named) tx_yum was born. Before I get to the script, I’ll admit that when it comes to maintaining the RPM database, my skills are sorely lacking. Beyond installing and uninstalling, I can’t do much. :) This script, then, may not be optimal, but it was a fun, quick effort, so lay off! :P That said, #!/bin/bash APP_NAME=`basename $0` TXN_DIR="$HOME/.$APP_NAME" function usage() { echo "The arguments to use are:" echo " -l : List all transactions" echo " -r <title> : Rollback transaction <title>" echo " -t <title> : Set a title for this transaction (default is first package name)" exit 1; } function list_txns() { ls $TXN_DIR | sed -e 's/\.txn$//' exit 0 } while getopts hilr:t:y opt do case "$opt" in h) usage ;; l) list_txns ;; t) TITLE=$OPTARG ;; r) ROLLBACK=true ; TITLE=$OPTARG ;; *) usage ;; esac done if [ "$TITLE" == "" ] ; then TITLE=$1 else shift 2 fi TXN_FILE="$TXN_DIR/$TITLE.txn" if [ "$ROLLBACK" == "" ] ; then echo "Preparing transaction for $TITLE" sudo yum install -y $* 2>&1 | tee /tmp/tx_yum.log if [ $? == 0 ] ; then mkdir -p $TXN_DIR cat /tmp/tx_yum.log | grep "Installing :" | cut -f 5 -d " " > "$TXN_FILE" else echo "Installation failed. No transaction recorded" exit -1 fi rm /tmp/tx_yum.log else if [ ! -e $TXN_FILE ] ; then echo "Transaction not found" exit -1 else echo "Rolling back transaction $TITLE" cat "$TXN_FILE" | xargs sudo yum remove -y rm "$TXN_FILE" fi fi This script takes a parameters. With -t, the user can specify the name of the "transaction" that will be recorded. If this option is not specified, the name of the first package is used. Transactions can be "rolled back" using -r, which takes the name of the transacation to roll back, and transactions can be listed with -l. For example: $ tx_yum cinnamon <lots of deleted output> $ tx_yum -l cinnamon $ tx_yum -r cinnamon Rolling back transaction cinnamon $ tx_yum -l $ That’s all there is to it. While I’m sure there are flaws and inefficiencies, it seems to work pretty well. If you have an improvement, feel free to hit the comments below. Either way, I hope you find it as helpful as I have so far. Now to find those orphaned RPMs…​ :) ### [Converting Many Images to One PDF](/2012/converting-many-images-to-one-pdf/) I recently had the need to convert several scanned images into one multi-page PDF. While there are probably tools to help do this manually, I knew that there was a good chance I’d have to do something like this again, quite possibly with a large number of images, so I did what any good geek would do: I scripted it. In this entry, I’ll show how I went about that. For starters, let’s take a look at the very small, simple Python script: #!/usr/bin/python import os,sys, PythonMagick from pyPdf import PdfFileReader,PdfFileWriter if not ((len(sys.argv) > 2) and sys.argv[1].endswith('.pdf')): print "usage: images_to_pdf.py <finalname.pdf> <image1.pdf> <imagen.pdf>" else: final_name = sys.argv[1] merged = PdfFileWriter() for file in sys.argv[2:]: print "Processing %s..." % (file) img = PythonMagick.Image() img.read(file) img.write('temp.pdf') pdf = PdfFileReader(open('temp.pdf')) for page in pdf.pages: merged.addPage(page) os.remove('temp.pdf') merged_file = open(final_name, mode='wb') merged.write(merged_file) merged_file.close() There’s not a lot to it, thanks in large part to PythonMagick and pyPDF. This script takes at least two parameters: the final name of the PDF, and at least on image file. The bulk of the work flow is this: Create a PdfFileWriter object. This handles the heavy lifting in actually writing the PDF Iterate over the image file names given Create an Image object and read the image source into it Write the image to a temporary PDF file. This implicitly converts the image to a PDF. Read the temporary PDF into memory via PdfFileReader For each page in the temporary PDF (which should be exactly 1), add it to the real, final PDF Delete the temporary PDF Write the newly constructed PDF to disk and exit It’s very simple, and pretty dumb (I added only enough error checking to make it work for me ;), and it may be a suboptimal use of the APIs, but it works pretty well for me. Hopefully, it will help someone else out. ### [Annotation Processing the New Way](/2012/annotation-processing-the-new-way/) I recently ran into an issue with our dependency injection system: it won’t return a list of interfaces, only implementations. That system, for what it’s worth, is HK2, but CDI has the same "problem". Since the rest of the system worked using these interfaces, I really wanted to solve the discoverability issue rather than redesigning that part of the system. After considering and playing with a Maven plugin, I opted to use the javax.annotation.processing API. Let’s take a quick look. The first step, of course, is to create the annotation. We’ll use this very simple one: @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyAnnotation { String parent(); } Nothing special there. The next step is to create the Processor class: @SupportedAnnotationTypes("com.foo.MyAnnotation") public class MyAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); try { Map<String, List<String>> classes = new HashMap<String, List<String>>(); for (TypeElement te : elements) { for (Element e : env.getElementsAnnotatedWith(te)) { final String parent = e.getAnnotation(MyAnnotation.class).parent(); List<String> list = classes.get(parent); if (list == null) { list = new ArrayList<String>(); classes.put(parent, list); } list.add(e.toString()); } } if (!classes.isEmpty()) { final Filer filer = processingEnv.getFiler(); FileObject fo = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/com.foo.MyAnnotation"); BufferedWriter bw = new BufferedWriter(fo.openWriter()); // ... bw.close(); } } catch (IOException ex) { messager.printMessage(Kind.ERROR, ex.getLocalizedMessage()); } return true; } } I trimmed as much of the logic as I could to clarify, I hope, the details of the processor. The class extends AbstractProcessor. It is also annotated with @SupportedAnnotationTypes, which is a multi-valued annotation telling the system which annotations we care about. In our case, it’s just one. In the process() method, we iterate over the elements which is, as best as I can tell, a Set of the annotations we just told the system we care about. Taking that, we ask the system (via env.getElementsAnnotatedWith()) for the elements that have that annotation. From here, we can get the annotation instance and process it (e.getAnnotation(MyAnnotation.class)). You may need to do some type checking (e.g., is this annotation only on a String?). In this example, we’re going to store it in a List, which is then stored in a Map, keyed by the value of parent. Once we’ve processed all the elements, we’re ready to create our metadata file. To do that, we instruct the Filer, obtained from the ProcessingEnvironment we get from AbstractProcessor, to create a resource. We tell it to use StandardLocation.CLASS_OUTPUT as the output directory (or Location in the parlance of the API), and to name it META-INF/com.foo.MyAnnotation. Once that’s done, the final step is to add this jar as a compile-time dependency to any project that uses the annotation (and which needs the metadata generated): <dependency> <groupId>com.foo</groupId> <artifactId>annotation-processor</artifactId> <version>1.0</version> <scope>compile</scope> </dependency> And that’s it. When your build tool (Maven, Gradle, or…​ shudder Ant :) compiles the classes in the project, it will create the metadata file. If you’re using Maven, you can verify by viewing target/class/META-INF/com.foo.MyAnnotation. Update: Reading the data The other side of this reading the data to finish locating the interfaces. Here is the code I’m currently using: // This Map<List> holds MyAnnotation data keyed by parent(). Since there may be more than one // MyAnnotation pointing to a given parent, we store the name of the actual MyAnnotation-annotated // interfaces in a List. private static final Map<String, List<String>> myAnnotations = new HashMap<String, List<String>>(); private static void loadMyAnnotationMetadata(Class similarClass) { try { Enumeration<URL> urls = similarClass.getClassLoader().getResources("META-INF/com.foo.MyAnnotation"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); while (reader.ready()) { final String line = reader.readLine(); if (line.charAt(0) != '#') { if (!line.contains(":")) { Logger.getLogger(MyAnnotationUtil.class.getName()).log(Level.INFO, "Incorrectly formatted entry in \{0}: \{1}", new String[] {"META-INF/com.foo.MyAnnotation", line}); // TODO: i18n } String[] entry = line.split(":"); String base = entry[0]; String ext = entry[1]; List<String> list = myAnnotations.get(base); if (list == null) { list = new ArrayList<String>(); myAnnotations.put(base, list); } list.add(ext); } } } } catch (IOException ex) { Logger.getLogger(MyAnnotationsUtil.class.getName()).log(Level.SEVERE, null, ex); } } This code reads any metadata files found in the running system and builds a Map<String,List> to hold the data. Elsewhere in the system, I iterate over these Lists and load the classes (Class.forName()) to integrate the interfaces into the system: List<String> list = myAnnotations.get(parent)); if (list != null) { for (String className : list) { try { Class<?> c = Class.forName(className, true, similarClass.getClassLoader()); exts.add(c); } catch (ClassNotFoundException ex) { Logger.getLogger(MyAnnoationUtil.class.getName()).log(Level.SEVERE, null, ex); } } } That should cover it. There’s much, much more that can be done in your processor, which you can read about in the javadocs, but this should get you going. ### [A New Way to Blog](/2012/a-new-way-to-blog/) On the Sunday before the recent JAX conference in San Francisco, I was privileged to attend the Speakers' Summit with many of the other speakers for that week. There was a lot of really good discussions, but the biggest thing I took away from it, or at least the most practical, came from Dan Allen’s lightning talk on documentation and removing the pain. That five minute talk stands a good chance of changing the way I write. Dan’s main point, as I saw it, is that documentation is hard enough, so why do we make it harder with all of those angle brackets? Whether we’re writing a blog entry and using HTML or a full-length book and using docbook, those angle brackets get in the way. They’re hard to type (correctly) and even harder to read. If I recall correctly, he had two suggestions (with one building on the other): asciidoc and awestruct. asciidoc is utility that allows one to write HTML, docbook, etc in a more natural format. There are no angle brackets (mostly). You just write your text, using a simpler, faster format. Once you have asciidoc installed, you can see the complete syntax by running asciidoc --help syntax. I am, in fact, writing this entry using asciidoc. My recent entry, Writing Pluggable Java EE Applications, The Explanation was also written in asciidoc. Once you’re familiar with the syntax, it really is simpler to use, and, thanks to a tool called blogpost, I can work offline, then post when I’m ready. What is blogpost? It’s another command-line utility that allows one to write a blog entry in asciidoc, then post (or update, delete, etc) that entry to a Wordpress-based blog. You can find more details here. Locally, I can run asciidoc to produce HTML, which I can review, and when I’m happy with it, I can run blogpost to push it to my site. So far, I like it. We’ll see how it does in the long term, but, for now, I’m going to run with it. :) The other tool is awestruct. As I understand it, it’s a tool for generating a static website, which can be authored in haml or markdown. It supports templating, theming, etc., and can even upload the generated content to your site for you. I intend to give this a whirl for Cub Tracker documentation when I get the time. It looks like a pretty nice tool. You can see some sample sites here, and you can get started here. One last item I think I should mention is presentations. Dan didn’t mention this here, but I see that he’ll be covering it at The Rich Web Experience (incidentally, it looks like he’ll be also be covering there what he shared briefly at the Summit). The idea is to author presentations without presentation packages (such as Powerpoint or OpenOffice.org Impress), but, rather, to use HTML5, JS, and CSS. I wasn’t able to catch any of Dan’s presenations during the conference, but Brian Leathem used the same approach, and it looked rather nice. While not required, it seems the JBoss guys are using awestruct to do much of the heavy lifting, so once you learn that, you’ll be set for this. :) You can find the source to Brian’s presentation on GitHub to see how it’s done. These are all certainly interesting approaches, and, based on my limited experience, much lighter and easier. I certainly intend to give them all a fair shake to see if they fit how I work, and, if not, if I should change how I work. :) If you have time and/or interest, you should check it out as well. ### [Writing Pluggable Java EE Applications, The Explanation](/2012/writing-pluggable-java-ee-applications-the-explanation/) I recently posted the slides and the source code from the presentation I gave at JAXConf San Francisco. While that’s helpful for those who were in my session, it’s probably less so for those who weren’t. What I’ll do in this post, then, is discuss the slides and code in detail, skipping over the introductory slides, and getting right to the heart of the matter. The idea of plugins is easy. The how is, often the hard part. To provide the "how", I’ve broken the question into two parts: how do I get access to the plugins, and how do I write the plugins. Problem #1: ClassLoading Perhaps the first question one should ask is, "How do I load the plugin data?" After all, if you can’t load the plugins, who cares if you can write them? There are many, many options, of course, but we’ll take a look at three, to keep things simple: repackaging, manual class loading, and OSGi. Repackaging Perhaps the simplest, safest approach is simply to repackage the application. This is exactly what it sounds like: you take the original application archive, and .war, for example, and add the plugin jars. This avoids some of the potential problems we’ll see in other approaches, as well as pushing the heavy lifting on to your container. You can do this through some sort of Ant- or Maven-based system, or a simple shell script: #!/bin/bash DIST=$1 if [ "$DIST" == "" ] ; then echo "You must specify the distribution .war" exit 1 fi BASE=`echo $DIST | sed -e 's/\.war//'` rm -rf work mkdir work cd work jar xf ../$DIST cp ../plugins/*jar WEB-INF/lib jar cf ../$BASE-repackaged.war * cd .. rm -rf work The upside to this is that you maintain access to all of the technologies provided by your container: EJB, JMS, etc. The downside is that deployment/upgrade takes a bit more work, and means that if you forget to run this process, you’ve suddenly lost all of your plugins. Not a major thing, but certainly a thing. :) Manual ClassLoading From a technical perspective, this is my favorite approach, simply because of the pure hardcode geekiness of it. In a nutshell, we read the bytecode from the jar file(s), and shove it into the ClassLoader. Fraught with peril, sure, but fun nonetheless. In the source tarball, you’ll find a project called Plummer. Plummer, so called because it provides some of the plumbing for the plugin system. before we dive into what Plummer provides, we should note that the plugin approach we’ll look at is based very heavily on CDI, a new specification in Java EE 6. What we need to do in this part of plugin equation is to provide these plugin classes to the CDI runtime. In Plummer, this happens in the PluginLoader class: public class PluginLoader implements Extension { protected static final String SERVICES_NAME = "com.steeplesoft.plummer.finders"; private static final Logger logger = Logger.getLogger(PluginLoader.class.getName()); private static List<PluginFinder> pluginFinders; List<Class<? extends PluginFinder>> pluginFinderClasses; public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd, BeanManager beanManager) { for (PluginFinder pluginFinder : getPluginFinders()) { try { for (Class<?> clazz : pluginFinder.getClasses()) { final AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(clazz); logger.log(Level.INFO, "Adding AnnotatedType for \{0}", annotatedType.toString()); bbd.addAnnotatedType(annotatedType); } } catch (Exception ex) { Logger.getLogger(PluginLoader.class.getName()).log(Level.SEVERE, null, ex); } } } // ... } Here we see CDI show up for the first time. What have here is a CDI portable extension (for more information, see the CDI RI (Weld) documentation). We also see another CDI concept that we’ll revisit in the next section, Events. Since we’re a portable extension, the class is loaded by the runtime very early in the process. In this case, our Extension observes the BeforeBeanDiscovery event, as you can see in the aptly-named method. This method asks the system for a list of the PluginFinder instances configured in the system (I got a little over-excited and added in the ability to have more than one, Just In Case). It then asks each PluginFinder for a list of the Classes it found. For each class, it creates an AnnotatedType, which it then adds to the BeforeBeanDiscovery class. When this method exits, the CDI runtime will, eventually, scan our plugin classes for CDI annotations, and, voila! our plugins are registered with the system. The bytecode loading is handled, in this case, by FilesystemPluginFinder. This class iterates over a list of jar files found in, by default, $HOME/.plugins. For each .class file in each jar, the bytes are read and the class is defined in the ContextClassLoader. We’ll not show how that happens here, but I will say that it seems to work pretty well. I’ve not found any issues with it so far, but I also have not been able to drive it very hard yet. When using this approach, it’s important to note some of its restrictions. Given how and when the classes are loaded, certain Java EE technologies are not available. Namely, this includes EJB, JMS, etc., as the related containers are unable to scan the classes for annotations. I have not tested JPA support yet. CDI seems to be completely and well supported. OSGi It seems that any discussion of plugins (or modules, if you will) would be incomplete without talking about OSGi. As I started thinking about this topic, Web Application Bundles came to mind pretty quickly. I will admit that I am far from an OSGi expert, but it seems that WABs aren’t quite what we want. In fact, they seem to be designed to solve different issues. WABs and Plummer are not mutually exclusive, however. In fact, I have very young, incomplete code in Plummer to allow a system to deliver plugins as OSGi bundles. Plummer assists in this by providing, in plummer-api, the PluginActivator class. This bundle activator runs, of course, when the bundle is started. You can look at the code for details, but it passes the Bundle to Plummer’s PluginTracker, which calls Bundle.findEntries() to find the class files in the bundle. The information is stored, and ultimately passed to the PluginLoader mentioned above. In terms of drawbacks, this one has the most severe of the approaches we’ve discussed. In addition to having the same limitations (most likely) as the manual class loading approach, it has one even more significant one: it does not currently work. :) I think the theory/approach is sound, but I have not had the chance to finish and test the code to date. For those interested, you know what to do. :) Problem #2: Application Design Now that we’ve answered any questions anyone would have — ever — about plugin loading, let’s spend some time on the more interesting part: how do I design the plugins. I would like to note that it’s probably not possible to write a complete, generally useful plugin system that works across applications, problem domains. If someone were determined enough to prove me wrong and actually did just that, I’d be willing to be that it would be difficult to use, heavy, etc. If this person were truly determined, gifted, etc. to prove me wrong yet again, well…​ good for him. :) For the rest of us (or, in this case, just me), Java EE makes this so easy that you really don’t need any extra frameworks. Specifically, we’ll take a look at JSF, CDI, and JAX-RS. View Extensibility Let’s start by taking a look at view extensibility, as, after all, even if you have the greatest plugin system in the world, if it can’t affect the view, then it’s pretty much worthless. To demonstrate this technique, we’re going to use JavaServer Faces, as it is the Java EE standard for web applications. You may prefer another framework, such as Spring MVC, Wicket, or GWT, or you may even be using desktop technologies such as Swing, SWT, or JavaFX to build views for your Java EE application. The technique here should work the same regardless of framework, more or less. You’ll just have to determine how to integrate into your technology of choice. For a plugin to add content to the view, it will have to provide what we on the GlassFish Console team ended up calling view fragments. These fragments are exactly what they sound like, small pieces of UI…​widgets that are added at specific points in the view. These fragments are categorized, by the plugin, into types, as defined by the consuming application. This means that the app might declare the types tab, treeNode, and widget. Aplugin, then, might add a tab to a configuration page, a treeNode to the navigation system, and a recent tweets widget to the sidebar. As we’ll see, how complex or simple the categorization/differentiaton exposed by the application is is completly up to you as the application author/architect. Having defined the terms, then, how might one implement this? First off, let’s take a look at ViewFragment.java in the plummer-api module: public @interface ViewFragment { String type(); String parent() default ""; } This simple interface defines type and parent properties. A plugin author would use it like this: public class SamplePlugin implements Plugin { @ViewFragment(type: "foo") public static String sample1 = "sample1.xhtml"; @Override public int getPriority() { return 500; } } There are several things to note here. First, let’s look at the annotation. Here, we are defining a ViewFragment of type foo. It is attached to a public static final String, whose value is sample.xhtml. When the system processes this annotation, it will store the value sample.xhtml in a Map, keyed by the value foo. When the view asks for view fragments of type foo, this piece of markup will be included. That file, by the way, is a simple JSF 2 Facelets file: <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:fragment xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <h1>Plugin Fragment</h1> This text comes from a fragment. Shiny! </ui:fragment> Very simple. The question that should come to mind now is, "How does the system find this annotation, and then how do I tell the system to insert this into my view?" The answer to the first half of that question is the Plugin interface. Those interested in the nitty gritty can read the code (PluginService.java in plummer-kernel), but for those not that curious, CDI again saves the day. In a nutshell, we ask CDI for all the beans that implement Plugin, scan them for fields annotated with ViewFragment, and store the metadata. On the view side, we use the pl:viewFragment custom component that Plummer offers: <pl:viewFragment type: "foo"/> The system does the rest. What you put in your view fragments is completely up to you. We’ve put everything from simple markup to `h:form`s with no known issues. One note with regard to resources: since the resources are stored in JARs and not in the application’s document root, you will need to use JSF 2’s resource mechanism to reference images, javascript, CSS, etc: <h:graphicImage value="#\{resource['myImage.JPG']}" height="200" title: "Here's a picture of something really cool!"/>" You can see a complete example of this in plummer-sample2. One final note before we move on: The code in Plummer is mostly standards-compliant, but some Mojarra-specific classes needed to be used get access to the FaceletFactory needed to insert the view fragments into the component tree. MyFaces users can still use Plummer, but someone will need to implement the MyFaces-specific code to reproduce this functionality. It would be great if the spec could expose this kind of functionality, but that would require someone to file a request and then, preferably, submit the spec prose and implementation code to make that happen, and I just haven’t had the time. ;) Application Extensibility The real work, of course, is done at lower levels. Here we’ll see just how simple Java EE makes things. Specifically, we’ll look at two parts of CDI, events, and what we’ll simply refer to as programmatic bean lookup. CDI events is, conceptually, just a simple pub/sub system. One part of the system fires, or publishes, events, and another observes (subscribes). This makes it very easy to loosely couple parts of the system: the core of your application need not worry about what, if anything handles, the event. It also easily allows multiple recipients to respond to the event fired. Again, the system doesn’t care. In Ron Popeil style, you just "set it and forget it". So what does this look like in practice? To demonstrate that in a meaningful way, we need a sample application, so we’ll write a very simple blogging system. If you’ve ever interacted with a blog, either as an author or a reader, you’ve likely seen the option by which a user can subscribe and get notifications of new posts. Let’s implement that. First up, we’ll need a way to create blog entries. You can find this BlogBean.java in the webapp, but here are the interesting parts: // ... @Inject private Event<BlogPostedEvent> blogPostedEvents; public String addEntry() { entries.add(entry); blogPostedEvents.fire(new BlogPostedEvent(entry)); entry = null; return null; } // ... For the sake of brevity here (too late, right?), you can find the view in examples/webapp/src/main/webapp/blog.xhtml. First, notice the @Inject. Here, we’re asking CDI to inject an Event that takes a BlogPostEvent payload. We use this in addEntry(), when we call blogPostedEvents.fire(new BlogPostedEvent(entry)). The code, simple as it is, should be pretty self-explanatory: we’re firing an event of type BlogPostedEvent, which looks like this: public class BlogPostedEvent { private String blogEntry; public BlogPostedEvent(String blogEntry) { this.blogEntry = blogEntry; } public String getBlogEntry() { return blogEntry; } } In this example, our payload is very simple. In a real world, this could be much more complex if your application’s needs warrant. Responding to this event is just as simple as firing it: public void sendEmail(@Observes BlogPostedEvent event) { emailService.sendEmail(event.getBlogEntry()); } That’s really all there is to it. By using CDI events, we are able to push data into our plugins in a loosely coupled manner. Again, in a real world application, the data push and the processing required to handle will likely be more complex, but the means of pushing it will not be. CDI for the win! Perhaps you need to allow a plugin to process data in the system. For example, in our system we want allow plugins to translate the blog entry into another language. To do so, we first need to define the interface by which the plugin will be called: public interface BlogEntryProcessor extends Serializable { String getName(); String process(String text); } From our blogging system, we can get a list of all of the BlogEntryProcessor instances, if any, with this CDI injection: @Inject @Translator Instance<BlogEntryProcessor> translators; This gives us an Instance instance that contains any BlogEntryProcessor`s defined in the system. We’ll come back to `@Translator in a bit. Next, we can provide a way for the user to pick a language with this code: <h:form> <h:selectOneMenu value="#\{blogBean.translator}" converter="#\{translatorConvertor}"> <f:ajax render=":entries" event="change" execute="@form"/> <f:selectItems value="#\{blogBean.translators}" var="t" itemLabel="#\{t.name}" /> </h:selectOneMenu> </h:form> and public List<BlogEntryProcessor> getTranslators() { List<BlogEntryProcessor> list = new ArrayList<BlogEntryProcessor>(); for (BlogEntryProcessor t : translators) { list.add(t); } return list; } This lets us change the language, but how do we get a default? Let’s define a Qualifier: @Qualifier @Retention(RetentionPolicy.RUNTIME) @Target(\{ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) public @interface English { } This simple class lets us differentiate at injection time: @Inject @English private BlogEntryProcessor translator; Instead of injecting Instance<BlogEntryProcessor>, we’re injecting a single..um…​instance. Since there might be more than BlogEntryProcessor on the system, we have to qualify which one we mean: @English @Singleton @Translator public class EnglishTranslator implements BlogEntryProcessor { // ... } EnglishTranslator is-a BlogEntryProcessor, and it has been marked as @English, which means this instance, which is also a singleton, will satisfy the injection above. We could have annotated this with @Default, both here and at the injection point, but the creation of a custom @Qualifier is a good exercise. :) But what’s up with that @Translator? That’s another @Qualifier, which must be applied to any BlogEntryProcessor that is intended to act as a translator (and which we document clearly in our system documentation, right? ;). Why is that important? In a simple system, we wouldn’t need that, but we’re going to intentionally muddy things a bit and introduce a different type of BlogEntryProcessor, one which allows for tags. One common type of plugin in systems like Wordpress allows a user to wrap certain text in a tag. This entry, for example, uses the code tag to get syntax highlighting. In our system, we’ll implement a tag that creates links to Google Maps. For example: Disneyland can be found at [map]1313 North Harbor Boulevard, Anaheim, CA[/map]. How is this implemented? Just like the translators: @Tag public class GoogleMapsProcessor implements BlogEntryProcessor { @Override public String getName() { return "Google Maps Processor"; } @Override public String process(String text) { Pattern pattern = Pattern.compile("\\[map\\](.*?)\\[\\/map\\]"); String replaceStr = "<a href=\\\"https://maps.google.com/maps?q=$1\\\">$1</a>"; Matcher matcher = pattern.matcher(text); String result = matcher.replaceAll(replaceStr); return result; } } This looks just like the translators, right? The only difference is the @Tag qualifier, whose source you can see in the bundle. In BlogBean, we access it and the translators in getEntries(): @Inject @Tag Instance<BlogEntryProcessor> tags; public List<String> getEntries() { List<String> list = new ArrayList<String>(); for (String text : entries) { for (BlogEntryProcessor tag : tags) { text = tag.process(text); } text = translator.process(text); list.add(text); } return list; } You can build and deploy the system to see this in action. Very simple, but very effective. REST Resources We’ve seen how to expose functionality to plugins loaded in the system, but what if we want to allow these plugins to expose this functionality to external clients, say, via REST? Again, Java EE makes this incredibly simple, using two specs in concert, CDI and JAX-RS. One of the ways one might configure a JAX-RS application is to provide a custom Application class, one which extends javax.ws.rs.core.Application. Plummer provides such an Application, so all Plummer users need do is configure it in the web application: <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>com.steeplesoft.plummer.kernel.rest.RestApplication</param-value> </init-param> </servlet> Oddly, note that the Application class is standardized, but the REST servlet is not (unlike, for example, JSF’s FacesServlet), so if you’re not using Jersey like we are here, then you’ll need to use the Servlet appropriate for your JAX-RS implementation. So how does RestApplication work? It uses CDI, but since it’s not handled by the CDI runtime, we can’t rely on injection. Instead, we’ll perform a manual look up of the BeanManager, a class provided by CDI’s excellent portable extension mechanism. We then query the BeanManager for our desired classes. But how do we identify our REST resources? Remember the Plugin marker interface? Plummer defines another marker, RestResource, to mark the JAX-RS resources we want to load, which are typical JAX-RS resources with the exception of this extra interface: @Path("myurl") public class PluginRestResource implements RestResource { @GET public String test(@QueryParam("text") String text) { return "You sent " + text; } } When the REST application is initialized, this class is loaded and exposed at /myurl as you would expect. Conclusion There are many, many plugin systems available for Java applications. It might be that one of these systems, modeled after or borrowed from, for example, Hudson or others, is the best choice for your application. I think that chances are good, though, that you need not resort to such a relatively complex system. The Java EE platform provides a rich set of APIs that will allow you to implement an domain-specific plugin system very simply, and with the introduction of another external dependency. ### [Writing Pluggable Java EE Applications](/2012/writing-pluggable-java-ee-applications/) I just finished giving my session at JAXConf San Francisco 2012, "Writing Plugged-In Java EE Apps". I think it went pretty well, though I guess I’ll find out how it really went when the reviews come in. :) Either way, I had a great time. As promised, here is a tar ball that includes the code we looked at during the session, as well as the accompanying slides. Hopefully I’ll be able to get this code put in a proper public repository (such as java.net or GitHub, or both) soon. For now, feel free to play with the code. Fix bugs. Extend it. Whatever comes to mind. :) If you make changes or use it in something, I’d love to hear about it. Thanks to all who attended! ### [Firefox, Linux, and the Java Plugin](/2012/firefox-linux-and-the-java-plugin/) In a perfect world, Firefox, Linux and the Java plugin would get along happily. You’d install all three, and things would just work. If memory serves, that’s exactly what happened under Ubuntu. However, after installing Fedora 17, it just didn’t want to work for me (I’m not blaming Fedora, mind you. I like to live on the bleeding edge, so I install Java 7 nightlies from tar balls and not RPMs, so I probably broke something along the way). After much fumbling and guessing, I finally found a solution, which I’ll share here in case you’re in the same boat: $ mkdir $HOME/.mozilla/plugins $ ln -s $PATH_TO_JRE/lib/amd64/libnpjp2.so $HOME/.mozilla/plugins/libnpjp2.so And restart Firefox. You can verify that Java (i.e., applets and webstart) is working by going here. ### [From OS X to Linux](/2012/from-os-x-to-linux/) When I joined Sun Microsystems "way back" in 2008, I was asked if I wanted a Mac for my work system. Having heard many extol the numerous virtues of the OS, I jumped at the chance. Since then, I’ve even migrated my wife and family to the OS. Trouble arose last fall, though, with the delivery of a new MacBook Pro (whose purchase was somewhat a miracle, brought about by the tireless efforts from my upper management). Simply put, I got a lemon. After five trips to the Apple Store, which resulted in overnight diagnostic runs; shipment to an offsite, more advanced repair facility; the replacement of the hard drive; and the replacement of the motherboard, I finally broke down and asked for a new machine, knowing it wouldn’t be a Mac. Just over a week ago, a new Lenovo Thinkpad arrived, and, after putting Linux on it, I have to say I’m generally very happy with the system.more In general, Apple puts together a very nice system in the MacBook Pro. The machine is a physical beauty, and the OS is veyr polished and user-friendly. As a developer, though, there were somethings that bothered me. The lack of any real visibility (that I could find) into the packaging system, the use of plists over conventional Unix configuration files, the odd command-line parameter parsing in the shell, the nearly universal requirement to use the mouse, the odd keyboard layout, etc. had been grating on me. Now I’l grant that many of these are silly or easily resolved, but they were different enough from years of habit-building that I never could get completely used to them, nor could I find workarounds that I really cared for. From a user experience, my complaints realy boil down to personal preferences. Many will likely read this list and think I’m quite a crank for my age, and that’s fine. We all have different preferences (I recently read a blurb about a Haskell developer — I forget his name — who prefers Windows!. Now that’s crazy, right? ;). At the end of the day, I had some minor quibbles with the OS, but I sucked it up and pressed on, and was generally pretty productive. Much more than I was on the Windows laptop at my last gig. Enter Linux. Or, I should say, re-enter Linux. I’ve been using Linux for many, many years now, so many of the annoyances I found when using OS X were the result of forming habits in that other Unix-like OS. On this new machine, I installed Linux Mint, which seems to the flavor of the day in some circles, and was mostly pleased. I had some odd issues with menus in NetBeans that seem to be GNOME-related, so I tried LXDE, which I found to be a bit…​ugly, and finally KDE, with which I had some stability issues. Over the course of part of an afternoon, then, I installed Ubuntu 12.04, since I had read that they fixed all the woes that at first plagued Unity. Surprisingly, I’m pretty happy with Unity. It has its issues, but the system is fast and stable, and lets me work the way I prefer, which is all I really wanted. Given my experience with this latest system, I doubt I’ll return to OS X in the near future. For me, Linux on the desktop is just about right. The price certainly is. ### [Java 7, NetBeans, Mac OS X, and a Little Bit of JavaFX 2](/2012/java-7-netbeans-mac-os-x-and-a-little-bit-of-javafx-2/) In a recent post showing how to use JavaFX 2 and NetBeans on the Mac, I noted that I have been unable to run NetBeans using Java 7 on my Mac for reasons I had not been able to figure out. Now, thanks to a pointer from Scott Kovatch, the technical lead at Oracle for the Mac OS X port of Java, I think I can show you how to do that. In case you missed it, here is his suggestion: The problem you’re seeing with Java 7 and text on the Mac is a known problem. If you are on a MacBook Pro a workaround is to turn off ‘Automatic graphics switching’ in the Energy Saver preference pane. We think we have a fix. It’s a simple enough fix that you probably won’t need screen shots, but I’ll do it anyway. :) First, open up your System Preferences and select "Energy Saver": Now uncheck "Automatic Grahpics Switching": In case you haven’t installed Java 7, you can grab it here. Once that’s downloaded, open the image and run the installer. This will install the JVM into /Library/Java/JavaVirtualMachines/1.7.0.jdk. Once that’s ready, you need to modify NetBeans to use the new JDK. The only way I’ve found to do this is to edit netbeans.conf: sudo vi /Applications/NetBeans\ 7.1.1.app/Contents/Resources/NetBeans/etc/netbeans.conf Your path may be slightly different, as I moved NetBeans out of the NetBeans folder the installer created, so you may have something like /Applications/NetBeans/NetBeans\ 7.1.1.app/Contents/Resources/NetBeans/etc/netbeans.conf. At about line 19 or so, you should something like this: #netbeans_jdkhome="/path/to/jdk" which I changed to this: netbeans_jdkhome=/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home Save that, then (re)start NetBeans. You can verify that you are running the correct JDK by opening the About window: From here, if you want to set things up for JavaFX work, just follow the steps in my last post, but point the Platform Home as well as the JavaFX SDK folder at your Java 7 installation folder, as the Mac OS X JDK previews now ship with JavaFX bundled. With that, you should be set. If you have any questions, leave a comment, and I’ll make some more swags to see if I can find you an answer. :) ### [Getting Started with JavaFX on the Mac](/2012/getting-started-with-javafx-on-the-mac/) image::javafx_logo_color_1-300x150.jpg As you may have guessed from my recent book review, I’ve been tinkering with JavaFX some, as time as permitted. I’ve been following the technology fairly closely since Sun announced the project way back in 2008. When it was announced that JavaFX 2.0 was finally available, albeit in preview form, for the Mac, I was ecstatic. I ran into issues, though, trying to get it to run in my IDE, though. After some guess work and googling, I finally figured it out. In retrospect, it may be obvious, but if you’re like me and are missing the obvious, I’m going to detail the steps I took to get it running on my Mac. Perhaps it can help someone out.more The first step, of course, is to download the binaries. You can do that here, sort of. Since this is still a preview release at the time of this writing, you have click the teeny tiny link under the header. Once you’ve downloaded the distribution, you need to extract it somewhere: $ unzip javafx_sdk-2_1_0-beta-b19-macosx-universal-27_mar_2012.zip -d $HOME/local/ You can, of course, put it anywhere you want, but you’ll need to adjust the following instructions. The next step is set up NetBeans. NetBeans has JavaFX support out of the box, assuming your JDK has JavaFX support. Since the Mac JDK does not yet, we need fix that. Otherwise, you’ll see this error: To fix this, we need to create a Java Platform with JavaFX support (I don’t know why we can’t modify the default platform, but we can’t, so we get to create a new one, which we can set to be the default if we want). To do that, go to Tools > Java Platforms, where you should see something like this: To create a new Java Platform, click the (wait for it…​!) "Add Platform…​" button in the lower left corner. OS X likes to put things in decidedly (to me) un-Unixy locations, and the JDK is no different. You can find the current JDK under /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents: We now need to give it a name, so we’ll call this "JDK 1.6 with JavaFX" and click OK. But wait, there’s no JavaFX support! To enable JavaFX support, we have to…​um..enable it. Doing so looks like this: We can now create a new JavaFX project: Your new project is ready to run. The even more adventurous may be wondering how one would do this with Java 7, to which I say, "Good question!" : ) I have mixed luck getting NetBeans and Java 7 to play nice on my Mac. It’s almost certainly pilot error, as I’ve done it before, as has Adam Bien, but I haven’t had a chance to debug things (e.g., the navigation tree under projects has all the tree icons, but no text. IIRC, the context menus are also text-less. Strange). At any rate, as I noted earlier, in retrospect, this seems pretty easy (if a bit unintuitive) and might be documented somewhere, but I couldn’t find it. Either way, it’s certainly documented now. I hope it helps. : ) ### [Book Review: Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology](/2012/book-review-pro-javafx-2-a-definitive-guide-to-rich-clients-with-java-technology/) I was privileged to be given a copy of the recently released Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology from Apress, authored by !/JavaFXpert">James Weaver, !/weiqigao">Weiqi Gao, !/steveonjava">Stephen Chin, !/deanriverson">Dean Iverson, Johan Vos. This review is a bit overdue, but I hope you find it as helpful as I found the book. For those looking for a quick summary, here it is: Overall, I thought it was a really good book that should get you up and running with JavaFX very quickly. Now, the details. As I said, I think this is a very solid technical book, which is hard thing to accomplish. Some books are really dry and overly technical, making them hard to read and reference, while others are fun to read, but shallow and not very helpful. This book, though, strikes a great balance, I think. There’s a wealth of knowledge, but I found it flows pretty well and doesn’t bog the user down in the super technical details. I do, though, read a fair number of these types of books, so maybe I’m numbed to that. Your mileage may vary. : ) Chapter 1, "Getting a Jump Start in JavaFX", might be the most important, as it introduces the technology to the user. Lose him here, and the rest of the book is worthless to him. The authors did a great job of working through a simple, yet functional application, hitting the high points. They didn’t spend a great deal of time on the details, but gave the reader enough to grasp kinda-sorta what’s going on. There is tons of source code and pictures, which is extremely helpful. You don’t have to go download the source and glance back and forth between the book and your computer. It’s literally all right there. Chapter 2 deals with "Creating a User Interface in JavaFX". The component library in JavaFX is large and growing, so the book can’t (and shouldn’t) cover all of them, this chapter hits some of the major ones, showing how to put them on the screen, lay them out, have them respond to events like mouse clicks, etc. Again, there is a lot of source code, giving the reader plenty of complete examples right the book to follow. Skipping a bit, Chapter 4 shows how to write (visually) scalable applications with no static positioning, while Chapter 5 returns to the topic of components, demonstrating a large number of the components and how to use them. Using these three chapters, I was able to get a non-functioning, but non-trivial UI mocked up in no time. Chapter 3 covers properties and bindings, two of the more fascinating aspects of the library, in my opinion. This one dives a bit deeper into the interfaces involved in the topics (including some UML for those that into that sort of thing), but still manages to be very readable. Like chapter 3, chapter 6 covers something not necessarily graphical, collections and concurrency. This chapter covers the new, rich collections API, while addressing the concurrency issues that are sure to arise in a modern, event-driven application. Chapter 7 spends considerable time on the charting features available in JavaFX, an important part of many business applications. The chapter has plenty of source and graphics to look at, and spends some time on styling the charts with CSS Chapter 8 shows the media control features in the JavaFX. In this chapter, the user is walked through building simple, yet functional audio and video players. This is very practical chapter, I think, giving interested parties a great starting point in making their media-capable applications. Chapter 9 seemed to me to take a very odd departure. What in the world do web services have to do with JavaFX? The answer is nothing, really, but what this chapter does, though, is provide a very practical, real world usage of the various JavaFX APIs, both UI and concurrency. We’re give great examples of ListCells, Services, TableViews, etc., and some more hands-on with JavaFX Property objects. I may have started the chapter confused, but I think in the end, this is one of my favorite chapters. Chapter 10 and Appendix A round out the book by describing some of the alternate languages available to JavaFX developers, namely, GroovyFX, ScalaFX, Visage, and FXML. While these chapters are really more about these other languages than JavaFX itself, I think those open to non-Java JVM languages will find a wealth of information here to help them pick a language. Or reinforce a choice they’ve already made. With all of that out of the way, if I had to say something bad about this book (and, I know, this will sound strange), I would say that maybe there’s too much code. The amount of source in a book is, I think, a pretty subjective question. When learning something, it’s great to have it all right there in front of you (the authors even include import statements, a rare, in my experience, but nice touch), but if you’re just needing a quick answer found somewhere in the prose of the book, it can obscure things a bit. Having said that, I don’t think they’ve done a bad thing here, as I like to see the code, but I can see someone being a bit put off by the multiple consecutive pages of code, so be forewarned. As I said at the beginning, I really enjoyed this book. As I find the time to work more with JavaFX, I think this will be my go-to tome to help me through my issues. Can you find all of this information online? Certainly, as is the case with every technical book, but the authors have done a great job of distilling all that information into a readable text, meaning you’ll spend less time on Google, and more time in your http://netbeans.org" title: ";)[IDE of choice]. If you’re interested in learning JavaFX, this book is well worth your money." ### [GlassFish 3.1.2, REST Security, and the Jersey Client](/2012/glassfish-3-1-2-rest-security-and-the-jersey-client/) I recently blogged about a change we made in GlassFish 3.1.2 with regard to REST security. Specifically, we added some CSRF protection (you can read the details here). For those of you using the Jersey Client, updating your code to support this change is very simple: import com.sun.jersey.api.client.filter.CsrfProtectionFilter; // ... Client client = new Client(); client.addFilter(new CsrfProtectionFilter()); // ... On the client side, that’s all you have to change. Jersey will take care of the details. Hat tip to Dan Allen for suggesting this post. :) ### [GlassFish 3.1.2 and REST Security](/2012/glassfish-3-1-2-and-rest-security/) As you may know by now, we released GlassFish 3.1.2 yesterday. Tim Quinn has a nice overview of some of the security-related changes, but one change he didn’t cover was one in the RESTful administration area, namely CSRF protection. I won’t go into the details of what CSRF attack is here, but I do want to show we’ve added protections to GlassFish to make sure the server is as secure as possible. For the curious, we implemented the CSRF protection using a filter provided by the Jersey team. As you can see from the javadoc, this change only affects requests that change state (POST, PUT, DELETE, etc). To update your client code, all you need to do is add the X-Requested-By header. Its value doesn’t matter: curl -X POST -H 'X-Requested-By: YeaGlassFish' -d key=value \ http://localhost:4848/management/domain/path/to/resource That’s all there is to it. It’s a very simple change, but an important one. If you run into any issues with this, please let us know! ### [Comparing JVM Web Frameworks - A Critique](/2012/comparing-jvm-web-frameworks-a-critique/) Recently, Matt Raible again presented his Comparing JVM Web Frameworks, this time at JFokus 2012. The intent of the presentation, as best as I can gather from half a world away, is to prevent some of the major JVM-based web frameworks, showing the various strengths and weaknesses, which will allow the audience to choose a framework more easily. While the goal is laudable, I’m just not sure how well executed the attempt was. Before I go any further, I should make some disclosures. The most important, probably, is my connection to JSF. I currently work for Oracle (and, of course, anything expressed on this blog is not necessarily shared by my employer, etc., etc. ; ), which I came to by way of Sun. JSF and GlassFish were my introduction to various Sun engineers and how I eventually came to work for Sun. I am a long time (and still current) user of JSF, I was a member of the JSF 2.0 Expert Group, and have worked on a handful of open source JSF projects (including Mojarra). I should also note that I neither know nor have ever met Matt Raible. I know next to nothing about him beyond what I read in blogs and slides. I have never had the opportunity to attend one of his presentations, and I have absolutely no interest in starting a flame war, assail him in anyway, etc. I’m just giving my feedback to his public comments/presentation, and trying to engage in the discussion presentations like this are meant to engender. : ) Whew! With that out of the way… How do you compare "JSF" and "MyFaces"? What do you mean by "JSF"? Mojarra? MyFaces Core? Caucho? IBM? What do you mean by "MyFaces"? MyFaces Core? MyFaces+Trinidad? MyFaces+CODI? What do you mean by Spring? Spring…um… core? Spring Security? Spring Social? How reliable are adoption numbers taken from polls at conferences? (Hint: I don’t think they are at all) How do you filter the jobs numbers to reflect only web frameworks and not ancillary add-ons? Why is your Wicket vs Seam data so old? Is there not a more current comparison? Why are you throwing Seam in as part of JSF, but using vanilla configurations of the other frameworks? I appreciate the intent of this presentation; I really do. I think it’s very helpful to have a good, honest look at the various frameworks, both as an end user and as an erstwhile framework developer. From just looking at the slides, though, I don’t know that this was a very effective or accurate execution of that. It may be true that the spoken part of the presentation has all the answers to the questions I’ve asked, but, as far as I know, that audio is not available. Furthermore, this seems to be the same presentation that has been given in times past, and I haven’t heard or seen anything from those occurrences that would give me any greater confidence in the fairness or accuracy of the information presented. Finally, I’m clearly a JSF fan. I know some will probably take this to a thin-skinned response to someone critiquing JSF, but it’s not. From a certain perspective, I really don’t care if you like or use JSF. There are a large number of us who do, and we continue to improve and refine the specification and implementations to make our jobs easier, and, yes, to appeal to new users. If you don’t like it and want to use something else, please feel free. My main problem with this presentation is that seems to use questionable and/or old data to make unfair comparisons and conclusions. I could be wrong, of course, but since this is my blog, I get to express my opinions. : P ### [CDI @OKCJUG](/2012/cdi-okcjug/) I had the opportunity today to present an introduction to CDI at the Oklahoma City Java Users Group. It was a smaller crowd, but they had great questions nonetheless. After a rough start in a workspace that wasn’t quite as clean as it should have been, I think the rest went fairly well. I had a good time at least. : ) Thanks to all those that came out and asked questions during and after. If you’d like to play with the code (WARNING: for those that weren’t there, these examples are 100% creativity-free :), you can download the project here. ### [A Jersey POJOMapping Client/Server Example](/2012/a-jersey-pojomapping-client-server-example/) JAX-RS is the specification that describes how to build RESTful interfaces in a Java EE environment. Jersey is the reference implementation of that spec, and, like many implementations, offers features above and beyond what spec does. One feature that I’ve been working with recently is the POJOMapping feature, which makes writing services and clients much easier, as well as typesafe. In a nutshell, what this feature allows you to do is deal with actual model classes in your service with little to no regard for their serialization and deserialization. That’s a huge boon, as dealing with XML and JSON isn’t always pretty, and really isn’t what we’re wanting to do with our service. To see how this works, we’ll develop a simple service and a client to interact with. First things first, we need some sort of model. Since I work on GlassFish, I’ve chosen something familiar to me, a Cluster. Here’s what our class might look like (Note: this is modeled roughly after GlassFish’s `ConfigBean ` of the same name): public class Cluster { private String name; private String configRef; private boolean gmsEnabled; private String broadcast = "udpmulticast"; private String gmsBindInterfaceAddress; private String gmsMulticastAddress; private int gmsMulticastPort; private Date modified = new Date(); // getters, setters, and toString() not shown } It’s a POJO in every sense of the word, so it’s pretty boring. Let’s move quickly, then, to our service: @Path("/cluster") public class ClusterResource { private static Map<String, Cluster> clusters = new HashMap<String, Cluster>(); public ClusterResource() { clusters.put("c1", new Cluster("c1")); clusters.put("c2", new Cluster("c2")); } @GET public Map<String, Cluster> getClusters() { return clusters; } @POST public Response addCluster(Cluster newCluster) { Response response; if (clusters.containsKey(newCluster.getName())) { response = Response.status(Response.Status.BAD_REQUEST) .entity("That cluster already exists") .build(); } else { clusters.put(newCluster.getName(), newCluster); response = Response.ok().build(); } return response; } @GET @Path("\{name}") public Cluster getCluster(@PathParam("name") String name) { return clusters.get(name); } @POST @Path("\{name}") public Response updateCluster(Cluster c) { c.setModified(new Date()); clusters.put(c.getName(), c); Response response = Response.ok(c).build(); return response; } @DELETE @Path("\{name}") public Response deleteCluster(@PathParam("name") String name) { clusters.remove(name); return Response.ok().build(); } } This is a very basic JAX-RS resource. So far, there’s nothing much new. Some JAX-RS users might now turn to writing one or more `MessageBodyWriter `s to handle the serialization of the `Cluster ` instances to JSON, XML, etc., but we’re not. In fact, we’re mostly done on the server-side. All we have left to do is to enable Jersey’s `POJOMapping ` feature. In our example, we’ll do that via `web.xml `: <?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <servlet> <servlet-name>jersey-serlvet</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <init-param> <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey-serlvet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> We’re ready to write a client now to see if we did things correctly. For that, we’ll write just a simple command-line Java application: public class RestClient { protected Client client; protected ObjectMapper mapper = new ObjectMapper(); protected WebResource webResource; public RestClient() { ClientConfig clientConfig = new DefaultClientConfig(); clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); client = Client.create(clientConfig); webResource = client.resource("http://localhost:8080/rest-service"); } public Cluster getCluster(String name) { return webResource .path("cluster") .path(name) .accept(MediaType.APPLICATION_JSON) .get(Cluster.class); } public ClientResponse createCluster (Cluster cluster) { return webResource.path("cluster") .type(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .post(ClientResponse.class, cluster); } public Cluster saveCluster(Cluster cluster) { ClientResponse cr = webResource.path("cluster") .path(cluster.getName()) .type(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .post(ClientResponse.class, cluster); return cr.getEntity(Cluster.class); } public ClientResponse deleteCluster(Cluster cluster) { return webResource.path("cluster") .path(cluster.getName()) .type(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .delete(ClientResponse.class); } public Map<String, Cluster> getClusters() { try { String json = webResource .path("cluster") .accept(MediaType.APPLICATION_JSON) .get(String.class); return mapper.readValue(json, new TypeReference<Map<String, Cluster>>() {}); } catch (IOException e) { } return new HashMap<String, Cluster>(); } public void run() { Cluster cluster = getCluster("c1"); assert (cluster.getName().equals("c1")); Map<String, Cluster> clusters = getClusters(); System.out.println("Number of clusters: " + clusters.size()); try { Thread.sleep(2000); } catch (InterruptedException e) { } cluster.setGmsMulticastPort(1234); saveCluster(cluster); clusters = getClusters(); System.out.println("Original time: " + cluster.getModified()); System.out.println("New time: " + clusters.get("c1").getModified()); Cluster newCluster = new Cluster("newCluster"); ClientResponse cr = createCluster(newCluster); int status = cr.getStatus(); if ((status >= 200) && (status <= 299)) { System.out.println("Cluster created."); } else { System.out.println("Cluster creation failed: " + cr.getEntity(String.class)); } System.out.println("List of clusters after create: " + getClusters()); deleteCluster(newCluster); System.out.println("List of clusters after delete: " + getClusters()); } public static void main(String... args) throws IOException { RestClient rc = new RestClient(); rc.run(); } } Note in the constructor, we pass a `ClientConfig ` instance to the `Client ` constructor so that we can enable `POJOMapping ` in the client. The rest is pretty basic Jersey Client code. For the endpoints that return a specific `Cluster ` instance, we can simply ask the `Client ` for `Cluster.class `. For the endpoint that returns all of the `Cluster `s, which we’ve modeled here as `Map<String, Cluster> ` (one might argue that this method is poorly designed, and you might be right, but the point of this exercise is to look at the POJOMapping feature, not, necessarily, to craft the world’s best REST resource : ), we have to do a little more work. If we ask the Client for a Map (i.e., `cr.getEntity(Map.class) `), Jersey will happily return that, but the type of the values in the `Map ` will be `LinkedHashMap `, not Cluster as we are wanting. To work around that, we ask the `Client ` for a `String `, which we then explicitly deserialize using the Jackson library, which is what Jersey itself uses: `mapper.readValue(json, new TypeReference<Map<String, Cluster>>() {}); `. If you run the client, you should get output like this: Number of clusters: 2 Original time: Thu Jan 26 07:47:22 CST 2012 New time: Thu Jan 26 07:47:24 CST 2012 Cluster created. List of clusters after create: \{newCluster=Cluster\{name='newCluster', configRef='null', \ gmsEnabled=false, broadcast='udpmulticast', gmsBindInterfaceAddress='null', \ gmsMulticastAddress='null', gmsMulticastPort=0, modified=Thu Jan 26 07:47:24 CST 2012}, \ c1=Cluster\{name='c1', configRef='null', gmsEnabled=false, broadcast='udpmulticast', \ gmsBindInterfaceAddress='null', gmsMulticastAddress='null', gmsMulticastPort=0, \ modified=Thu Jan 26 07:47:24 CST 2012}, c2=Cluster\{name='c2', configRef='null', \ gmsEnabled=false, broadcast='udpmulticast', gmsBindInterfaceAddress='null', \ gmsMulticastAddress='null', gmsMulticastPort=0, modified=Thu Jan 26 07:47:24 CST 2012}} List of clusters after delete: \{c1=Cluster\{name='c1', configRef='null', gmsEnabled=false, \ broadcast='udpmulticast', gmsBindInterfaceAddress='null', gmsMulticastAddress='null', \ gmsMulticastPort=0, modified=Thu Jan 26 07:47:24 CST 2012}, c2=Cluster\{name='c2', \ configRef='null', gmsEnabled=false, broadcast='udpmulticast', gmsBindInterfaceAddress='null', \ gmsMulticastAddress='null', gmsMulticastPort=0, modified=Thu Jan 26 07:47:24 CST 2012}} Note that the serialization/deserialization works both ways (getting FROM the server and posting TO the server). It’s all handled automagically. Having written and maintained several `MessageBodyWriter `s and `MessageBodyReader `s, I find this simplicity immensely appealing. I would imagine that for most basic resources, this should work really well. I’m not sure yet how this will scale up, if you will, with more complex resources, but I intend to find out. Either way, it’s definitely a great tool to have at hand. Source code for this project can be found here. ### [Grabbing Screenshots of Failed Selenium Tests](/2012/grabbing-screenshots-of-failed-selenium-tests/) For the GlassFish Administration Console, we have quite a few tests (about 133 at last count). Given the nature and architecture of the application, we’ve chosen Selenium to drive our tests. One of the problems we’ve faced, though, is understanding why a test failed due to the length of time the tests take (roughly 1.5 hours to run the whole suite). Sometimes, we can look at the log and know exactly what failed, but not the why. Did the screen render correctly? Did, perhaps, the click, etc. not get performed (we’ve seen instances of that) leaving the application in a state not expected by the test? Since I usually start the tests and move on to something else, we had no way of knowing. Until now. I finally sat down and figured out how to grab a screen shot when a test fails. I’ve distilled that technique down to its essentials, which I’ll share here. In this example, we’re going make sure example.com works correctly. Sort of. : ) What we need to do first, though, is set up our project, which we’ll configure (for simplicity’s sake) as a simple Maven-based Java application. The important pom.xml elements are these: <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-server</artifactId> <version>2.14.0</version> <exclusions> <exclusion> <groupId>org.testng</groupId> <artifactId>testng</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> <showDeprecation>true</showDeprecation> </configuration> </plugin> </plugins> </build> Simple enough. Now, the test: public class ScreenshotDemoTest { private static WebDriver driver; private static Selenium selenium; @Rule public ScreenshotTestRule screenshotTestRule = new ScreenshotTestRule(); @BeforeClass public static void beforeClass() { driver = new FirefoxDriver(); selenium = new WebDriverBackedSelenium(driver, "http://example.com"); } @AfterClass public static void afterClass() { selenium.close(); } @Test public void testThatSucceeds() { selenium.open("/"); assertTrue(selenium.isTextPresent("As described")); } @Test public void testThatFails() { selenium.open("/"); assertTrue(selenium.isTextPresent("Your test should fail here")); } } This is an extremely simple test that should make sense to those familiar with Selenium. The interesting part here is lines 4 and 5. What’s that Rule? That little nugget is a means of extending JUnit in an AOP fashion. In our case, that’s where the magic is going to happen, so let’s take a look at ScreenshotTestRule: class ScreenshotTestRule implements MethodRule { public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) { return new Statement() { @Override public void evaluate() throws Throwable { try { statement.evaluate(); } catch (Throwable t) { captureScreenshot(frameworkMethod.getName()); throw t; // rethrow to allow the failure to be reported to JUnit } } public void captureScreenshot(String fileName) { try { new File("target/surefire-reports/").mkdirs(); // Insure directory is there FileOutputStream out = new FileOutputStream("target/surefire-reports/screenshot-" + fileName + ".png"); out.write(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES)); out.close(); } catch (Exception e) { // No need to crash the tests if the screenshot fails } } }; } } Implementations of MethodRule act as an interceptor for your tests. You can do all the usual types of things you might do in an interceptor (in fact, in GlassFish, we use this is allow us to run only specific test methods, e.g., mvn -Dtest=MyTest -Dmethod=testMethod1,testMethod3). Here, though, we want to run every test, but, in the case of failures, which present themselves as Exceptions, we wan’t to capture the screenshot. Once we’ve saved the image to a file (note the assumption that we’re running under Maven in captureScreenshot()), we rethrow the Throwable to make sure the failure is reported. If you run these tests, you should see one success and one failure, and you should see target/surefire-reports/screenshot-testThatFails.png. How easy was that?! :) The full source code can be found here. I hope this helps you as much as it has me. :) ### [Merry Christmas](/2011/merry-christmas/) Merry Christmas I hope everyone who happens to find this site this Christmas season has a very special and blessed time with friends and family. On this geek blog, I think it appropriate to leave you all with a retelling of the Christmas story…​through Facebook. God bless! ### [Testing Android Applications with Maven, Android-x86 and VirtualBox](/2011/testing-android-applications-with-maven-android-x86-and-virtualbox/) Testing Android Applications with Maven, Android-x86 and VirtualBox For a few months now, I’ve been working on a small application called Cub Tracker which is designed to help Cub Scout den and pack leaders track the progress of the scouts assigned them. I’m a big fan of testing, so I’ve done my best to follow TDD as I’ve worked on the app. Early on, it became clear that I needed a better way to test, as the official Android app is slow and unreliable at times. Via Twitter, I was turned on to Android-x86 and after a couple nights of hacking, I think I have a usable installation of Android-x86 under VirtualBox that has sped up my testing considerably. In this article, I’ll show you how I did it. First up, let me clarify something, namely, my claim that the Android emulator is unreliable. Unless I’m just really unlucky or doing something really wrong, sometimes the emulator comes up, for lack of a better term, in a funky state. I can unlock the screen, interact with the "device" etc., but adb doesn’t see the emulator, so I can’t deploy my app (e.g., adb logcat sits waiting for the device to come online forever). Usually, killing the zombie emulator and starting a new one solves the problem, but that type of manual interaction doesn’t work under CI. With what little experience I’ve had with Android-x86 and VirtualBox, that doesn’t seem to be a problem anymore. The device starts up quickly and is almost immediately ready to use. So how does one set up a VM for this? While there are probably a myriad of ways, I’ll give you two. You can follow these instructions, or you can download this VirtualBox appliance I exported. The appliance has the lock screen disabled, and the ethernet configuration set to a static IP, so, assuming the IP works on your network, you can just import the appliance and start using it. For those that want to build your own VM, once you’ve finished the instructions linked above, I would suggest setting a static IP (Menu → Settings → Ethernet Configuration) and disabling the lock screen (Menu → Settings → Location & security → Set up screen lock). *A quick note on navigating in the emulator*: To go back, you press ESC. To emulate menu keypresses, etc, click on the clock in the status bar. After a moment or two, it will tell you that "you can touch the menu bar to do the function of menu now". Once that’s displayed, click on the status bar will go Home, and click and swiping right will emulate a Menu press. So now, one way or another, you have your VM setup, but how do you integrate that with your tests? While Maven’s XML doesn’t make it easy, judicious as of antrun saves the day. Here’s a sample POM: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <groupId>com.example.application</groupId> <artifactId>application-parent</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>test-suite</artifactId> <packaging>apk</packaging> <name>My Test Suite</name> <dependencies> <dependency> <groupId>com.google.android</groupId> <artifactId>android</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.google.android</groupId> <artifactId>android-test</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>application</artifactId> <version>$\{project.version}</version> <type>apk</type> </dependency> <dependency> <groupId>$\{project.groupId}</groupId> <artifactId>application</artifactId> <version>$\{project.version}</version> <scope>provided</scope> <type>jar</type> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.7</version> <executions> <execution> <id>startvb</id> <phase>prepare-package</phase> <configuration> <target> <echo>***** Starting VirtualBox</echo> <exec executable="adb"> <arg value="kill-server"/> </exec> <exec executable="VBoxManage"> <arg value="startvm"/> <arg value="Android"/> </exec> <waitfor maxwait="3" maxwaitunit="minute"> <and> <socket server="192.168.1.200" port="5555"/> </and> </waitfor> <exec executable="adb"> <arg value="connect"/> <arg value="192.168.1.200"/> </exec> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> <execution> <id>stopvb</id> <phase>verify</phase> <configuration> <target> <echo>***** Stopping VirtualBox</echo> <exec executable="VBoxManage"> <arg value="controlvm"/> <arg value="Android"/> <arg value="poweroff"/> </exec> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <sdk> <platform>8</platform> </sdk> <undeployBeforeDeploy>true</undeployBeforeDeploy> <enableIntegrationTest>true</enableIntegrationTest> </configuration> </plugin> </plugins> </build> </project> Scroll down to about line 40 or so. Here, there’s an antrun execution block that starts the VirtualBox VM. In my case, it’s called "Android", so you’ll want to change that as appropriate. Ideally, that would be a property so that you can target different VMs for different Android versions. I’ll leave that as an exercise for the reader. : ) First up, we kill the adb server. This might be overkill (no pun intended. Honest! : ), but I’ve had issues where adb was certain it was already connected to the device in situations where I run the tests over and over. Next, we start the VM, and then we wait for it to listen on port 5555. The startvm command finishes pretty quickly, but that doesn’t mean we’re ready to deploy our test app yet, so wait. Finally, we tell adb to connect to our VM. From there, it’s the standard Maven Android Plugin.After our tests are done, we tell VirtualBox to shut down our VM. Sharp-eyed readers have probably noted a dependency listed twice, that of the application to test. That oddity is, as best as I can tell, to allow the test application to compile (via the Jar dependency) and to tell the Maven plugin what application archive to deploy (via the apk dependency) so that the tests have something to run against. The setup isn’t perfect, sadly. For example, if a test fails, the VM isn’t torn down (it’s likely just a poor choice of Maven phase), and, ideally, those hard-coded values would be properties. It does, however, seem to work fairly well for manual runs, so while there may still be lingering issues preventing unattended runs under, say, Hudson, this feels like a good step in the right direction. The best part is that this can easily be imported into NetBeans or IDEA thanks to their great Maven support (read as: Eclipse is no longer required. : ) Give that a whirl and let me know what you think. If you find a way to improve it, I’d love to hear about! ### [Book Review: Real World Java EE Night Hacks - Dissecting the Business Tier](/2011/book-review-real-world-java-ee-night-hacks-dissecting-the-business-tier/) Book Review: Real World Java EE Night Hacks - Dissecting the Business Tier Last week, a great post by Adam Bien brought his latest book, Real World Java EE Night Hacks - Dissecting the Business Tier, to mind. I have since gotten myself a copy and thought I’d share my thoughts here. For starters, this is a very different kind of book. In the foreword, James Gosling describes it this way (and I’ll just quote the whole thing : ) : Most books for software developers are horizontal slices through some piece of the technological landscape. !“X for Dummies” or “Everything you need to know about X.” !Breadth and lots of toy examples. !This book takes a largely orthogonal approach, taking a vertical slice through a stack of technologies to get something very real done. !Adam takes as his organizing principle one real Java EE application that is not a toy, and goes through it, almost line-by-line explaining what it does, and why. !In many ways, it feels like John Lions’, Lions’ classic Commentary on UNIX 6th Edition. One of the problems that people often have when they start looking at Java is that they get overwhelmed by the vast expanse of facilities available. !Most of the APIs have the interesting property that the solution to any task tends to be pretty simple. !The complexity is in finding that simple path. !Adam’s book shows a path to a solution for the problem he was trying to solve. !You can treat it as an inspiration to find your own simple path to whatever problem you have at hand, and guidance on how various pieces fit together…​ — James Gosling Rather than telling the user everything he needs to know about Java EE, Adam walks the user through the process of building a real world piece of software in a blow-by-blow account. I think that’s really what makes this shine. The application is one called x-ray, a "[s]tatistics and analytics Java EE 6 software for blogs (tested with roller) and webapps." As the "domain expert, operator, quality assurance department, architect, tester, and developer all in one person", Adam starts the book by describing the scenario at hand (in a nutshell, gathering blog statistics in real-time without affecting the performance and availability of the blog itself). He does a great job upfront of describing the functional and non-functional requirements so the reader knows where he’s heading. With the high-level details spelled out, he jumps into coding. One of the things I really liked about the text is that we get to see what works and what doesn’t. At the start of the text (and I’ll let you get the details from the book itself ; ), he tries one approach, finds that it doesn’t work, explains why, then tries another tack, and we get to see it all happen. Sometimes we can learn as much from failure/adversity (ours or someone else’s), so I’m glad he included this part. After pretty well-documented trial and error in the overall architecture of the software, he finally identifies an approach that should work and beings giving the implementation details. In the process, he shows practical examples of EJB 3.1, REST, CDI, and JPA, all working together. In places where he could use one technology or another (e.g., EJB 3.1 or CDI, or REST vs SOAP), he explains why he chose the one he did, which is a helpful insight for those new to the technology. By the end of the book, the reader should have a pretty good handle on how the software works, as well as why it was written the way it was. The reader won’t come away with a complete understanding of all of the Java EE technologies used, though, but that’s not the intent of the work. It strikes me as more of an extended mentoring engagement in written form, and I think it does a great job at that. As a musician (bass guitar, for the curious :), one of the ways I learn to play better is by watching other musicians, listening to them talk about their music, trying to play their lines, etc. The same approach can (and should be) applied in the software world. As best as I can tell, Adam Bien’s is one the most recognized and respected names in the Java EE environment (especially in GlassFish circles), making him a great choice to watch and learn from. Anyone dizzied from the storm of acronyms in the Java EE will be well-served to pick up this book (lots of links to do so here). ### [Funky Object Initialization](/2011/funky-object-initialization/) Funky Object Initialization I’ve been using a technique a lot, recently, for initializing an object a bit more succinctly. It looks pretty odd, I’ll admit, enough so that it really caught a coworker of mine off guard. If you’ve been reading my recent REST posts, you’ve seen this a few times. I like it a lot, so I thought I’d a take a quick look at it. Here’s the technique in question: Map<String, Object> map = new HashMap<String, Object>() {{ put("foo", "abc"); put("bar", "123"); }}; I’m not a language geek by any reasonable stretch of the imagination, so I can’t see in definitive (or maybe even accurate) terms what’s going on here, but it seems to me to be very much like the instantiation of an anonymous inner class. We’ve all seen those: Thread t = new Thread(name) { @Override public void run() { // foo } } Nothing unusual there. What makes this so interesting is (if my educated guess is correct) is the static initializer block we’ve declared ({ put…​; put…​;}). Technically, I think we’re subclassing HashMap and specifying a static initializer. Technicalities aside, what this does is allow us to execute initialization code in the context of the newly created object before it’s returned to the enclosing code. What I like about this is that it makes the code much more concise, and can be collapsed in IDEs and editors that support such things. It also allows me to create a Map (or List or Set or Foo or…​) and initialize it inside a method call: someObject.someMethodThatTakesAList(new List<String>() {{ add("foo"); add("bar"); }}); That’s some fancy kung fu. :) I didn’t invent or discover this technique, but I’ve found it to be extremely useful. Now that you have it in your toolbox, maybe you will too. ### [GlassFish REST Client - ComplexExample.java](/2011/glassfish-rest-client-complexexample-java/) GlassFish REST Client - ComplexExample.java In a series of recent posts, I’ve shown off what the GlassFish 4.0 REST client wrappers should look like, giving simple examples of using the wrappers using both Java and Python, the two currently supported languages. In this post, we’ll take a look at a more complex example, that of setting up clusters and standalone instances, deploying an app, then cleaning up after ourselves. Let’s jump right in. In this fairly contrived scenario, we’re going to create one cluster, c1, with two nodes, c1in1 and c1in2, as well as two standalone instances, in1 and in2. In a real world situation, we might be deploying a single app to three different customer environments, for example. Once the cluster and instances are created, we’ll deploy the app, and then create application references on each of the instances. This is GlassFish’s way of deploying the same application to multiple targets. We could, of course, deploy the war multiple times, but that would result in the war file being deployed several times. There’s nothing inherently wrong with either approach. We’re just going to go with the former. Enough with that, then, let’s get to the code. Hopefully, if you’ve been following along, this should be pretty straightforward and easy to read. public class ClusterDemo { RestClient rc = new RestClient(); Domain domain = new Domain(rc); public void run() { createCluster(); createStandaloneInstances(); deployApplication(); testApplication(); undeployApplication(); removeStandaloneInstance(); removeCluster(); } private void createCluster() { deleteCluster("c1"); RestResponse rr = domain.getClusters().createCluster("c1"); rr = domain.createInstance("localhost-domain1", "c1in1", new HashMap<String, Object>() {{ put("cluster", "c1"); put("portbase", "10000"); }}); rr = domain.createInstance("localhost-domain1", "c1in2", new HashMap<String, Object>() {{ put("cluster", "c1"); put("portbase", "11000"); }}); } private void createStandaloneInstances() { deleteInstance("in1"); deleteInstance("in2"); RestResponse rr = domain.createInstance("localhost-domain1", "in1", new HashMap<String, Object>() {{ put("portbase", "12000"); }}); rr = domain.createInstance("localhost-domain1", "in2", new HashMap<String, Object>() {{ put("portbase", "13000"); }}); } private void deployApplication() { Application app = domain.getApplications().getApplication("test"); if (app != null) { app.delete(); } RestResponse rr = domain.getApplications().deploy(new File("test.war"), new HashMap<String, Object>() {{ put("target", "c1"); }}); rr = domain.getServers().getServer("in1").createApplicationRef("test"); rr = domain.getServers().getServer("in2").createApplicationRef("test"); } private void testApplication() { // An exercise for the reader } private void undeployApplication() { RestResponse rr = domain.getServers().getServer("in1").deleteApplicationRef("test"); rr = domain.getServers().getServer("in2").deleteApplicationRef("test"); rr = domain.getClusters().getCluster("c1").deleteApplicationRef("test"); rr = domain.getApplications().undeploy("test"); } private void removeStandaloneInstance() { deleteInstance("in1"); deleteInstance("in2"); } private void removeCluster() { deleteCluster("c1"); } private void deleteCluster(final String clusterName) { RestResponse rr = domain.listInstances(new HashMap<String, Object>() {{ put("id", clusterName); }}); List<Map> instanceList = (List<Map>) rr.getExtraProperties().get("instanceList"); if (instanceList != null && !instanceList.isEmpty()) { for (Map instance : instanceList) { String instanceName = (String) instance.get("name"); Server server = domain.getServers().getServer(instanceName); server.stopInstance(instanceName); server.delete(); } } Cluster cluster = domain.getClusters().getCluster(clusterName); if (cluster != null) { if (cluster.delete()) { System.out.println("Successfully deleted instance " + clusterName); } else { System.out.println("Failed to delete instance " + clusterName); } } } private void deleteInstance(String name) { Server server = domain.getServers().getServer(name); if (server != null) { if (server.delete()) { System.out.println("Successfully deleted instance " + name); } else { System.out.println("Failed to delete instance " + name); } } } public static void main(String... args) { ClusterDemo cd = new ClusterDemo(); cd.run(); } } There’s not much to say about the code beyond what I said in the intro. I should note, though, that I removed some error checking to try to make this a bit shorter. Typically, after each REST call, I would have assert (rr.isSuccess()); just to make sure. In production code, you would need something similar (though, obviously, more robust). If you have any questions about the code, please feel free to ask questions in the comments section. I’ll try to get the Python version posted as soon as I can. If there’s anything in particular you’d like to see me address about these client wrappers or the GlassFish REST interface in general, you know where to ask. ;) ### [GlassFish REST Client Goes to the Flying Circus](/2011/glassfish-rest-client-goes-to-the-flying-circus/) GlassFish REST Client Goes to the Flying Circus It happened a bit more quickly than I had planned, and, yes, I know that’s a pretty bad Python joke, but, as promised, I just committed code to add support for generating Python REST clients to the GlassFish RESTful Administration interface. Let’s take a quick look at it. One easy egg to crack! Generating the python client looks strangely similar to how it’s done for java: asadmin generate-rest-client --languages python --outputdir tmp After that is complete, you’ll have a Python egg in tmp/ that you can then install into your Python environment: sudo easy_install tmp/glassfish-rest-client-stubs.zip If you want both the Java and Python stubs, the command line would look like this: asadmin generate-rest-client --languages java,python --outputdir tmp Great! How do I use it? To show how similar the clients are, I’m going to implement here, in Python, the same examples I gave in my last post. First up, then, is creating a JDBC connection pool: from glassfish.rest import * restClient = RestClient() domain = restClient.getDomain() resources = domain.getResources(); cp = resources.getJdbcConnectionPool("TestPool") if cp: # The get method will return null if the requested resource does not exist cp.delete() rr = resources.createJdbcConnectionPool("TestPool", { "restype": "javax.sql.XADataSource", "datasourceclassname": "org.apache.derby.jdbc.ClientDataSource", "property": "portNumber=1527:password=APP:user=APP:serverName=localhost:databaseName=sun-appserv-samples" }) print "Success!" if rr.isSuccess() else ("Failure: " + rr.getMessage()) Easy! Now let’s deploy an application: from glassfish.rest import * restClient = RestClient() domain = restClient.getDomain() rr = domain.getApplications().deploy(open("test.war"), {'force':True}) print "Success!" if rr.isSuccess() else ("Failure: " + rr.getMessage()) Undeploying is just as easy: app = domain.getApplications().getApplication("test") if app: app.delete(); Final Word In theory, the Python API should look just like the Java API. The goal is to provide, as nearly as possible, identical experiences with the client API, regardless of the target language. That certainly opens the door to complaints that this code isn’t as "pythonic" as it should (which may or may not be the case. I’m not good enough with Python to tell you one way or the other ; ). It also means that any API warts the Java version has will be present in the other languages. The goal, then, is to fix whatever issues the Java version may have and let that trickle down to the other language(s). That means that if you have any issues, now’s the time to speak. Good or bad, I’d love to hear your thoughts. ### [GlassFish REST Interface, a Client-side Perspective](/2011/glassfish-rest-interface-a-client-side-perspective/) GlassFish REST Interface, a Client-side Perspective As I’ve covered here before, GlassFish sports (and has for a while now), a pretty comprehensive set of management and monitoring REST endpoints. While this goes a long way toward opening up GlassFish management to various scripting solutions, the client side is still pretty manual. One my goals in GlassFish 4.0 is to fix that. In this article, I’m going to give you a sneak peak into what we on the REST team have planned for the GlassFish RESTful administration interface. So, What’s New? Currently, interacting with the REST interface means JSON or XML. Lots and lots of it. We do ship some utility methods to help with that (though I won’t discuss them here, as they’re not technically public APIs at this point) and I’ve heard of GlassFish users doing the same. What would be nice, though, is to avoid that as much as possible. What we plan to deliver, then, is a set of Java classes that wrap all the complexities of JSON/XML, the Jersey client, etc. We can generate these stubs (see note below) by using this command: asadmin generate-rest-client --outputdir client/ Currently, this will create 3 files in the directory client/: pom.xml, rest-client-4.0.jar, and rest-client-sources-4.0.jar. Internally, this command analyzes all of the ConfigBeans and AdminCommands deployed to GlassFish, creates the source files for the clients, compiles it, and returns the binary and source jars for the client, as well as a POM file that developers can use to install the jars into a local Maven repository. Note: All of this code is still pretty new, so file names, etc. may change. I’m still not happy with the CLI command name or the name of the resulting artifacts, for example. Great! How do I use it? For those familiar with GlassFish internals, these classes largely mimic the public interfaces of the `ConfigBean`s they represent. There are additional methods exposed to make available the CLI commands that GlassFish exposes via REST. With that out of the way, perhaps the best way to explain how to use the library is to show a couple of examples. We’ll start with a simple example, creating a JDBC connection pool: RestClient restClient = new RestClient("localhost", 4848, false /* use ssl? */); Domain domain = new Domain(restClient); final Resources resources = domain.getResources(); JdbcConnectionPool cp = resources.getJdbcConnectionPool("TestPool"); if (cp != null) { // The get method will return null if the requested resource does not exist cp.delete(); } RestResponse rr = resources.createJdbcConnectionPool("TestPool", new HashMap<String, Object>() {{ put("restype", "javax.sql.XADataSource"); put("datasourceclassname", "org.apache.derby.jdbc.ClientDataSource"); put("property", "portNumber=1527:password=APP:user=APP:serverName=localhost:databaseName=sun-appserv-samples"); }}); if (rr.isSuccess()) { System.out.println("Successfully created connection pool."); } else { System.out.println("There was an error while creating the connection pool: " + rr.getMessage()); } This simple example does several things. First, we create the base RestClient. We tell the constructor that our server is on localhost, listens on port 4848, and does not use SSL. Next, we create a Domain object, which is, of course, the root node for all configuration data in the GlassFish server. From here, we have methods exposed that allow the client code to walk down the REST tree you’ve come to expect if you’ve used the REST interface before. With a reference to the Resources, we have access to the createJdbcConnectionPool method. One thing to note about CLI command wrapper methods, is that all required parameters are explicitly listed, by name and type, in the method signature. All optional parameters are passed in a Map<String, Object>, as shown above. Calls to CLI endpoint methods return a RestResponse object, which wraps all of the complexities of the REST response payload. In fact, you don’t even need to care if you’re using JSON or XML (<whisper>It’s currently using JSON ; )</whisper>). There are several methods on this class, but all we care about here is whether or not we’ve succeeded (.isSuccess()), and what message was returned if there was a failure (.getMessage()). That’s fun, but let’s try something a bit more hard core: Let’s deploy an application. I hate to disappoint, but it’s not all that exciting: RestClient restClient = new RestClient("localhost", 4848, false /* use ssl? */); Domain domain = new Domain(restClient); RestResponse rr = domain.getApplications().deploy(new File("test.war")); And that’s it. You can now access your application as expected. Need to undeploy the application? Application app = domain.getApplications().getApplication("test"); if (app != null) { app.delete(); } Whew! That’s hard! : ) But, wait! That’s not all! One of the goals of the REST interface is to allow non-Java clients to interact with the GlassFish administration layer. These classes, then, clearly don’t help much with that, but I have a glimmer of hope for all of you Pythonistas and Rubyists out there. My hope, once I have a good handle on the Java client interface, is to extends the CLI command to generate Python and Ruby bindings. Apart from learning Ruby, I think it should be a fairly simple task. There might even be hope for PHP users in the offing as well. GlassFish is, of course, open source, so if your language isn’t supported, you know how to fix that. ; ) Final Word All of this code, is, as I’ve mentioned, very new. Names, interfaces, etc may very well change, and you can actually make that happen. If you have a vested interest in this new feature, we could use your feedback. Filing issues in JIRA is the best way to do that. Comments here, while are, might get lost in the shuffle. :) ### [A Quick (and oh so Brief) Look at a Windows 8 Developer Build](/2011/a-quick-and-oh-so-brief-look-at-a-windows-8-developer-build/) A Quick (and oh so Brief) Look at a Windows 8 Developer Build Call me crazy, but I tried Windows 8, albeit a developer build. An entry in my feed reader from TechBargains showed up announcing a free download of a Windows 8 developer build. It was free, so I figured it couldn’t hurt to check it out. After the 4G+ download, I was ready to create my VirtualBox Windows 8 VM, which I did this morning. It may not last long. First, for the curious, I told VirtualBox to create a 64-bit Windows 7 VM, and gave it 1 gig of RAM, 128M video, and 20G of disk space. The installation took quite a while, as it to unpack a lot of files. Once that was done, though, the installation proceeded fairly quickly and painlessly, so that’s an improvement since I left Windows years ago. Once it was finally installed and ready to use, I was immediately surprised by how different it is. I haven’t been following Windows super closely for some time now, but it seems that Microsoft is trying to tap into the touch screen, drag and poke interfaces that iOS and Android have made so popular. On my desktop (well, MacBook Pro, to be exact), it comes across weird. If you have a touch screen monitor, it may be fine, but it feels awkward with a mouse to me. For example, to login, I finally figured out that I have to click at the bottom of the screen and drag up to reveal the log in screen. Once I did that, I was assaulted with this monstrosity: One of the blogs I follow said "it looks like it was designed by Hasbro", and I’d have to say that’s pretty accurate. It’s…​ugly and weird. I tried clicking around some, but it was hard to tell what I was looking at. Where are my apps? Why do I have all of these large blocks of various colors? I’m not convinced that the basic Windows UI, which was introduced way back with Windows 95, is the ne plus ultra of user interface experiences (nor am I, by the way, too terribly smitten with OS X’s), and I’m all for UI experimentation, etc., but this is pretty bizarre. I can’t imagine too many enterprises being really excited about this release, and, is it turns out, they’re not. I really don’t expect Microsoft will ever be able to coax me back into the fold (without serious coercion from any possible future employer), but this new release of Windows certainly isn’t going to do it. ### [Android at the OKC JUG](/2011/android-at-the-okc-jug/) Android at the OKC JUG Today, I presented basic Android development at the Oklahoma City JUG. In the presentation, we walked through a very simple (and very ugly) note-taking application. The app allows the user to list, view, add, edit, and delete notes. There are no bells and whistles in the app, as I was trying to find something that is non-trivial enough to be interesting, yet no so complex that the audience gets lost in all the details. Overall, I think I succeeded there, though I guess the evaluation slips should tell me how far off I really was. :) As I said at the start of the talk, it’s not a pretty app, and I likely violate many of the best practices the Google and other experts suggest, but it’s a functional app and, for that reason alone, I think, a decent start. I’ve pushed the sources to GitHub so anyone can take a look at it, fork it, etc. As time permits, I hope to clean the code up some, and add, via comments, some of the discussion we had in the talk itself. That will likely make the code a bit more valuable and interesting. Thanks to all who attended, especially those who shouted out hints for things I broke. :P ### [My First Android App: Cub Tracker](/2011/my-first-android-app-cub-tracker/) My First Android App: Cub Tracker Over the weekend, I published my first Android application, Cub Tracker. Cub Tracker is really a pretty simple application, but one born out of a personal need. My oldest son is a Cub Scout Wolf, and I am his den leader. There have been countless times where we had been out somewhere, and my wife and I would ask each other, "I wonder if there’s a Cub Scout achievement or elective for this?" At the time, there was no easy to find out. There are web sites that list these, of course, but it wasn’t convenient to load the page and search it while we’re in the middle of something. Given what I do for a living, I immediately thought, "There should be an app for that!" and Cub Tracker was born. I won’t go into all the details here (there’s a site for that, though it’s pretty bare at the moment), but Cub Tracker allows you to track the achievements and electives of one or more Cub Scouts on your mobile device. It will also generate a report that can be emailed to, say, your Scout’s den leader. It’s not flashy and probably isn’t very exciting for many people, but I’m pretty proud of it and expect I’ll get a lot of use out of it. If you have a Scout, please check it out and let me know what you think. ### [Managing GlassFish JDBC Resources via REST](/2011/managing-glassfish-jdbc-resources-via-rest/) Managing GlassFish JDBC Resources via REST I was asked this morning about creating JDBC resources via REST. As with user management, it’s actually pretty simple, once you’ve seen how. Let’s take a look. To create a JDBC resource, you need two different objects, a JDBC Connection Pool and a JDBC Resource. The endpoints for these two objects are http://localhost:4848/management/domain/resources/jdbc-connection-pool and http://localhost:4848/management/domain/resources/jdbc-resource. Let’s start by creating the connection pool. There are many parameters available (which you can see via OPTIONS), but we’ll only deal with a small subset here: $ curl -X POST -H 'Accept: application/json' \ -d driverClassname=org.postgresql.Driver \ -d resType=java.sql.Driver \ -d id="ExamplePool" \ http://localhost:4848/management/domain/resources/jdbc-connection-pool { "message": "\"http:\/\/localhost:4848\/management\/domain\/resources\/jdbc-connection-pool\/ExamplePool\" created successfully.", "exit_code": "SUCCESS" } This connection pool will, of course, need to know where to connect, and how to log in. To do that, we need to set some properties on the connection pool. Setting properties, though, is a bit different. Properties in GlassFish’s domain.xml aren’t simple name/value pairs. Each property has a name, a value, and a description. To support that, the property endpoint takes an object which, expressed in JSON, is a list of objects: [{'name':'propertyName','value':'propertyValue','description':'optionalPropertyDescription'}]. In our case, the command will look like this: $ curl -X POST -H 'Accept: application/json' \ -H 'Content-Type: application/json' -d "[{'name':'user','value':'test'},{'name':'password','value':'test'},{'name':'databaseName','value':'test'},{'name':'serverName','value':'localhost'},{'name':'url','value':'jdbc:postgresql://localhost/test/'}]" \ http://localhost:4848/management/domain/resources/jdbc-connection-pool/ExamplePool/property { "message": "\"http:\/\/localhost:4848\/management\/domain\/resources\/jdbc-connection-pool\/ExamplePool\/property\" updated successfully.", "command": "Property", "exit_code": "SUCCESS" } We can now view this connection pool like this: $ curl -H 'Accept: application/json' \ http://localhost:4848/management/domain/resources/jdbc-connection-pool/ExamplePool { "command": "Jdbc-connection-pool", "exit_code": "SUCCESS", "extraProperties": { "commands": [], "methods": [ // ... ], "entity": { //... "datasourceClassname": null, "description": null, "driverClassname": "org.postgresql.Driver", //... "name": "ExamplePool", //... "resType": "java.sql.Driver", //... }, "childResources": {"property": "http:\/\/localhost:4848\/management\/domain\/resources\/jdbc-connection-pool\/ExamplePool\/property"} } } Now that we have a connection pool, let’s create the JDBC Resource: $ curl -X POST -H 'Accept: application/json' \ -d id=jdbc/test \ -d poolName=ExamplePool \ http://localhost:4848/management/domain/resources/jdbc-resource { "message": "\"http:\/\/localhost:4848\/management\/domain\/resources\/jdbc-resource\/jdbc\/test\" created successfully.", "exit_code": "SUCCESS" } Your connection pool and resource are now ready to use. As an added bonus, let’s ping our new connection pool to make sure it works: $ curl -H 'Accept: application/json' \ http://localhost:4848/management/domain/resources/ping-connection-pool?id=ExamplePool { "command": "ping-connection-pool AdminCommand", "exit_code": "SUCCESS" } Deleting the pool and the resource are both very simple. Note that the JNDI name (jdbc/test) must be properly encoded (jdbc%2Ftest): $ curl -X DELETE -H 'Accept: application/json' \ http://localhost:4848/management/domain/resources/jdbc-resource/jdbc%2Ftest { "message": "\"http:\/\/localhost:4848\/management\/domain\/resources\/jdbc-resource\/jdbc%2Ftest\" deleted successfully.", "exit_code": "SUCCESS" } $ curl -X DELETE -H 'Accept: application/json' \ http://localhost:4848/management/domain/resources/jdbc-connection-pool/ExamplePool { "message": "\"http:\/\/localhost:4848\/management\/domain\/resources\/jdbc-connection-pool\/ExamplePool\" deleted successfully.", "exit_code": "SUCCESS" } There you have it. If you have any questions, or have some examples you’d like to see, feel free to ask. : ) ### [Adding Users to a GlassFish Realm via REST](/2011/adding-users-to-a-glassfish-realm-via-rest/) Adding Users to a GlassFish Realm via REST A user on the GlassFish forums recently asked how to create users in bulk. The asadmin command create-file-user doesn’t support passing the password as a parameter, which makes scripting difficult. The REST interface, though, can help there, and it’s really pretty simple. The REST endpoint of interest is link: http://localhost:4848/management/domain/configs/config/server-config/security-service/auth-realm/file/create-user, and here’s a sample bash shell script to exercise it: #!/bin/bash for USER in user1 user2 user3 user4 user5 user6 user7 user8 user9 user10 ; do curl -X POST -H 'Accept: application/json' \ -d id=$USER -d AS_ADMIN_USERPASSWORD=$USER http://localhost:4848/management/domain/configs/config/server-config/security-service/auth-realm/file/create-user done Want to see what users exist in the realm? $ curl -H 'Accept: application/json' http://localhost:4848/management/domain/configs/config/server-config/security-service/auth-realm/file/list-users { "command": "list-file-users AdminCommand", "exit_code": "SUCCESS", "extraProperties": {"users": [ { "name": "user10", "groups": [] }, { "name": "user9", "groups": [] }, // ... ]}, "children": [ { "message": "user10", "properties": {} }, { "message": "user9", "properties": {} }, // ... ] } Minor update I forgot that the poster asked about deleting users. Here’s how you do that: $ curl -H 'Accept: application/json' -X DELETE -d id=user1 $mgmt/configs/config/server-config/security-service/auth-realm/file/delete-user { "command": "delete-file-user AdminCommand", "exit_code": "SUCCESS" } It’s important to note that only FileRealm-based realms support user management in this manner. For other realm types, like LdapRealm and JdbcRealm, for example, the system administrator will need to use tools that are appropriate for the type of realm in question. If you have any questions, leave a message. :) ### [Debugging GlassFish REST Requests](/2011/debugging-glassfish-rest-requests/) Debugging GlassFish REST Requests If you’ve been following my series on using the GlassFish REST interface, you’ve probably noticed that your JSON and XML output isn’t pretty-printed like mine. While there are several online tools that can fix that for you, there’s no need for the extra step. GlassFish will do that for you. Let’s look at how to make that happen. To configure the REST interface, we can use the REST interface, in particular http://localhost:4848/management/domain/configs/config/server-config/_set-rest-admin-config $ curl -X OPTIONS http://localhost:4848/management/domain/configs/config/server-config/_set-rest-admin-config { "command": "_set-rest-admin-config", "exit_code": "SUCCESS", "extraProperties": {"methods": [ {"name": "GET"}, { "name": "POST", "messageParameters": { "debug": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, "indentLevel": { "acceptableValues": "", "optional": "true", "type": "int", "defaultValue": "-100" }, "logInput": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, "logOutput": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, "showDeprecatedItems": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, "showHiddenCommands": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, "wadlGeneration": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" } } } ]} } Here’s what each of those options mean: debug - To the best of my knowledge, this option is not used. indentLevel - If this option is 0 or greater, the output is pretty-printed, using this value as the indentation level. logInput - Echo to the server log all REST requests. logOutput - Echo to the server log all REST responses. showDeprecatedItems - By default, deprecated items are not shown. If you need to see them, set this to true. showHiddenCommands - By default, hidden commands are not shown. If you need to see them, set this to true. Be warned, though, that hidden commands are hidden for a reason. They are internal, undocumented commands and can be changed or removed without notice. wadlGeneration - Since WADL generation is an expensive process, it is turned off by default. If you need WADL, set this to true. You can then retrieve the WADL document from http://localhost:4848/management/application.wadl. Be careful with that, the resulting file is HUGE. For technical, implementation-specific reasons (which I won’t go into here), the first attempt to manipulate the REST configuration must be done via http://localhost:4848/management/domain/configs/config/server-config/_set-rest-admin-config. Once that’s done, the rest-config element will show up under server-config as expected. For example, to enable pretty-printing, for example, we can issue these requests: $ curl -s -S -H "Accept: application/json" -X POST http://localhost:4848/management/domain/configs/config/server-config/_set-rest-admin-config $ curl -s -S -H "Accept: application/json" -X POST -d indentLevel=4 http://localhost:4848/management/domain/configs/config/server-config/rest-config { "message": "\"http:\/\/localhost:4848\/management\/domain\/configs\/config\/server-config\/rest-config\" updated successfully.", "exit_code": "SUCCESS" } And that’s all there is to it. Debugging your REST client issues should now be much simpler. ### [GlassFish 3.1 Is Now Available](/2011/glassfish-3-1-is-now-available/) GlassFish 3.1 Is Now Available image::http://glassfish.java.net/image/sparky_3.1_orange.gif[style="float: right; padding: 0px 0px 10px 10px;"] For those that may not have noticed, today the GlassFish team officially released version 3.1. This new release brings in a myriad of features, the most significant of which is probably clustering and high availability. The Aquarium is the best place to find links to blogs, screencasts etc. from various GlassFish engineers (though Markus Eisele has a nice run down of the new features here as well). The Aquarium’s list is pretty extensive, so certainly check it out, but I’d like to highlight a few that I found interesting from teammates of mine: GlassFish 3.1 Overview GlassFish 3.1: New Features in Admin Console GlassFish 3.1: From Installation to Running Application in a Cluster People often ask what the difference is between the free GlassFish and the commercially-supported version. The answer really is "not much" in terms of the core server itself (pretty much just branding changes). The commercial version, though, has some nice value-add features, such as the Performance Tuner, amongst others. I’m really, really pleased with how GlassFish 3.1 has turned out. We still (and will always) have more work to do, but this is a solid release that finally fills in some enterprise holes that v3 didn’t have time to fill. Download it, install it, kick the tires a bit, and tell us what you what you think. In the meantime, we’re going to go ahead and get started on 3.2. ### [RESTful GlassFish Monitoring](/2011/restful-glassfish-monitoring/) RESTful GlassFish Monitoring In previous posts, I’ve shown various ways to manage a GlassFish 3.1 server via its REST interface. As nice as that is, we also support monitoring your server via REST as well. In this article, we’ll take a look at some of the things you can ask of your server. If you’re familiar with the management interface, you should be immediately comfortable with the monitoring interface. To access it, you use http://localhost:4848/monitoring/domain. Just like the management interface, you can request HTML, XML, or JSON. The simplest way to change the return type is to append an extension of the desired type. $ curl http://localhost:4848/monitoring/domain.html $ curl http://localhost:4848/monitoring/domain.xml $ curl http://localhost:4848/monitoring/domain.json Similarly, you can use the Accept header as well: $ curl -H "Accept: text/html" http://localhost:4848/monitoring/domain $ curl -H "Accept: application/xml" http://localhost:4848/monitoring/domain $ curl -H "Accept: application/json" http://localhost:4848/monitoring/domain There’s a good chance that at this point, many of you are getting a response that looks like this (in JSON): { "message": "", "command": "Monitoring Data", "exit_code": "SUCCESS" } I’ll admit that’s not a very helpful message, but the issue here is that while monitoring is turned on by default, the monitoring levels are set to OFF by default. You can change that a few different ways. Perhaps the two easiest are via the command-line (you can use asadmin set, but we’ll not look at that here): ... or via the Admin Console: Select the modules you’re interested in (if you’re just experimenting, it might be best to select all of them), select the level you want (again, I’d suggest HIGH for now), then click save. Your monitoring requests will now give you the data you’re seeking. Now that we know how to get the data, what kind of data can get? Fortunately, the system will help you with that: $ curl -H "Accept: application/json" http://localhost:4848/monitoring/domain { "message": "", "command": "Monitoring Data", "exit_code": "SUCCESS", "extraProperties": { "entity": {}, "childResources": {"server": "http:\/\/localhost:4848\/monitoring\/domain\/server"} } } If you just installed GlassFish 3.1, you’ll see the above. If, however, you have a more complex setup (cluster, standalone instances, etc.), you might see something like this (two clustered instances, one standalone instance, and the DAS): $ curl -H "Accept: application/json" http://localhost:4848/monitoring/domain { "message": "", "command": "Monitoring Data", "exit_code": "SUCCESS", "extraProperties": { "entity": {}, "childResources": { "c1in1": "http:\/\/localhost:4848\/monitoring\/domain\/c1in1", "c1in2": "http:\/\/localhost:4848\/monitoring\/domain\/c1in2", "in1": "http:\/\/localhost:4848\/monitoring\/domain\/in1", "server": "http:\/\/localhost:4848\/monitoring\/domain\/server" } } } If you do have extra instances like this, you will need to set the monitoring levels as desired in the appropriate configuration. The server instance (also known as the DAS), has these child elements: $ curl -H "Accept: application/json" http://localhost:4848/monitoring/domain/server { "message": "", "command": "Monitoring Data", "exit_code": "SUCCESS", "extraProperties": { "entity": { "starttime": "1298837779434", "state": "1", "uptime": "2639132" }, "childResources": { "applications": "http:\/\/localhost:4848\/monitoring\/domain\/server\/applications", "deployment": "http:\/\/localhost:4848\/monitoring\/domain\/server\/deployment", "http-service": "http:\/\/localhost:4848\/monitoring\/domain\/server\/http-service", "jvm": "http:\/\/localhost:4848\/monitoring\/domain\/server\/jvm", "network": "http:\/\/localhost:4848\/monitoring\/domain\/server\/network", "resources": "http:\/\/localhost:4848\/monitoring\/domain\/server\/resources", "security": "http:\/\/localhost:4848\/monitoring\/domain\/server\/security", "transaction-service": "http:\/\/localhost:4848\/monitoring\/domain\/server\/transaction-service", "web": "http:\/\/localhost:4848\/monitoring\/domain\/server\/web" } } } Note that we can see the server start time (displayed in Unix time. This server was started on Sun Feb 27 2011 14:16:19 GMT-0600 (CST)) and how long the server has been up (2639132 milliseconds, or about 44 minutes). Notice under childResources the various classes of additional information. The easiest way to examine those is to point your browser at http://localhost:4848/monitoring/domain/server. Go ahead and poke around. You can’t hurt anything. : ) While I won’t take the time to examine the tree exhaustively, for those that can’t examine a running GlassFish instance right now, let’s take a look at the information on memory the server gives us: $ curl -H "Accept: application/json" http://localhost:4848/monitoring/domain/server/jvm/memory { "message": "", "command": "Monitoring Data", "exit_code": "SUCCESS", "extraProperties": { "entity": { "committedheapsize-count": { "count": 158642176, "lastsampletime": 1298841382830, "description": "Amount of memory in bytes that is committed for the Java virtual machine to use", "unit": "bytes", "name": "CommittedHeapSize", "starttime": 1298839382803 }, "committednonheapsize-count": { "count": 120938496, "lastsampletime": 1298841382830, "description": "Amount of memory in bytes that is committed for the Java virtual machine to use", "unit": "bytes", "name": "CommittedNonHeapSize", "starttime": 1298839382803 }, "initheapsize-count": { "count": 0, "lastsampletime": 1298841382830, "description": "Amount of memory in bytes that the Java virtual machine initially requests from the operating system for memory management", "unit": "bytes", "name": "InitialHeapSize", "starttime": 1298839382803 }, "initnonheapsize-count": { "count": 12750848, "lastsampletime": 1298841382830, "description": "Amount of memory in bytes that the Java virtual machine initially requests from the operating system for memory management", "unit": "bytes", "name": "InitialNonHeapSize", "starttime": 1298839382803 }, "maxheapsize-count": { "count": 518979584, "lastsampletime": 1298841382830, "description": "Maximum amount of memory in bytes that can be used for memory management", "unit": "bytes", "name": "MaxHeapSize", "starttime": 1298839382803 }, "maxnonheapsize-count": { "count": 234881024, "lastsampletime": 1298841382830, "description": "Maximum amount of memory in bytes that can be used for memory management", "unit": "bytes", "name": "MaxNonHeapSize", "starttime": 1298839382803 }, "objectpendingfinalizationcount-count": { "count": 0, "lastsampletime": 1298841382830, "description": "Approximate number of objects for which finalization is pending", "unit": "count", "name": "ObjectsPendingFinalization", "starttime": 1298839382803 }, "usedheapsize-count": { "count": 95092688, "lastsampletime": 1298841382830, "description": "Amount of used memory in bytes", "unit": "bytes", "name": "UsedHeapSize", "starttime": 1298839382803 }, "usednonheapsize-count": { "count": 77427208, "lastsampletime": 1298841382830, "description": "Amount of used memory in bytes", "unit": "bytes", "name": "UsedNonHeapSize", "starttime": 1298839382803 } }, "childResources": {} } } In English, this shows us: CommittedHeapSize - 158642176 bytes CommittedNonHeapSize - 120938496 bytes InitialHeapSize - 0 bytes InitialNonHeapSize - 12750848 bytes MaxHeapSize - 518979584 bytes MaxNonHeapSize - 234881024 bytes ObjectsPendingFinalization - 0 UsedHeapSize - 95092688 bytes UsedNonHeapSize - 77427208 bytes Similarly, from http://localhost:4848/monitoring/domain/server/jvm/runtime, we learn (large strings like InputArguments stripped for brevity’s sake): ClassPath InputArguments LibraryPath ManagementSpecVersion - 1.2 Name - 937@halpert SpecName - Java Virtual Machine Specification SpecVendor - Sun Microsystems Inc. SpecVersion - 1.0 Uptime - 1298843595776 VmName - Java HotSpot™ Client VM VMVendor - Apple Inc. VmVersion - 17.1-b03-307 We’ve only scratched the surface of what the monitoring interface can provide developers and administrators, and since this is REST, you no longer need to write a Java client to get to the data, so point your browser at the monitoring interface and start digging. ### [Java EE's Buried Treasure: the Application Client Container](/2011/java-ee-039-s-buried-treasure-the-application-client-container/) Java EE's Buried Treasure: the Application Client Container From time to time, I’m asked about accessing various EE artifacts (EJBs, etc) from a standalone client. Almost invariably, the user is having trouble getting the environment setup, grabbing an InitialContext, etc. Also almost invariably, my answer to them is "use the application client container", which is as far as I can take them. The topic of application client container, or ACC, came up again recently when I was asked on Twitter about an issue with ACC and GlassFish in a clustered environment. While this user (hi, Markus! : ) figured out his issue before I could be of much help, I took this opportunity finally to learn exactly what the ACC is and how to use it. Thanks to Oracle’s Tim Quinn for his patient and tireless help, here’s what I learned…​ What is the Application Client Container Officially, an ACC is defined this way: The Application Client Container (ACC) includes a set of Java classes, libraries, and other files that are distributed along with Java client programs that execute on their own Java Virtual machine. The ACC provides system services that enable a Java client program to execute. It communicates with the Application Server using RMI/IIOP and manages communication of RMI/IIOP using the client ORB bundled with it. The ACC is specific to the EJB container and is often provided by the same vendor. In a nutshell, an application client is a Java application (which would typically be, I’m guessing, a Swing app, for example) that is a client of a particular enterprise application. It is run in an "application client container" which handles the lifecycle of the application, providing various enterprise type services (such as EJB injection). An example might be an EJB-based order entry system, with a Swing frontend. Much to my surprise, there doesn’t seem to be any magic to it beyond the inclusion of the XML file, META-INF/application-client.xml, which we’ll look at in just a moment. First, let’s build a simple enterprise application. The Enterprise Application In order to have an application client, we need an application, so we’re going to build one, but I’m going to do something a bit unusual. Typically, my examples here all Maven-based. This time, though, I’m going to walk you through building the application (and its client) using NetBeans, as it’s support for what we’re doing here is pretty slick. Don’t click away yet, Maven fans. I’ll have a Maven version further down. To create the application, click File → New Project in NetBeans (I’m using a nightly of NetBeans 7.0, for what it’s worth): Choose the Jave EE category, and Enterprise Application under Projects. On the next page, enter the project name and location: On the third step in the wizard, make sure you have a server selected (I, for example, chose the very excellent GlassFish 3.1 server : ). Uncheck Create Web Application Module, and, if you would like, check Enable Contexts and Dependency Injection. Finally, click finish and NetBeans will create your project for you. With our project ready, let’s create a really simple EJB. We’ll do that in the new EnterpriseApplication-ejb project (for what it’s worth, I modified my project to find its source under src/main/java to make Mavenization simpler later). Let’s start with an interface (yes, I know EJB 3.1 has interface-less EJBs, but the ACC doesn’t seem to like that, and I still think programming to interfaces is a good idea): @Remote public interface Dummy { String sayHello(String name); } And here’s the implementation: public class DummyBean implements Dummy { @Override public String sayHello(String name) { return "Hello, " + name; } } And that’s our app. You can have NetBeans build and deploy it if you’d like, but you won’t see much. To fix that, let’s write a simple Swing app to exercise this impressive EJB. The Enterprise Application Client In NetBeans, click File → New Project again. Choose the Java EE category again, but this time select Enterprise Application Client under Projects: On the final page, select EnterpriseApplication for Add to Enterprise Application, make sure the correct server is selected, target Java EE 6, and check Enable Contexts and Dependency Injection if you’d like (all this does, by the way, is add a basically empty beans.xml to the project, so you can always do this later if you forget). Our app client will look something like this: public class Main extends javax.swing.JFrame { @EJB private static Dummy dummy; /** Creates new form NewJFrame */ public Main() { initComponents(); } @SuppressWarnings("unchecked") private void initComponents() { label = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); label.setText("label"); GroupLayout layout = new GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.LEADING) .add(layout.createSequentialGroup() .add(134, 134, 134) .add(label, GroupLayout.PREFERRED_SIZE, 256, GroupLayout.PREFERRED_SIZE) .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.LEADING) .add(layout.createSequentialGroup() .add(81, 81, 81) .add(label) .addContainerGap(203, Short.MAX_VALUE)) ); pack(); } /** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { final Main frame = new Main(); frame.label.setText(dummy.sayHello("Jason")); frame.setVisible(true); } }); } // Variables declaration - do not modify protected javax.swing.JLabel label; // End of variables declaration } We’re now ready to run our application. In the Projects browser on the left, right click EnterpriseApplication and click Run. After a few seconds, you should see a window that looks like this: Beautiful! 8-) Deploying and running outside of NetBeans Obviously, you won’t deploy this to production with NetBeans, so let’s a take a quick look at deployment and execution via the command line. If you want to deploy the app and immediately download the client stubs, you can do this: asadmin deploy --retrieve localdir/ --force dist/EnterpriseApplication.ear This will deploy the app and download the client stubs to localdir in the current directory. If you don’t need the client stubs at the time of deployment (say, you’ve deployed to the server from your machine, then need to download on a client machine), you can issue this command: asadmin get-client-stubs --appname EnterpriseApplication localdir To run the client, issue this command: appclient -jar localdir/EnterpriseApplicationClient.jar The problem with that approach is that it requires a pretty heavy configuration: grab some GlassFish client jars, configure XML, and on and on. That’s just too much. Fortunately, GlassFish makes this really simple (remember when I said GlassFish was an excellent server? : ). With the application deployed, point your browser at http://localhost:8080/EnterpriseApplication/ApplicationClient and wait for it. GlassFish gives you Java Web Start for your application client for free. No extra steps needed. If this is the first time you’ve run the Application Client via JWS on this machine, it will take a few minutes to download the required libraries, but subsequent runs should be much quicker starting up. How fancy is that? Enough with the GUI! Give me some XML! For those that have been waiting patiently, here’s how to accomplish the same thing via Maven. Let’s start with a parent POM: <project xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd' xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>parent</artifactId> <packaging>pom</packaging> <version>0.1-SNAPSHOT</version> <name>Enterprise Application - parent</name> <modules> <module>ejb</module> <module>appclient</module> <module>ear</module> </modules> <repositories> <repository> <id>maven2-repository.dev.java.net</id> <name>Java.net Repository for Maven</name> <url>http://download.java.net/maven/2/</url> </repository> </repositories> <properties> <javaee-api.version>6.0</javaee-api.version> </properties> <dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>6.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project> The EJB POM is very simple: <project xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd' xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>parent</artifactId> <version>0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>ejb</artifactId> <packaging>jar</packaging> <name>Enterprise Application - ejb</name> </project> As is the app client jar: <project xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd' xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>parent</artifactId> <version>0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>appclient</artifactId> <packaging>jar</packaging> <name>Enterprise Application - appclient</name> <dependencies> <dependency> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>ejb</artifactId> <version>$\{project.version}</version> </dependency> <dependency> <groupId>org.swinglabs</groupId> <artifactId>swing-layout</artifactId> <version>1.0.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.3.1</version> <configuration> <archive> <manifest> <mainClass>com.steeplesoft.acc.client.Main</mainClass> <addClasspath>true</addClasspath> </manifest> </archive> </configuration> </plugin> </plugins> </build> </project> Note that we add a dependency on our EJB module, as well as the swing-layout artifacts. We also need to configure the Maven JAR plugin to tell it the name of our Main class. I also have application-client.xml and beans.xml in src/main/resources/META-INF. Lastly, we have the POM for the ear module: <project xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd' xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>parent</artifactId> <version>0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>enterpriseapplication</artifactId> <packaging>ear</packaging> <name>Enterprise Application - ear</name> <dependencies> <dependency> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>ejb</artifactId> <version>$\{project.version}</version> <type>ejb</type> </dependency> <dependency> <groupId>com.steeplesoft.enterpriseapp</groupId> <artifactId>appclient</artifactId> <version>$\{project.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-ear-plugin</artifactId> <version>2.5</version> <configuration> <version>6</version> <defaultLibBundleDir>lib</defaultLibBundleDir> <generateApplicationXml>false</generateApplicationXml> <modules> <ejbModule> <groupId>$\{project.groupId}</groupId> <artifactId>ejb</artifactId> </ejbModule> <jarModule> <groupId>$\{project.groupId}</groupId> <artifactId>appclient</artifactId> <bundleDir>/</bundleDir> </jarModule> </modules> </configuration> </plugin> </plugins> </build> </project> The configuration for the EAR plugin took me a while to figure out, and there’s a good chance I’m not doing it quite right, but it works. :) Issue mvn install from the top-level directory, and you have your deployable archive in ear/target. That’s all there is to it. Clearly, you’ll want a more interesting enterprise application, which leads to a more interesting application client, but the basics of putting these pieces together remain the same. So next time you need to access an EJB deployed to a remote application server, you know the official, portable way to get to it. As always, feel free to post questions, suggestions, critiques, etc in the comments below. The source code can be found here. ### [GlassFish 3.1, REST, and a Secured Admin User](/2011/glassfish-3-1-rest-and-a-secured-admin-user/) GlassFish 3.1, REST, and a Secured Admin User In my last post on using the GlassFish REST interface, a commenter asked about how GlassFish handles security. So far, all of my examples have been using GlassFish 3.1 out of the box, which doesn’t require authentication (as a convenience for developers, as well as system admins evaluating the server). In production, of course, the server will be secured, which means our client code will have to be modified. In this installment, we’ll see how that might be done in Java. Let’s start with a very simple class that deploys an application to the server: public class AuthExample { protected Client client; public AuthExample() { client = Client.create(); } public boolean deployApp(String fileName) throws URISyntaxException { FormDataMultiPart form = new FormDataMultiPart(); form.getBodyParts().add(new FileDataBodyPart("id", new File(fileName))); form.field("name", fileName.substring(0, fileName.indexOf(".")), MediaType.TEXT_PLAIN_TYPE); form.field("contextroot", fileName.substring(0, fileName.indexOf(".")), MediaType.TEXT_PLAIN_TYPE); form.field("force", "true", MediaType.TEXT_PLAIN_TYPE); ClientResponse response = client.resource("http://localhost:4848/management/domain/applications/application/") .type(MediaType.MULTIPART_FORM_DATA) .accept(MediaType.APPLICATION_JSON) .post(ClientResponse.class, form); return response.getStatus() == 200; } public static void main(String... args) { try { AuthExample example = new AuthExample(); if (example.deployApp(args[0])) { System.out.println("Success"); } else { System.out.println("Failure"); } } catch (Exception e) { e.printStackTrace(); } } } If you execute this, passing a WAR as the first and only parameter, you should see "Success" printed to the screen. Now that we’ve verified this works, let’s secure the server: $ asadmin change-admin-password Enter admin user name [default: admin]> Enter admin passwordthe > Enter new admin password> Enter new admin password again> Command change-admin-password executed successfully. If you rerun the class now, you should see "Failure" printed to the screen, which is what we’d expect to see. To fix this, let’s change the constructor for our test app: public AuthExample() { client = Client.create(); client.addFilter(new HTTPBasicAuthFilter("admin", "admin")); } Change the password, of course, to what you entered, and rerun the app. You should now see "Success". Pretty simple. Ultimately, this has more to do with the Jersey Client than with GlassFish, but is still something one will need to know if using these two pieces of software together. For the Maven people in the audience, here’s the POM I used to build this: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>jersey-plus-auth</artifactId> <packaging>jar</packaging> <version>0.1-SNAPSHOT</version> <name>Jersey plus Authentication Example</name> <dependencies> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.5</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-multipart</artifactId> <version>1.5</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> <showDeprecation>true</showDeprecation> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>run</id> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2</version> <executions> <execution> <phase>package</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass> com.steeeplesoft.jersey.examples.auth.AuthExample </mainClass> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles> </project> I executed the project with this command line: mvn -Prun -Dexec.args="test.war" package Enjoy! ### [GlassFish 3.1, REST, and Secure Admin](/2011/glassfish-3-1-rest-and-secure-admin/) GlassFish 3.1, REST, and Secure Admin After posting my last entry, GlassFish 3.1, REST, and a Secured Admin User, I was asked about an entry on using GlassFish 3.1’s REST interface with secure admin enabled. Some of you may be asking, "Isn’t that what you just wrote about?" While the titles sound the same, they’re slightly different, but in a very significant way. Let’s take a quick look at secure admin and then see what our REST client needs to do make use of this new server configuration. Secure admin is defined as this in the enable-secure-admin help: The enable-secure-admin subcommand creates or modifies secure-admin and secure-admin-principal elements under the domain element in the domain.xml for the domain. Enabling secure admin affects the entire domain, including the DAS and all instances. As part of this action, the enable-secure-admin subcommand performs the following functions: Sets the secure-admin enabled attribute to true in domain.xml Adjusts all configurations in the domain, including default-config, and creates or updates secure-admin If the secure-admin fragment already exists in domain.xml, then the alias values in the secure-admin-principal elements are changed only if the --adminalias or --instancealias options is specified with the enable-secure-admin subcommand. The hidden _instance-enable-secure-admin sub-command is sent to all non-DAS targets in the domain. This hidden command performs the same configuration changes on the instances as enable-secure-admin does on the DAS. Creates the necessary truststore if it is missing If the keystore and truststore do not contain a certificate for the instance alias, then the instance self-signed key pair is generated and the private key is added to the keystore and the public certificate is added to the trust-store. If the truststore does not contain a certificate for the DAS alias, the DAS certificate from the keystore is added to the truststore. Adjusts Grizzly settings SSL/TLS is enabled using the specified --adminalias value in the DAS’s admin listener and the --instancealias value in the instances' admin listeners. Port unification, redirection, and client-auth=want are enabled. A server restart is required to change the Grizzly adapter behavior. This also synchronizes the restarted instances that will deliver any updated keystore and truststore files. There’s a lot to that, but all you really need to understand from the client’s perspective is that you’re going to have to use SSL. So…​ sorry to make you read all of that. :) First up, let’s prepare the server: $ asadmin enable-secure-admin $ asadmin stop-domain $ asadmin start-domain Unless you installed a signed certificate, if you run the example from my last post, you should now see a giant stack trace with sun.security.validator.ValidatorException: PKIX path building failed toward the end. There are at least two ways to handle this. The first, and perhaps the best, is simply to import the server’s certificate. One way to do this is via this utility (written by a Sun engineer whose name I can’t find): $ javac InstallCert.java $ java InstallCert localhost Another approach, albeit riskier, is to accept all certificates. You can achieve that with this code: public static void disableCertificateValidation() { // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { return; } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { return; } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { } } Note that this will affect all HTTPS connections in the JVM, so use it with caution. Once a call to that method has been added to the class' constructor, we can then change the GlassFish url to use HTTPS: public class SslExample { private Client client; public SslExample() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { disableCertificateValidation(); client = Client.create(); } public static void disableCertificateValidation() { // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { return; } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { return; } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { } } public boolean deployApp(String fileName) throws URISyntaxException { FormDataMultiPart form = new FormDataMultiPart(); form.getBodyParts().add(new FileDataBodyPart("id", new File(fileName))); form.field("name", fileName.substring(0, fileName.indexOf(".")), MediaType.TEXT_PLAIN_TYPE); form.field("contextroot", fileName.substring(0, fileName.indexOf(".")), MediaType.TEXT_PLAIN_TYPE); form.field("force", "true", MediaType.TEXT_PLAIN_TYPE); ClientResponse response = client.resource("https://localhost:4848/management/domain/applications/application/") .type(MediaType.MULTIPART_FORM_DATA) .accept(MediaType.APPLICATION_JSON) .post(ClientResponse.class, form); return response.getStatus() == 200; } public static void main(String... args) { try { SslExample example = new SslExample(); if (example.deployApp(args[0])) { System.out.println("Success"); } else { System.out.println("Failure"); } } catch (Exception e) { e.printStackTrace(); } } } There are likely cleaner, safer ways of going about this, but this will certainly get you going. ### [Deploying Applications to GlassFish Using curl](/2011/deploying-applications-to-glassfish-using-curl/) Deploying Applications to GlassFish Using curl Over the past few months, I’ve been posting tips on how to use the REST interface in GlassFish v3 and later to perform various functions. My last post used Scala. In this much briefer and far less ambitious post, I thought I’d share how to deploy an app using curl (from the shell of your choice). If you’re familiar with the REST endpoint, there’s really not just a whole lot new here: curl -s -S \ -H 'Accept: application/json' -X POST \ -H 'X-Requested-By: dummy' \ -F id=@/path/to/application.war \ -F force=true http://localhost:4848/management/domain/applications/application Remember that the actual archive contents are passed as the value to the parameter id, so we tell curl to send the contents of the file using the prefix @. The context root and application will be deduced by the system (or can be specified by passing contextroot and name parameters). The force parameter tells GlassFish to force the deployment even if an application is already deployed under that name (which is effectively a redeployment). As an added bonus, to undeploy, you can issue this: curl -s -S \ -H 'Accept: application/json' \ -H 'X-Requested-By: dummy' \ -X DELETE http://localhost:4848/management/domain/applications/application/$APPNAME It’s as simple as that. If you’re using a shell script, you could always just use asadmin directly, of course. Using that approach, asadmin must be on the PATH, or you have to specify the full path in your script, so your choice comes down to preference, I think. Either way, now you know how to do both. :) ### [Running Long-Running Reports with JMS](/2011/running-long-running-reports-with-jms/) Running Long-Running Reports with JMS At a recent meeting of the Oklahoma City JUG, I was asked by a member how her group could "script" JSF report generation. After a couple of questions, I figured what she really wanted: she wanted a way to allow users to request reports in an ad hoc manner, as opposed to the reports being run on a schedule. In a general sense, this is a pretty easy question to answer, but I’ve run into situations where the reports take a long time to run — and I’m sure she will, as well — making a web interface for generating the report less useful (due to timeouts, etc). In this entry, we’ll take a look at one way to handle that. In a prior shop, I solved this problem using a Thread. As you may or may not know, the use of Threads in user applications is STRONGLY discouraged in Java EE. A thread improperly started and managed can cause all sorts of problems for the server. Fortunately, Java EE offers a way to perform long-running operation like we’re discussion in an asynchronous manner: JMS. For old-timers, the first reaction to hearing that may be wailing and gnashing of teeth, but Java EE 5 (and, of course, Java EE 6) makes this really, really easy. Our sample app will be a really simple JSF application. It will ask the user for an email address, then send that address to a JMS queue, where a message-driven bean will pick it up, fake generating the report and email it to the user. Let’s start with the JSF managed bean: @ManagedBean @RequestScoped public class JmsBean { @Resource(mappedName = "jms/ConnectionFactory") // [1] private ConnectionFactory connectionFactory; @Resource(mappedName = "jms/Queue") // [2] private Queue queue; protected String emailAddress; private static final Logger logger = Logger.getLogger(ReportMdb.class.getName()); public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String generateReport() { try { Connection connection = connectionFactory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // [3] MessageProducer messageProducer = session.createProducer(queue); // [4] ObjectMessage message = session.createObjectMessage(); // ([5]) ReportRequest request = new ReportRequest(emailAddress); message.setObject(request); messageProducer.send(message); // ([6]) return "queued"; } catch (JMSException ex) { Logger.getLogger(JmsBean.class.getName()).log(Level.SEVERE, null, ex); return null; } } } At the top of the class, we see two @Resource-annotated members, connectionFactory([1]) and queue ([2]). These two objects are then used in generateReport to send our message. We get a connection, then create javax.jms.Session ([3]) and javax.jms.MessageProducer ([4]) instances. Next we create an ObjectMessage ([5]). In this case, ReportRequest is a really simple class that just has a single, public member: emailAddress. In a real world app, this would have a myriad of members that hold the user’s criteria for the report. Note that the ObjectMessage payload must implement Serializable. With our message created, we send it ([6]) and tell JSF to navigate to the queued view. At this point, from the user’s perspective, the job is done, and the report wil be delivered via email when it’s done. On the backend, though, we still have work to do. A JMS message-driven bean, or MDB, is a bean that watches a particular JMS Destination (usually a Topic or a Queue) and performs some action when a message is delivered, and in Java EE 5 and later, they’re incredibly simple: @MessageDriven(mappedName = "jms/Queue", activationConfig = { // [1] @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") }) public class ReportMdb implements MessageListener { // [2] @Resource(name = "mail/myserver") private Session mailSession; // [3] private static final Logger logger = Logger.getLogger(ReportMdb.class.getName()); @Override public void onMessage(Message inMessage) { ObjectMessage msg = null; try { if (inMessage instanceof ObjectMessage) { // [4] msg = (ObjectMessage) inMessage; Object obj = msg.getObject(); if (! (obj instanceof ReportRequest)) { throw new RuntimeException("Invalid message payload. ReportRequest required, but found " + obj.getClass().getName()); } ReportRequest request = (ReportRequest)obj; logger.log(Level.INFO, "Sending report to \{0}", request.emailAddress); sendMessage(request.emailAddress); } else { logger.log(Level.WARNING, "Message of wrong type: \{0}", inMessage.getClass().getName()); } } catch (JMSException e) { logger.log(Level.SEVERE, "Error: \{0}", e.getLocalizedMessage()); } } protected void sendMessage(String emailAddress) { MimeMessage msg = new MimeMessage(mailSession); try { msg.setSubject("Your Report"); msg.setRecipient(RecipientType.TO, new InternetAddress(emailAddress)); msg.setText("Here is your report!"); Transport.send(msg); } catch (MessagingException me) { logger.log(Level.SEVERE, "Error: \{0}", me.getLocalizedMessage()); } } } There are two parts to creating this MDB. First, we must create a class that implements javax.jms.MessageListener ([2]), which has one method, void onMessage(Message inMessage). Next, we add annotations to tell the container to deploy the MDB, @MessageDriven ([1]). I don’t want to get lost in the weeds of all the options here, so I’ll only make note of two: the mappedName, and the destinationType (javax.jms.Queue). The container will look, then, for a Queue called jms/Queue, which we’ll look at in a moment. Since we’re going to be emailing the report, we inject a javax.mail.Session ([3], which we’ll not spend any time on here). In onMessage, we have some defensive coding ([4]) to make sure we were sent an ObjectMessage (since the Queue will take anything you send it), and that the ObjectMessage payload is a ReportRequest (I did, though, leave out the null check, which you will definitely want). Once we’re sure we have a good message, we extract the email address, "generate" the report, and email it to the user. Our work here, then, is done! Before we leave the issue, though, it’s important to note that the JMS Queue must be configured in the broker as part of the application deployment process. Here’s how that would look for a GlassFish deployment. And that should do it. If you’re interested in the source, you can find that here. If you have any questions, feel free to post them below. ### [Merry Christmas, 2010](/2010/merry-christmas-2010/) Merry Christmas, 2010 I’d like to wish all of my readers a very merry Christmas. It is my hope and prayer that in all the hustle and bustle of the season, that the first Christmas, the birth of the Jesus, the Savior of the world, is not lost. To help with that, I’d like to leave you with some of my current favorite Christmas songs. I hope you enjoy them. God bless. Hallelujah! Light Has Come - Barlowgirl Joseph’s Lullaby - MercyMe (fan video) Christmas Like a Child - Third Day ### [GlassFish Administration: The REST of the Story Part II - Deploying Apps Using Scala](/2010/glassfish-administration-the-rest-of-the-story-part-ii-deploying-apps-using-scala/) GlassFish Administration: The REST of the Story Part II - Deploying Apps Using Scala In a previous post (far too long ago :), I began showing off the RESTful administration API in GlassFish v3. In GlassFish Administration: The REST of the Story Part I, I showed the basics of the API, what to send, what you get back, etc. In this post, I want to show a practical use of the API, namely, deploying an application, and this time, for no particular reason other than I’m trying to learn the language, we’ll do it in Scala. If you’ll recall from Part I, the default root URL is http://localhost:4848/management/domain. The endpoint, then for deploying applications works out to be http://localhost:4848/management/domain/applications/application. [1] Submitting an OPTIONS request to this endpoint gets us a document like this (trimmed down for clarity): { "extraProperties": { "methods": [ {"name": "GET"}, { "name": "POST", "messageParameters": { "contextroot": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, "enabled": { "acceptableValues": "", "optional": "true", "type": "boolean", "defaultValue": "" }, "force": { "acceptableValues": "", "optional": "true", "type": "boolean", "defaultValue": "false" }, "id": { "acceptableValues": "", "optional": "false", "type": "class java.io.File", "defaultValue": "" }, "name": { "acceptableValues": "", "optional": "true", "type": "string", "defaultValue": "" }, } } ] } } There are a lot of options there, but there are many more, giving you really fine-grained control over the deployment of your application. In our case, we only care about a few options, which are in the list above: id, contextroot, and force. The contextroot option specifies the context root at which the application will be available, and force tells the server to redeploy the application if an existing app of the same name is already deployed. The id parameter is a bit different. It’s called id because of the way the REST Resource is implemented on the server side (i.e., the REST Resources wrap, more or less, various GlassFish CLI commands, pulling the required data in from the REST request, and handing if off to the appropriate AdminCommand instance. It all boils down to a lot of internal GlassFish code that’s outside the scope of this entry : ). In our client code, we’ll handle it as a String that represents the path to the archive to be deployed. When we make the actual REST call (via the Jersey Client), we’ll see that a File object is created as we pass the data to Jersey. Having already said too much, let’s see some Scala code (for the Scala enthusiasts out there, this is, quite literally, the very first bit of Scala I’ve ever written, so be kind :): import com.sun.jersey.api.client.Client import com.sun.jersey.api.client.ClientResponse import com.sun.jersey.multipart.FormDataMultiPart import com.sun.jersey.multipart.file.FileDataBodyPart import javax.ws.rs.core.MediaType import java.io.File import scala.xml._ object Main { def main(args: Array[String]): Unit = { val deployer = new GlassFishDeployer deployer.deployApp("test.war"); deployer.applications foreach println } } object GlassFishDeployer { val RESPONSE_TYPE = "application/xml" } class GlassFishDeployer { val url = "http://localhost:4848/management/domain" val client: Client = Client.create() /** * Get the management URLs for each deployed app */ def applications: List[String] = { var apps = List[String]() val xml = XML.loadString(client.resource(url + "/applications/application") .accept(GlassFishDeployer.RESPONSE_TYPE) .get(classOf[String])) for (entry <- ((xml \\ "entry" filter { node => (node \ "@key").text == "childResources" }) \ "map" \ "entry")) { apps ::= entry.attributes("value").text } return apps } def deployApp(pathToArchive: String) = { postWithUpload("/applications/application", Map[String, Any]( "id" -> new File(pathToArchive), "contextroot" -> "testApp", "force" -> "true")) } def postWithUpload(address: String, payload: Map[String, Any]) = { val form = new FormDataMultiPart(); for ((key, value) <- payload) { value match { case x: File => form.getBodyParts().add((new FileDataBodyPart(key, value.asInstanceOf[File]))) case _ => form.field(key, value, MediaType.TEXT_PLAIN_TYPE) } } client.resource(url + address) .`type`(MediaType.MULTIPART_FORM_DATA) .accept(GlassFishDeployer.RESPONSE_TYPE) .post(classOf[ClientResponse], form) } } The two methods that are of interest here are GlassFishDeployer.deployApp and GlassFishDeployer.postWithUpload. In the first, we build the map that holds all of the information we want to pass to the REST interface. Of these three values, only id is required, for you minimalists out there. In postWithUpload, we see the Jersey Client code. We create a FormDataMultiPart object and populate it, then pass that to client as part of the chained calls at the end of the method. There’s no error handling here as that would obscure our objective here, but, barring something unforeseen, the test app should now be deployed. Back in the main method of Main, we make another call to the applications endpoint, which simply returns a list of application endpoints (for further management, such as undeploying) and prints each URL. That’s all there is to it. Using less-than-stellar Scala code, we’ve demonstrated how to deploy an application to a GlassFish instance. Using the RESTful interface that shipped with v3, and which we continue to improve in 3.1, allows us to manage GlassFish from an application written in the language of our choice. The full project (including the Maven pom file), can be found here. [1] You might look at that an wonder why it’s "applications/application," and the answer is because the tree mimics the structure of the domain.xml file that is being manipulated via these endpoints. ### [The Value of the Stack](/2010/the-value-of-the-stack/) The Value of the Stack This morning on twitter, I saw an announcement that Mollom has a new backend, one based on GlassFish. I have to be honest. I don’t know much of anything about Mollom beyond this, nor do I know anything about their previous backend other than it was Java-based. The blog post, though, immediately made me think of dynamic languages. These days, it’s hot to be dynamic, whether it’s Ruby, Python, Groovy, or something else. There’s no denying that they have some very compelling features. One of the quotes in the blog post, though, really stood out to me: With our move to GlassFish, we’ll have to worry a lot less about memory management, REST handling, XML parsing, database connection pooling, and all the other ancillary things that make big systems work. That frees us up to focus on the domain-specific problems — the actual moving parts of Mollom itself — and will help both support our growth and allow us to implement new features and improve the old ones. As I’ve noted, their former architecture was Java-based, but the same idea applies to the typical deployment of projects based on dynamic languages. While readily admitting I’ve done precious little with dynalang projects in the enterprise, from what I’ve read and have heard people discuss, it seems the most common deployment scenario is, for example, Apache httpd with mod_foo installed. There might even be a cluster of these httpd instances (or some other web server that a language or framework suggests) behind a load balancer or two, and that seems to work for a lot of people. While effective, though, it seems that such a configuration leaves a lot of grunt infrastructure work up to the development or production support team. Enter the Java EE stack. As the Mollom engineer noted, using an application server like GlassFish gives the developer and support teams quite a bit of infrastructure for free. In addition to what he listed, a full EE stack can also give you clustering/high-availability, monitoring, server management, etc. (Note: GlassFish v2 support all of these. GlassFish v3 does not support clustering, but GlassFish 3.1, which is just about ready to ship, will). Many of the "ancillary things that make big systems work" are provided for you. It’s not free, of course. The system demands are typically higher, and those "ancillary things" have to be configured, tuned and monitored, but they don’t have to be developed, which makes the systems that run on them a fair bit simpler. It is possible, of course, to get the best of both worlds. Some dynamic languages, like Groovy, already run on the JVM, while projects like JRuby and Jython allow running those languages in a Java EE container, all while still reaping the benefits that dynamic languages offer. For shops that using those languages, or would like to, this is a very compelling option. Dynamic languages do offer a lot that we Java developers would love to use, but users of those dynamic languages would be well-served to take a good look at the Java EE stack and see if perhaps Java can add value to their deployment. ### [Adding SCM Branch Information to Your Prompt](/2010/adding-scm-branch-information-to-your-prompt/) Adding SCM Branch Information to Your Prompt UPDATE: I’ve modified the scripts and prompt settings to be a bit more intelligent Today, a coworker sent me a link to an old blog post about adding git and svn branch information to your prompt. As awesome and helpful as that was, my first thought was, "What about hg support?" followed quickly, if not somewhat embarrassingly, by, "What about CVS support?" Thinking it would be quicker (and more fun) to hack than to google, I added both. The end result is this: parse_git_branch () { git name-rev HEAD 2> /dev/null | sed 's#HEAD\ \(.*\)# (git::\1)#' } parse_hg_branch() { hg branch 2>/dev/null | sed 's#\(.*\)# (hg::\1)#' } parse_svn_branch() { parse_svn_url | sed -e 's#^'"$(parse_svn_repository_root)"'##g' | awk '\{print " (svn::"$1")" }' } parse_svn_url() { if [ -e .svn ] ; then svn info 2>/dev/null | sed -ne 's#^URL: ##p' | sed -e 's#^'"$(parse_svn_repository_root)"'##g' | egrep -o '(tags|branches)/[^/]+|trunk' | egrep -o '[^/]+$' | awk '\{print " ("$1")" }' fi } parse_svn_repository_root() { if [ -e .svn ] ; then svn info 2>/dev/null | sed -ne 's#^Repository Root: ##p' fi } parse_cvs_branch() { if [ -e CVS ] ; then #cat CVS/TAG | cut -c 2- 2>/dev/null | sed '#\(.*\)# (cvs::\1)#' BRANCH=`cat CVS/TAG 2>/dev/null | cut -c 2- ` ; if [ "$BRANCH" != "" ] ; then echo " (cvs::$BRANCH)" ; fi fi } get_branch_information() { if [ -e .svn ] ; then parse_svn_branch elif [ -e CVS ] ; then parse_cvs_branch else parse_git_branch parse_hg_branch fi } BLACK="\[\033[0;38m\]" RED="\[\033[0;31m\]" RED_BOLD="\[\033[01;31m\]" BLUE="\[\033[01;34m\]" GREEN="\[\033[0;32m\]" export PS1="$BLACK[ \u@$RED\h $GREEN\w$RED_BOLD\$(get_branch_information)$BLACK ] " I should note that there seems to be a slight performance hit due to all of this, but I can’t tell if it’s all these new checks or if my machine is just already working too hard. Either way, it’s nowhere near significant enough to make me care. :) ### [Running a Single JUnit Test](/2010/running-a-single-junit-test/) Running a Single JUnit Test Part of my job as a developer is writing unit tests. Lately, though, I’ve been spending more and more of my time in our tests, which take a long, long time to run. For example, to run the GlassFish Admin Console’s StandaloneTest class, the last run took 17 minutes and 36 seconds. Clearly, something needs to be done to speed that up overall, but I have to wait for the entire class to run just so that I can see if my one new/changed test works. Try as I might, I have not been able to find a way to make the surefire Maven plugin run just that one test method. This morning, though, I happened to stumble across a new feature of JUnit (as of 4.7, if I read correctly) that did the trick for me, which I’ll share here. This new feature is a MethodRule. It’s an interface that a user can implement, and, when coupled with the @Rule attribute, allows this rule to applied in a very AOP-like manner to each test. Since code is often better than words, here’s the MethodRule I implemented for the console tests: public class SpecificTestRule implements MethodRule { protected String method; public SpecificTestRule() { method = System.getProperty("method"); } @Override public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) { return new Statement() { @Override public void evaluate() throws Throwable { boolean runMethod = false; Ignore ignore = frameworkMethod.getAnnotation(Ignore.class); if ((method != null) && method.equals(frameworkMethod.getName())) { runMethod = true; } else if (ignore == null) { runMethod = true; } if (runMethod) { statement.evaluate(); } } }; } } There’s really not much going on here. In the constructor, I look up the value of the method system property and store it on the instance. In the apply() method, we check to see if method is null. If it is (i.e., the user did not specify this property on the command line, so all test methods are to be run), we execute the test method in question. If it is not, then the user has requested that only a specific method be run, so check to see what the current method is. We do that by calling frameworkMethod.getName(). If that equals method, then we evaluate the Statement. Otherwise, we exit without doing anything. With that rule defined, let’s take a look at how that is applied to the tests. All of the console tests extend a base class, so I added this snippet to that base class: @Rule public SpecificTestRule specificTestRule = new SpecificTestRule(); In this case, that particular instance variable is never used, so this usage seems strange, but it is possible for the MethodRule to provide data to test (such as the test name). In our case, though, we just want to apply the rule, so we add the instance variable and forget about it. With those two pieces of code in place, we can now run individual test methods: public class MyTest extends MyBase { // The rule is defined in the base @Test public void foo() { System.out.println("foo"); } @Test public void bar() { System.out.println("bar"); } public void baz() { System.out.println("baz"); } } For that test, we can execute mvn -Dtest=MyTest -Dmethod=foo test, and expect output like this: ------------------------------------------------------- T E S T S ------------------------------------------------------- Running MyTest foo Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.048 sec Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 A possible enhancement would be to allow for a comma-delimited list of methods to run (mvn -Dtest=MyTest -Dmethod=foo,baz test), but this is a nice start, I think. Update: After posting this, I found a bug where the @Ignore annotation was ignored. I have updated the MethodRule implementation above to fix the bug. Yes, the code can be more concise, but I’m blogging it as I develop and test it, and, that aside, this is more readable than super-compact code, and that’s not nothing. :P ### [Interested in Remote Method Calls via JS in JSF?](/2010/interested-in-remote-method-calls-via-js-in-jsf/) Interested in Remote Method Calls via JS in JSF? One of the nicest enhancements to the JSF specification that 2.0 brought was the inclusion of native Ajax support. It is now extremely simple to Ajaxify a JSF application. One thing that it lacks, though, is the ability to call arbitrary methods on JSF (or CDI?) Managed Beans. There is a project that offers that kind of functionality, and it’s been around for years: Direct Web Remoting. I’ve used this library at times and have found it to be really useful in certain situations. That got me to wondering, Should this kind of functionality be a first class citizen of JSF? To help us decide, let’s take a quick look at how DWR works. Once you have DWR configured to work (warning: those docs might be slightly out of date, if memory serves me), you have to tell DWR what to expose. I prefer the annotation-based approach (condensing, here, the DWR documentation, with some modifications): @ManagedBean @SessionScoped @RemoteProxy public class RemoteFunctions { @RemoteMethod public int calculateFoo() { return 42; } public String calculateBar() { return "Life, the universe, and everything" } } For a class like this, DWR will expose RemoteFunctions.calculateFoo(), but will not expose RemoteFunctions.calculateBar(). With DWR, you must explicitly mark a method as remoteable (is that a word? : ) or you won’t have access to it. On the client side, you would put something like this on your page: <script type: "text/javascript" src="[WEBAPP]/dwr/interface/RemoteFunctions.js"/> <script type: "text/javascript" src="[WEBAPP]/dwr/engine.js"/> With those two declarations, you would then be able to call the JSF Managed Bean via: RemoteFuctions.calculateFoo(function(str) { alert(str); }); While this isn’t a very exciting example, it should highlight the type of interaction DWR enables. It offers a great deal more flexibility with things like RBAC and Object conversion (i.e., DTOs). I’ve found this to be a very nice library that neatly solves certain types of asynchronous issues. The question I have, though, is, as stated above, "Should this be added to the JSF specification?" Ed Burns, the JSF spec lead, is pretty vocal in his assertion (with which I tend to agree) that specs aren’t primarily for innovating but for standardizing (which is not to say that it can’t be done at all, of course, but great care must be taken with unproven techniques, technologies, etc). His approach with JSF 2 was to look at the field of web application frameworks and see what works and what doesn’t, and what might be a good addition to JSF. With that approach in mind, is DWR-like functionality a good candidate for JSF 2.next? Please feel free to comment below. While I await responses, we’ll see if I can hammer out a proof-of-concept in the Mojarra tree. :) ### [Mojarra 1.2_15 Now In Maven Repo](/2010/mojarra-1-2_15-now-in-maven-repo/) Mojarra 1.2_15 Now In Maven Repo Way back in July, Ed Burns released and announced Mojarra 1.2_15, which is mostly a backport of performance fixes from the 2.0 branch. Given recent changes on the Mojarra team1, there was some confusion and difficulty getting the jars published to the java.net Maven repository. I’m happy to report, though, that we’ve gotten those kinks worked out, and that this new release of the 1.2 branch of Mojarra is now available for your Mavenized pleasure. Note that this is the Maven 1 repository, and it’s not in central. Those are separate issues on which we’re still working. 1 Many, many thanks to you, Ryan, for all of your hard work over the years, and best of luck in your new position. :) ### [Book Review: JSF 2.0 Cookbook](/2010/book-review-jsf-2-0-cookbook/) Book Review: JSF 2.0 Cookbook image::https://www.packtpub.com/sites/default/files/imagecache/productview/9522.jpg Packt Publishing recently released a book titled JSF 2.0 Cookbook, by Anghel Leonard. When I first heard about this book, I was really anxious to get my hands on it. I really like the cookbook concept, so I was excited to see a work in that vein published for JSF. Packt recently sent me a copy to review, so, having read most of the book, here are my thoughts. First off, I’ll be upfront: I have not read the whole book, but I don’t think that’s a problem. Cookbooks aren’t meant to be read cover to cover, necessarily. While you can certainly do that, these types of books are intended to be a reference. When you have an issue, you look in the table of contents to find the "recipe" that covers your issue, and jump to that page. That’s what I did with this book, mostly. I looked up the recipes for issues I most often have trouble with. I did, though, read almost all of the custom component chapter, as that’s area that holds a lot of interest for me. I’ll give that one special attention in a moment. Each recipe, follows the same basic pattern. It starts with a basic summary of the problem, then goes in to "Getting ready," "How to do it…​," "How it works…​" and "See also." There are minor deviations along the way, but that’s the basic gist. In the Getting Ready section, the author details how the recipe was created (NetBeans 6.8, Mojarra 2.x, and GlassFish v3, showing the author has great tastes : ), so new users can get a sense of what might help work through the recipe. The How to do it section is pretty detailed, with LOTS of source code. Much of the markup is still using JSP, which is a shame since JSP is all but formally deprecated with JSF 2.0 (Facelets being the de facto standard), but you shouldn’t have any major issues applying what you see to a Facelets page. The How it works section that follows does a great job of explaining…​err…​ how it works, which I think is really important. How to do something is rarely enough. If you understand why to do something and how that something works, you’ll be better equipped in the future for similar, but slightly different issues. This section does a good job of that. The only area of the book I want to comment on specifically is Chapter 5, Custom Components. Of all the areas in JSF, component authoring has always been a favorite of mine. I am far from being a leading expert, but I’m pretty comfortable with it and really enjoy it. Chapter 5, then, was one of the first things I turned to. The author does a great job of giving a variety of examples using validators, ajax, etc. A big glaring flaw for me, though, was the discussion of the JSF lifecycle, a very important topic for component authors. In the graphic on page 130, encoding is shown as happening in the Apply Request Values Phase, and decoding is shown as happening in the Render Response Phase. Unless I’m sorely mistaken, that’s exactly backwards. Despite that error, the chapter itself is extremely helpful. I would advise, though, that if you are looking to learn component development, to try JavaServer Faces 2.0: The Complete Reference by Ed Burns, and Chris Schalk, or Core JSF by David Geary and Cay Horstmann. That’s not to belittle this book in anyway. The Geary/Hortsmann and Burns/Schalk books are meant for different purposes. JSF 2.0 Cookbook has a slightly different purpose, which is complementary to the first two, and which it does well, I think. Overall, I think this is a really good book. Though not perfect, it provides a lot of value to the JSF developer. From beginner to expert, I think there is enough in this book to help just about everyone out of a jam from time to time. ### [GlassFish Administration: The REST of the Story Part I](/2010/glassfish-administration-the-rest-of-the-story-part-i/) GlassFish Administration: The REST of the Story Part I Of the many great things about GlassFish, one that is often mentioned most (and is, in fact, what got me involved with GlassFish as an end user years ago) is the Administration Console. It’s an extremely powerful and capable interface, and is, if I may be so bold, orders of magnitudes better than its open source competition (it may even beat commercial competitors, but I have no experience with those). Another powerful tool in GlassFish administration is the asadmin CLI utility, which allows for quick and easy scripting of server provisioning, etc. Did you know, though, that GlassFish has a third administration interface? As of GlassFish v3, we offer a RESTful administration API, based on Jersey, to allow non-Java clients to configure the app server easily. For GlassFish 3.1, one of my main responsibilities, with the help, I should add of my coworkers Ludovic Champenois and Mitesh Meswani, has been to help improve upon the great start we had in in v3. In this entry, we’ll take a look at the current state of the interface and learn the basics of using. The Basics I don’t want to go too far into the weeds explaining what REST is, so for those of you new to the concept, you can get a high level overview at Wikipedia. Go ahead and read it. We’ll wait. Everyone back? Great! :P The GlassFish RESTful Administration API (aka, the REST API/interface) can be found at http://localhost:4848/management/domain for configuration-related activities, and http://localhost:4848/monitoring/domain for monitoring-related activities. For this entry, we’ll not do anything with the monitoring side other than mention that it’s there. The REST API supports three different response encodings (yes, I’m aware of how dangerously overloaded that term is : ): HTML, JSON, and XML. Which type to use is determined using the Accept header, but can be overridden by using an extension on the URL (.html, .json, or .xml). Let’s take a quick look at what the return looks like. The Request The request payload is typically what you would see with an HTML form submission. For example, this curl example sets the port for http-listener-1, which is the listener that serves your applications: curl -H "__debug: true" -H "Accept: application/json" -X POST -d "port=8675" http://localhost:4848/management/domain/configs/config/server-config/network-config/network-listeners/network-listener/http-listener-1 which will return this document (edited for brevity): { "message":"\"http:\/\/localhost:4848\/...\/http-listener-1\" updated successfully.", "exit_code":"SUCCESS", "properties":{ }, "extraProperties":{ } } There are places where the payload is a bit more complex of necessity (such as properties), but I’ll cover those in another post. The Response Early on, the structure of the document the REST interface could vary depending on how the endpoint resource was implemented (more on the later). In this cycle, we’ve done a lot of work to standardize on one format, which I’ll describe here, but be aware you may still see non-compliant response documents. If you do, it’s a bug and we’d appreciate it if you could open an issue. :) The structure, then, is an object with the following fields: message, command, exit_code, properties, and extraProperties. An example is often best, so here’s the three representations of the endpoint http://localhost:4848/management/domain/: JSON { "command": "Domain", "exit_code": "SUCCESS", "properties": {}, "extraProperties": { "commands": [ { "path": "create-instance", "command": "create-instance", "method": "POST" }, // ... ], "methods": [ {"name": "GET"}, { "name": "POST", "messageParameters": { "applicationRoot": { "optional": "true", "type": "string", "key": "false" }, // ... } } ], "entity": { "applicationRoot": "$\{com.sun.aas.instanceRoot}\/applications", "locale": "en", "logRoot": "$\{com.sun.aas.instanceRoot}\/logs", "version": "jasonlee-private" }, "childResources": { "amx-pref": "http:\/\/localhost:4848\/management\/domain\/amx-pref", // ... } } } XML <?xml version="1.0" encoding="UTF-8" standalone="no"?> <map> <entry key='extraProperties'> <map> <entry key='methods'> <list> <map> <entry key='name' value='GET'/> </map> <map> <entry key='name' value='POST'/> <entry key='messageParameters'> <map> <entry key='applicationRoot'> <map> <entry key='optional' value='true'/> <entry key='type' value='string'/> <entry key='key' value='false'/> </map> </entry> </map> </entry> <!-- ... --> </map> </list> </entry> <entry key='entity'> <map> <entry key='applicationRoot' value='$\{com.sun.aas.instanceRoot}/applications'/> <entry key='locale' value='en'/> <entry key='logRoot' value='$\{com.sun.aas.instanceRoot}/logs'/> <entry key='version' value='jasonlee-private'/> </map> </entry> <entry key='commands'> <list> <map> <entry key='command' value='create-instance'/> <entry key='path' value='create-instance'/> <entry key='method' value='POST'/> </map> <!-- ... --> </list> </entry> <entry key='childResources'> <map> <entry key='resources' value='http://localhost:4848/management/domain/resources'/> <!-- ... --> </map> </entry> </map> </entry> <entry key='message'/> <entry key='exit_code' value='SUCCESS'/> <entry key='command' value='Domain'/> </map> HTML The Details --- As you can see from these trimmed down version, there’s quite a bit of data there. For the most part (though we still have areas we need to clean up), the data you will be most interested in as an end user will be under 'extraProperties'. This property is an object that lists the various HTTP methods the endpoint supports, giving information on parameters it supports; the entity’s state, if there is any (more on that later); any commands nested under this endpoint (more on that later as well); and any child resources this resource may have. It’s worth noting that the documents you see above were pretty-printed by the server, a feature that is off by default. To enable this feature, the HTTP Accept header __debug must be set to true. If this header is not present, or if the value is not 'true', the server will not format the document. In this case, the unformatted JSON document is just over half the size of the pretty-printed one, resulting in much less going over the wire, an important production consideration. Quack! Quack! WADL! WADL! What’s a REST service with a WADL document describing it? Since the REST interface is Jersey-based, we get that for free. It can be found at http://localhost:4848/management/application.wadl. Be careful, though, because it’s BIG. :) You put your module in. You take your module out! Those of that have been following GlassFish for a while may remember the big deal we made about the dynamic nature of v3. Jerome Dochez stood on the stage at JavaOne and showed an EJB-less GlassFish container start up, and then refuse to deploy an EJB app, because it didn’t support them. He then added the require jars, and with the black magic help of OSGi, the server suddenly supported EJB deployments. Really slick. One of the issues we tackled on the REST side, though, was how to handle the addition and removal of these modules. Making matters more difficult, we didn’t want to require third party module developers to worry about REST when writing their add-ons. Enter asm, stage right. Thanks to hard work of Mitesh and Ludo, the REST endpoints you see in the server are completely dynamic. The REST module itself is lazily loaded, so you don’t have to pay that penalty as the server starts, but, once it starts, it analyzes what is in memory (i.e., the HK2 DOM hierarchy) and generates and registers REST endpoints on the fly. What this means for third party developers is that as long as they’re using HK2 and domain.xml to manage their config, they get REST endpoints for free. It also means that a web profile GlassFish installation isn’t exposing useless endpoints. Summary This ended up being much longer than I had intended, but here’s the take away. GlassFish offers three ways to administer the server: the web-based console, the command line-based asadmin utility, and HTTP-based REST interface. Using one or more of those means you will likely never have to look at an XML file, and that ain’t bad. :) In future posts in what I intend to be a series, we’ll take a look at specific use cases using the REST interface. ### [Book Review: JSF 1.2 Components](/2010/book-review-jsf-1-2-components/) Book Review: JSF 1.2 Components Some time ago, I was given a copy of JSF 1.2 Components by Ian Hlavats and asked if I’d write a review for it. It’s long overdue, but here are my thoughts on this book. <img src="http://ecx.images-amazon.com/images/I/51WxF2r1EEL.SL500_AA300.jpg" align="right"/>First off, in case you’re guessing, like I did, based on the title, that this is a book about writing JSF 1.2 components, it’s not. It’s book about some existing JSF 1.2 component libraries. So if you need the former, I would suggest http://www.amazon.com/JavaServer-Faces-2-0-Complete-Reference/dp/0071625097/ref=sr_1_2?ie=UTF8&s=books&qid=1276116885&sr=8-21 or http://www.amazon.com/Core-JavaServer-Faces-David-Geary/dp/0137012896/ref=sr_1_1?ie=UTF8&s=books&qid=1276116930&sr=8-11. That said, what this book does offer is a nice overview/introduction to a number of different components including the standard JSF components and those from a number (five, to be exact) third party component sets. One of the things I liked about the book is that it starts off with a nice, light overview of JSF. Introductions to JSF usually seem to get mired in detailed discussions of the JSF lifecycle. While that’s important to know, it can also be very overwhelming for new users. I think this introduction did a credible job while avoiding that pitfall. The first two chapters, in addition to this introduction, covered the standard component set as well as the de facto standard Facelets. The next few chapters cover some of the more prominent components of Tomahawk, Trinidad, ICEfaces, Seam, and RichFaces. Overall, I found the introduction to be fairly well done, though I had some minor quibbles. The biggest was the apparent mismatch between the code in the book and the images to support it. In several places, it seemed the screen shot simply didn’t match the code sample, which is a bit confusing until I finally decided it was just the wrong graphic. The Seam chapter seemed (no pun intended ; ) a bit strange, as the Ajax4Jsf discussion probably should have been in the RichFaces chapter, and the conversation scope isn’t technically a component, but it would be pedantic of me to point that out. :) The book closes with a brief introduction to the new features in JSF 2. I thought this was pretty well done and should whet the appetites of those who have not yet made the switch to the new spec. Overall, I’d have to give the book, say, 3.5 out of 5 stars. Though not perfect, it’s a nice overview of the major JSF component sets. While you can find all that information somewhere on the web (which is true of just about everything in a tech book these days), JSF 1.2 Components provides this information in one place in a fairly easy to read setting. Those with a lot of experience with third party component sets may not get much out of the book, but beginning to intermediate JSF users should find a good deal of value in it. 1 I realize that, in the context of a discussion of a book about JSF 1.2, that I linked to two texts discussing JSF 2.0. This is intentional. Core JSF 2ed does not seem to be available any longer (at least at the time of writing this, it was unavailable on Amazon), and it makes little sense to buy older versions of the book. Both books cover the 1.2 and 2.0 versions of the spec, and The Complete Reference is especially good about noting the differences in the two specs. I have both books, and have read both of them (Note: I work with Ed Burns and was a reviewer for David Geary), and can comfortably recommend both books. If you need a fuller treatment of JSF, as of now, these are the go-to books. You should buy at least one copy of each. :) ### [Putting Facelets in a Jar](/2010/putting-facelets-in-a-jar/) Putting Facelets in a Jar In a recent forum post, a user asked how to store a Facelets file in a database. Although JSF doesn’t support this out of the box (though it would be a nice feature), it’s not too difficult to add. In this entry, I’ll show you how to serve Facelets from a JAR file, then give some thoughts that will help, I hope, implement a database-backed approach. I’ll be using JSF 2, so if you’re using Facelets 1.x with JSF 1.2, you’ll have to extend com.sun.facelets classes to make this work in that environment. With that out of the way, unto the breach! To implement this solution, we’ll need to provide JSF with three artifacts: and ExternalContextFactory, an ExternalContext, and a ResourceResolver. ExternalContextFactory The ExternalContext "allows the Faces API to be unaware of the nature of its containing application environment. In particular, this class allows JavaServer Faces based appications to run in either a Servlet or a Portlet environment." JSF creates the ExternalContext by means of an ExternalContextFactory. Since we’re providing a custom ExternalContext, we must provide an ExternalContextFactory, which is really quite simple: public class MyExternalContextFactory extends ExternalContextFactory { private ExternalContextFactory parent; public MyExternalContextFactory (ExternalContextFactory parent) { super(); this.parent = parent; } @Override public ExternalContext getExternalContext(Object context, Object request, Object response) throws FacesException { return new MyExternalContext(getWrapped().getExternalContext(context, request, response)); } @Override public ExternalContextFactory getWrapped() { return parent; } } This factory decorates any existing ExternalContextFactory, returning the custom ExternalContext we’ll see now. ExternalContext As we noted briefly above, the ExternalContext is an abstraction over either a ServletContext or a PortletContext (in theory, an ExternalContext implementation could also wrap BillyBobsRubyThingamajig if one were so inclined to write one). The function of the ExternalContext for our purposes here is to allow JSF to ask its external context for a URL to the resource requested by the client, and that’s why we have to override this class. Since the default ExternalContext looks in the document root of the web app for a resource, and since we’re not storing some/any of our Facelets in the document root, we have to change the look up logic. However, there will likely still be at least <em>some</em> resources in the doc root, so we look first in the classpath for the resource. If that lookup fails, we call the wrapped ExternalContext, whatever it is, and let it take things from there. That code, then, might look something like this: public class MyExternalContext extends ExternalContextWrapper { private ExternalContext wrapped; public MyExternalContext(ExternalContext wrapped) { this.wrapped = wrapped; } public URL getResource(String path) throws MalformedURLException { System.out.println("Looking for " + path); URL url = Thread.currentThread().getContextClassLoader().getResource(path.substring(1)); if (url == null) { url = getWrapped().getResource(path); } return url; } @Override public ExternalContext getWrapped() { return wrapped; } } The interesting method here is getResource(String). We interrogate the classpath for the resource (minus the leading '/' — that code should probably be more robust than it is), then fallback to the wrapped/decorated ExternalContext on a lookup failure. In the end, we return the URL even if it’s null. If we don’t override this class, the default ExternalContext will look in the document root, not find the resource we want, and return null, which will result in a 404 for the user, which is clearly not what we want. : ) With that done, we come to the final piece of the puzzle, the ResourceResolver. ResourceResolver The ResourceResolver provides "a hook to decorate or override the way that Facelets loads template files." Sadly, this class looks a lot like the custom ExternalContext from above: public class MyResourceResolver extends ResourceResolver { private ResourceResolver parent; public MyResourceResolver(ResourceResolver parent) { this.parent = parent; } @Override public URL resolveUrl(String path) { URL url = null; try { url = url = Thread.currentThread().getContextClassLoader().getResource(path.substring(1)); if (url == null) { url = parent.resolveUrl(path); } } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } return url; } } Eerily familiar, isn’t it? It’s certainly possible that this redundant code could be reduced or removed altogether, but I haven’t found a way. If you do, please let me know. : ) With our artifacts coded, we now need to tell JSF to use them. That’s done in faces-config.xml (one of the few places where XML is still needed): <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <factory> <external-context-factory>com.foo.MyExternalContextFactory</external-context-factory> </factory> </faces-config> We also need a context parameter to tell Facelets to use our new ResourceResolver: <context-param> <param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name> <param-value>com.foo.MyResourceResolver</param-value> </context-param> But what about the database? At this point, it should be pretty clear how to pull things from the database, at least in general (WARNING: I’ve not actually tried this, so I’m shooting from the hip). The problem as I see it is the use of URLs in the various APIs. Since java.net.URL is final, you can’t subclass it with something smart enough to know how to get its contents from a database. That leaves (again, from the hip) caching the item to disk (in the ResourceResolver) and returning a URL to that (make sure to call File.deleteOnExit()! ;). Perhaps there’s a better solution, and I hope there is, but I’ll leave that as an exercise for the reader. Unless you get really stuck, then I’ll try to find time to create a complete, working solution. ### [GlassFish Roadmap](/2010/glassfish-roadmap/) GlassFish Roadmap There has been a lot of speculation and concern about the fate of GlassFish after the Oracle acquisition. Yesterday, though, we were able to unveil the official roadmap for GlassFish, and I think it looks very promising. In short, not much is going to change with regard to the open source side of things, though there are some changes on the commercially supported offering, which is not unexpected. Some of the highlights include: GlassFish 3.0.1 - 2010 Branding and patches</li> Multi-lingual release</li> Value-added features for Oracle GlassFish Server</li> Base interop w/Oracle Middleware products</li> GlassFish 3.1 - 2010 Centralized administration of cluster</li> HA/state replication</li> Value-added features like Coherence Support</li> GlassFish 3.2 - 2011 Improved cluster/HA admin</li> Better integration with Oracle Identity Management</li> Virtualization support</li> Some Java EE 6 spec updates plus some Java EE 7 EA specs</li> GlassFish 4 Common server platform - shared best-of-breed with WebLogic Server</li> Java EE 7</li> For a more complete picture, see the slide deck here. ### [Writing Selenium Tests for the GlassFish Admin Console](/2010/writing-selenium-tests-for-the-glassfish-admin-console/) Writing Selenium Tests for the GlassFish Admin Console One of the results of the Oracle purchase of Sun has been an increased focus on testing — not that we didn’t test GlassFish before, but it was mostly manual in my area of the server. The task of automating this fell to me, and, after a little — ahem — testing, I settled on Selenium. For those that don’t know, Selenium is a web application testing tool. It has a number of different modules, including the Selenium IDE, which is used to help write tests, and Selenium RC to run the tests. Selenium server, which actually interacts with the browser, is, for us, a transitive dependency through RC. At any rate, I’ve been working on a number of tests for the GlassFish Admin Console to try to cover as much of what we currently have running as possible. At some point, I need to get out of writing tests and back to writing code, so I need to document what I’ve done, which is where this post comes in. I started out writing a step-by-step tutorial on how I use Selenium, but that was almost guaranteed to be hard to follow, so I created a screencast (using screencast-o-matic, incidentally, which is a Java-based tool. It runs on any platform, with no installation required. It’s pretty slick : ). What you’re about to see, then, is a demonstration of how I’ve written the 40+ tests we have so far. Nothing says this is the only way to do it, but I’ve found it pretty fast and effective. Without further ado, then, I present the Jason Lee masterpiece, /videos/GlassFishSeleniumTestCreation.flv Instant classic! ### [Run GlassFish V3 As a Non-Root Service on Gentoo Linux](/2010/run-glassfish-v3-as-a-non-root-service-on-gentoo-linux/) Run GlassFish V3 As a Non-Root Service on Gentoo Linux Byron Nevins, a colleague of mine here at Oracle, has a couple of nice blog entries showing how to run GlassFish as a service, both as root and non-root users, on Ubuntu or Debian. As a Gentoo user, that doesn’t help me much, unfortunately, but, some time ago, I developed a script that works great for me, so I thought I’d share it here. To make things a bit easier, go read Byron’s non-root user entry (changing the install location to /opt/glassfish unless you want to edit the script below), and stop at step 5. I’ll wait. All done there? Ok, great! As the root user (or a user with appropriate privileges), create the file /etc/init.d/glassfish and paste the following script into it: #!/sbin/runscript depend() { need net } start() { ebegin "Starting glassfish" # Ensure that we run from a readable working dir, and that we do not # lock filesystems when being run from such a location. cd / start-stop-daemon --start --quiet --background --make-pidfile --pidfile /var/run/glassfish.pid --exec /usr/local/bin/gf_start eend $? } stop() { ebegin "Stopping glassfish" /usr/local/bin/gf_stop eend $? } restart() { if ! service_stopped "$\{SVCNAME}" ; then svc_stop || return "$?" fi svc_start } I actually use a couple of scripts, as you might see there, to help manage my GlassFish instance, as I run this on my "dev" box. Those two scripts are /usr/local/bin/gf_start: #!/bin/bash su -c '/opt/glassfish/server/bin/asadmin start-domain' glassfish and /usr/local/bin/gf_stop: #!/bin/bash su -c '/opt/glassfish/server/bin/asadmin stop-domain' glassfish Once those files are in place (and paths are updated), test the script (/etc/init.d.glassfish start) to make sure everything is working as expected. Once you’re happy with it, you can register the service to start at system boot by issuing the command rc-update add glassfish default. The next time your system starts, GlasssFish will be patiently waiting for you on port 8080. If you’d like, you can now issue the iptables commands that Bryon lists to redirect port 80 to 8080. I haven’t done that because I actually front GlassFish with Apache as I have other sites listening on 80 and uses virtual hosts to sort them all out, but that’s another topic altogether. :) I hope that helps. ### [New Components in Mojarra Scales: Part III – sc:imageZoomer and sc:lightbox](/2010/new-components-in-mojarra-scales-part-iii-sc-imagezoomer-and-sc-lightbox/) New Components in Mojarra Scales: Part III – sc:imageZoomer and sc:lightbox In Part II of this series, I introduced the new auto complete component in Mojarra Scales. In this installment, we’ll take a look at two new closely related components, sc:imageZoomer and sc:lightbox. The first component, sc:imageZoomer, displays a thumbnail, and, when clicked, "zooms" that thumbnail up to the full size image. Here is a sample usage: <sc:imageZoomer thumb="#\{request.contextPath}/images/thumbs/image1.jpg" image="#\{request.contextPath}/images/image1.jpg" caption="Some descriptive caption"/> Given the active nature of the component, a screen shot wouldn’t be that interesting, so to see it in action, point your browser at the Image Zoomer demo. The next component is sc:lightbox. Chances are good that you’ve seen a lightbox before. When an image is clicked, it "zooms" up, and navigation is offered to go to the previous or next image in the group. While using the lightbox library linked above has never been tedious to use, Mojarra Scales makes it even easier now: <sc:lightbox id="lightbox2"> <h:outputLink id="boxer1" value="images/boxers/Boxer1.jpg" > <h:graphicImage value="images/boxers/tBoxer1.jpg" alt="Good looking dog (demo 2)"/> </h:outputLink> <h:outputLink id="boxer2" value="images/boxers/BoxerFace.jpg"> <h:graphicImage value="images/boxers/tBoxerFace.jpg" alt="Only a mother could love that face. (demo 2)"/> </h:outputLink> </sc:lightbox> The sample above puts two images on the page, adding them to the "lightbox2" group. To use the lightbox inside another component, say sc:carousel, your markup may look something like this: <sc:carousel id="carousel1" numVisible="4" isCircular="true" isVertical="false"> <h:outputLink value="images/boxers/Boxer1.jpg" rel="lightbox[boxers]"> <h:graphicImage value="images/boxers/tBoxer1.jpg" alt="Good looking dog"/> </h:outputLink> <h:outputLink value="images/boxers/BoxerFace.jpg" rel="lightbox[boxers]"> <h:graphicImage value="images/boxers/tBoxerFace.jpg" alt="Only a mother could love that face."/> </h:outputLink> <h:outputLink value="images/boxers/DogGoat.jpg" rel="lightbox[boxers]"> <h:graphicImage value="images/boxers/tDogGoat.jpg" alt="Best of friends?"/> </h:outputLink> <h:outputLink value="images/boxers/boxer-pup.jpg" rel="lightbox[boxers]"> <h:graphicImage value="images/boxers/tboxer-pup.jpg" alt="In the sandbox"/> </h:outputLink> <h:outputLink value="images/boxers/boxer-dog.jpg" rel="lightbox[boxers]"> <h:graphicImage value="images/boxers/tboxer-dog.jpg" alt="Fun-loving dogs"/> </h:outputLink> <h:outputLink value="images/boxers/stonewall.gif" rel="lightbox[boxers]"> <h:graphicImage value="images/boxers/tstonewall.gif" alt="Boxers are intelligent and curious"/> </h:outputLink> </sc:carousel> <sc:lightbox id="lightbox1" group="boxers"/> Notice that we created the carousel as we normally would, but we added the rel attribute to the h:outputLink components, then we create the lightbox and specify the group to use. The lightbox JavaScript will gather all of the links with rel="lightbox[boxers]" and add them to the image group. I’m sure you’ve noticed that the actual image and link construction has to be done manually. A new component will be added shortly to do that work for you. I’m still working through how that should look, but as soon as it’s ready, I’ll let you know here. Like sc:imageZoomer, a screen shot wouldn’t do this component justice, so please take a look at the demo application to see the lightbox in action. As a side note, I’d like to point out that this lightbox implementation is 100% custom, YUI-based code. While the behavior and appearance of the widget was influenced by (read as, lifted from : ), the implementation linked above, I wanted to reduce, as much as possible, the number of external libraries Mojarra Scales ships with, so I wrote this implementation. I also got the boxer images from Google Images (my wife and I have a Boxer named Sadie, who is our third Boxer, after Bosco and Abby : ). If you stumble across this and find an image of yours that you want removed, please let me know. :) As always, if you notice any bugs or deficiencies, or if there’s a feature you’d like to see, please feel free to file an issue. ### [New Components in Mojarra Scales: Part IV – sc:combo](/2010/new-components-in-mojarra-scales-part-iv-sc-combo/) New Components in Mojarra Scales: Part IV – sc:combo Yesterday brought us Part III in our look at some new components in Mojarra Scales. Today, Part IV brings us sc:combo, combination, if you can imagine that, of a h:selectOneMenu and h:inputText. The h:selectOneMenu is a nice control as it allows the application author to limit what the user can enter, thus helping insure data integrity (and sanity). Sometimes, though, it would be nice to offer a list of options for the user, but allow him to enter any arbitrary alternative. Unfortunately, the HTML spec doesn’t offer this kind of control. Lucky for us, though, this is fairly easy to implement using some of the nice JavaScript widgets provided by YUI. Here’s a sample: <sc:combo id='combo' style='width: 500px' value='#\{comboBean.value}'> <f:selectItems value='#\{comboBean.selectItems}'/> </sc:combo> This should look very familiar to anyone who has used any of the selection components in JSF (h:selectBooleanCheckbox, h:selectManyCheckbox, h:selectManyListbox, h:selectManyMenu, h:selectOneListbox, h:selectOneMenu, or h:selectOneRadio). About the only change is the name of the parent tag. Rendered, you should see something like this: As the user keys in his choice, should he choose to do so, type-ahead will attempt to complete his entry for him from the available options. If one is not found, though, the user is free to enter what he desires. In the next installment, we’ll take a look at sc:resize, a component that adds resizing capabilities to another control on the screen. ### [A Comparison Table of 4 Android Phones](/2010/a-comparison-table-of-4-android-phones/) A Comparison Table of 4 Android Phones I’ve been an iPhone user for about 1.5 years now. I’m mostly happy with it, but I’d kinda like to write applications for it. The problem, though, is that the iPhone uses Objective-C (and I don’t consider writing web apps the same thing as writing an iPhone app ; ). Enter Google’s Android. I can use my existing Java knowledge to write applications for an Android device, giving me a much smaller learning curve. The question, then, is which device should I get? There are several available, unlike the iPhone, so the choice can be difficult. Recently, I ran across 6 of the Best Android Mobile Devices, which has a pretty nice run down of six different devices, not all of which are phones. The problem with this particular comparison, was that each phone was on a different page, making comparison more difficult as I had to switch tabs a lot. My solution, then, is the table below. Inspired by the link above, though taking most of the data from the devices' product pages, I’ve compiled the following table. Obviously, this isn’t every Android phone on the market. I took the three listed in the article above, and added one other phone that I’ve been considering. Hopefully this table will be helpful in those looking at these devices. Feature/Device Nexus One Droid Eris Hero Processor Qualcomm QSD 8250 1 GHz ARM Cortex A8 600MHz (underclocked to 550MHz) Qualcomm® MSM7600™, 528MHz Qualcomm® MSM7200A™, 528 MHz Screen 3.7-inch WVGA AMOLED 800 x 480 TFT 3.7-in. ; WVGA (480 x 854 pixels) 3.2-inch 320 x 480 HVGA 3.2-inch TFT-LCD 320x480 HVGA Memory 512MB Flash ; 512MB RAM ; 4GB microSD (expandable to 32GB) 16 GB microSD pre-installed 512MB ROM / 288MB RAM ROM: 512MB RAM 288MB Network UMTS Band 1/4/8 (2100/AWS/900) ; HSDPA 7.2Mbps ; HSUPA 2Mbps ; GSM/EDGE (850, 900, 1800, 1900 MHz) 2G Network : GSM 850/900/1800/1900 ; 3G Network : HSDPA 900/2100, HSDPA 850/1900/2100 CDMA: Dual-band 800/1900MHz ; CDMA2000 1xRTT/1xEVDO rev. A HSPA/WCDMA 900/2100 MHz ; Quad-band GSM/GPRS/EDGE 850/900/1800/1900 MHz Hardware Keyboard? No Yes No No GPS? Yes Yes Yes Yes Camera 5MP auto-focus ; 2x digital zoom ; LED flash ; geo-tagging ; Video captured at 720x480 pixels at 20 frames per second or higher 5MP ; 4x digital zoom<br>dual LED flash ; automatic focus ; geo tagging ; DVD quality video capture (720x480 resolution) up to 24 fps capture ; up to 30 fps playback 5.0 MP w/ Auto Focus 5.0 megapixel color camera with auto focus Connectivity WiFi (802.11 b,g) ; Bluetooth + EDR ; A2DP stereo Bluetooth WiFi (802.11 b,g) ; Bluetooth + EDR WiFi (802.11 b,g) ; Bluetooth + EDR WiFi (802.11 b,g) ; Bluetooth + EDR Support Audio Formats AAC LC/LTP, HE-AACv1 (AAC+), HE-AACv2 (enhanced AAC+), AMR-NB, AMR-WB 9, MIDI SMF (Type 0 and 1), DLS Version 1 and 2, XMF/Mobile XMF, RTTTL/RTX, OTA, iMelody, Ogg Vorbis, WAVE (8-bit and 16-bit PCM) AAC, MP3, WAV, WMA, OGG, eAAC+, AMR WB, AMR NB, AAC+, MIDI MIDI, M4A, QCP, AMR, AAC, AAC+, eAAC+, WAV, WMA, MP3, EVRC-B MP3, AAC(AAC, AAC+, AAC-LC), AMR-NB, WAV, MIDI and Windows Media® Audio 9 Support Video Formats H.263, MPEG-4 SP, H.264 AVC H.263, H.264, MPEG-4 MPEG4, H.263, H.264, WMV MPEG-4, H.263, H.264 and Windows Media® Video 9 Expansion Slots SIM card slot ; microSD slot microSD microSD microSD Battery Life Standby time: Up to 290 hours on 2G; Up to 250 hours on 3G Talk time: Up to 10 hours on 2G; Up to 7 hours on 3G Internet use: Up to 5 hours on 3G; Up to 6.5 hours on Wi-Fi Video playback: Up to 7 hours *Audio playback Up to 20 hours Standby – up to 270hrs ; Talk – up to 6:25 Standby: 373 hrs ; Talk time: 214 min Standby time: Up to 750 hours for WCDMA; Up to 440 hours for GSM Talk time: Up to 420 minutes for WCDMA; Up to 470 minutes for GSM Weight 4.56 oz/130g 5.96 oz/169g 4.23 oz/120g 4.76 oz/135ga Size 4.64 x 2.35 x .45 in ; 118 x 59.8 x 11.5 mm 2.4 x 4.6 x .5 in ; 60 x 115.8 x 13.7 mm 4.45 x 2.19 x .51 in ; 113 x 55.6 x 13 mm 4.41 x 2.21 x 0.57 in ; 112 x 56.2 x 14.35 mm Other features Haptic feedback ; Second microphone for active noise cancellation ; Proximity sensor ; Light sensor ; Digital compass Flash-enabled G-sensor ; Digital compass I am in no way a cell phone expert. I merely combined the data that seemed important to me in this table to help in my decision-making. This table may be completely useless to anyone but me. Since I had it, though, I thought I’d share it. If you don’t like it, well, it was free. :) ### [Merry Christmas!](/2009/merry-christmas/) Merry Christmas! As 2009 winds down to a close, it is my hope that you and your family have a very merry Christmas. It is my prayer that in the hustle and bustle of the season, the real meaning — the birth of the Savior of the world, Jesus Christ — is not lost: Do not be afraid. I bring you good news of great joy that will be for all the people. Today in the town of David a Savior has been born to you; he is Christ[a] the Lord. — Luke 2:10-11 ### [New Components in Mojarra Scales: Part II – sc:autoComplete](/2009/new-components-in-mojarra-scales-part-ii-sc-autocomplete/) New Components in Mojarra Scales: Part II – sc:autoComplete In Part I, I introduced the new YUI-backed Scales dataTable component. In this installment in the series, we"ll take a look at another new component available in Scales 2.0, sc:autoComplete. The auto-complete component is likely very familiar to most seasoned web users. As information is typed into a field on the form, suggestions are displayed in a box that appears below the input field. The user is then free to select one of these options or to continue entering his value of choice. To put such a component on the web page using Mojarra Scales, a component similar to the following can be used: <sc:autocomplete animate="both" id="autoComplete" suggestions="#\{autoCompleteBean.autoCompleteValues}" typeAhead="true" value="#\{autoCompleteBean.value}" width="300px"/> This example will create an input that is 300 pixels wide, has a suggestion box whose appearance is animated in both directions, and allows type ahead — meaning the component will auto-fill the field with the first result, allowing the user to tab away to automatically select that value or continue typing. The ValueExpression suggestions is what the component uses to retrieve the appropriate set of suggestions. In our simple example, the implementation looks like this: public List autoCompleteValues(String query) { List values = new ArrayList(); for (String word : words) { if (word.startsWith(query)) { values.add(word); } } return values; } Elsewhere in the bean, we have a static String[] with all of the possible values. We then iterate over this list, finding words that start with the value the user has entered. For each hit, we that to a List, which we then return to the client. It"s probably not the most efficient implementation, but should serve to demonstrate the use. On the page, this component will look something like this: In the next installment, we"ll take a look at two image components, sc:imageZoomer and sc:lightbox. Until then, please feel free to experiment with sc:autoComplete. If you notice any bugs or deficiencies, or if there"s a feature you"d like to see, please feel free to file an issue. ### [GlassFish v3 Virtual Conference](/2009/glassfish-v3-virtual-conference/) GlassFish v3 Virtual Conference This is a little late notice, but we at Sun are holding a "virtual conference" covering GlassFish v3, Java EE 6, etc. You can find details here. It starts in 30 minutes (10:00 CST, 8:00 PST). :) ### [GlassFish v3 Is Now Available](/2009/glassfish-v3-is-now-available/) GlassFish v3 Is Now Available Today, the GlassFish team is pleased to announce the release of GlassFish v3. This release marks the first production-ready release of a Java EE 6 compliant application server. It also marks the culmination of a tremendous engineering effort to transform the very capable but monolithic GlassFish v2 into a small, sleek and scalable modular system, built on OSGi. You can get all the details over at The Aquarium. Of all the features in this release, the two I’m the proudest of are the console, on which I work during the day, and JSF 2, on which I work when I can. The console, while it looks similar to that in v2 (somewhat by design), has undergone a pretty serious makeover. We’ve removed the frameset, which solved a number of issues on both the client and the server, we introduced the use of the YUI LayoutManager to help with the page layout, and we implemented Ajax-based navigation (which was one of my major tasks, along with Ken Paulsen). The result is, I think, a lighter, faster console. It posed some interesting challenges, but I think we were able to work everything out to make a very nice and snappy console. We’re not resting on our laurels, though. Like the rest of the server, our team has some grand plans for upcoming releases in the console. On the backend, we had to do a fair amount of rework to accomadate all the changes made to support the modularity introduced for v3. For example, as we demonstrated at a Hands-on-Lab at JavaOne, the console is pluggable, which allows developers, OEMs, admins, etc to create and install plugins that add functionality to the console. In fact, that’s how we delivered all of the non-core functionality in the console. If you’re running the web profile, you won’t see anything JMS-related, for instance. The other feature I’m pretty proud of is JSF 2. As an Expert Group member and sadly not-too-active-committer (at the moment) on Mojarra, the JSF implementation we ship with GlassFish, I’m really, really pleased with how JSF 2 turned out. In what spare time I can find, I’ve been doing some application development as well as component development using the new spec, and it’s been a joy to work with. From annotations to composite components and more, JSF 2 is just really easy to work with (I hope to blog more on that in the near future). In addition to those, v3 offers CDI (via Weld), JPA 2, EJB 3.1, Servlet 3.0, and on and on. There should be something for everyone, so do yourself a favor and check it out. I don’t think you’ll be disappointed. ### [NetBeans 6.8 Is Now Available](/2009/netbeans-6-8-is-now-available/) NetBeans 6.8 Is Now Available While we’re making product announcements, I might as well mention that NetBeans 6.8 is available today as well. I really think NetBeans is the best Free <del>Java</del> multi-language IDE on the market. It’s by no means perfect, but I like it a lot.1 Quoting from the release: Today Sun and the NetBeans™ community are announcing the availability of the NetBeans Integrated Development Environment (IDE) 6.8 — in conjunction with the availability of Java™ Platform Enterprise Edition 6 (Java EE 6) and Sun GlassFish™ Enterprise Server v3. The NetBeans 6.8 IDE is the first IDE to provide complete support for Java EE 6 and GlassFish v3, and offers other new and exciting features. The NetBeans IDE 6.8 is available for download free of charge at www.netbeans.org. KEY UPDATES TO THE NETBEANS 6.8 IDE Complete Java EE 6 Support: Java EE 6 language features simplify Java application development with less XML configuration, more annotations and more POJO-like development. GlassFish v3 Support: Developers can easily target and deploy to GlassFish v3, including the new lightweight GlassFish v3 Web Profile. JavaFX™: The latest version of the NetBeans editor provides improved code completion, hints and navigation for JavaFX. PHP Support: The NetBeans IDE expands its support of dynamic languages with support for PHP 5.3 and the Symfony framework. Tighter Integration with Project Kenai: Project Kenai, a collaborative environment for hosting open source projects, now delivers full support for JIRA and improved instant messenger and issue tracker integration. For more information visit www.kenai.com. C/C Profiling*: The new Microstate Accounting indicator and I/O usage monitor help developers profile and tune C/C applications. *NetBeans Platform: As a rock-solid application framework for Swing applications, the platform saves developers a huge amount of time and effort by providing commonly-used facilities such as menu items, toolbar items, keyboard shortcuts, and window management out of the box. Additional information is available at: NetBeans 6.8 IDE - http://netbeans.org/community/releases/68/ Java EE 6 - http://java.sun.com/javaee/ GlassFish v3 - http://www.sun.com/glassfishv3 Head over to netbeans.org and give it a spin! The JSF 2 support is excellent! ;) 1 Some might expect that, as a Sun employee, I have to push NetBeans, but that’s not the case. I converted from Eclipse months prior to the start of my employment at Sun, so that has no bearing at all on my choice. :) In fact, I’ve never had anyone at Sun tell me what to use. We have engineers that use every major IDE (or none). ### [New Components in Mojarra Scales: Part I - sc:dataTable](/2009/new-components-in-mojarra-scales-part-i-sc-datatable/) New Components in Mojarra Scales: Part I - sc:dataTable The migration of Mojarra Scales to JSF 2, adding new components has become much easier due to JSF 2’s new composite component feature. In the past couple of weeks, this new capability has paid off in spades as Mojarra Scales has gotten (so far) three new components in rapid succession. In this, the first part of a multi-part series, we’ll take a look at the most complex of the new components, sc:dataTable. The JSF spec details a data table, but it’s nothing fancy. It doesn’t offer pagination or sorting, for example. For simple applications, this may be sufficient, but for more complex or dynamic applications, it can be pretty plain and boring. The YAHOO! User Interface library provides a very nice table, which supports sorting, pagination, ajax updates, row and cell selecting, etc. In keeping with Scales' original intent, it is this Javascript that Scales wraps and provides as a JSF component. For those familiar with the standard h:dataTable, the usage should look very familiar. From the Scales demo, we find something like this: <sc:dataTable id='people' pagination='true' rowsPerPage='#\{tableBean.rowsPerPage}' rowsPerPageTemplate='4 8 16 32' value='#\{tableBean.peopleList}' var='person' width='50%'> <sc:column resizeable='true' sortable='true' width='200'> <f:facet name='header'>First Name</f:facet> #\{person.firstName} </sc:column> <sc:column resizeable='true' sortable='true'> <f:facet name='header'>Last Name</f:facet> #\{person.lastName} </sc:column> <sc:column resizeable='true' sortable='true'> <f:facet name='header'>Position</f:facet> #\{person.position} </sc:column> </sc:dataTable> In short, we specify a table with three columns, all of which are sortable and resizeable, and will be paginated. Like the standard data table, the value passed to the component can be a JSF DataModel, a List, or an Array. Internally, the Scales dataTable will wrap the value in a Paginator object that handles the heavy lifting. Just to show that there’s no magic in the managed bean, here’s the full bean (can you tell what television show I like to watch? : ) : @ManagedBean @SessionScoped public class TableBean { protected List<Person> list; protected int index = 0; protected int rowsPerPage = 4; public int getRowsPerPage() { return rowsPerPage; } public void setRowsPerPage(int rowsPerPage) { this.rowsPerPage = rowsPerPage; } public List<Person> getPeopleList() { if (list == null) { list = new ArrayList<Person>(); list.add(new Person("Michael", "Scott", "Co-Manager of Dunder Mufflin Scranton")); list.add(new Person("Jim", "Halpert", "Co-Manager of Dunder Mufflin Scranton")); list.add(new Person("Pam", "Halpert", "Sales Representative")); list.add(new Person("Andy", "Bernard", "Sales Representative")); list.add(new Person("Stanley", "Hudson", "Sales Representative")); list.add(new Person("Phyllis", "Lapin-Vance", "Sales Representative")); list.add(new Person("Dwight", "Schrute", "Sales Representative / \"Assistant to the Regional Manager\"")); list.add(new Person("Angela", "Martin", "Senior Accountant")); list.add(new Person("Kevin", "Malone", "Accountant")); list.add(new Person("Oscar", "Martinez", "Accountant")); list.add(new Person("Meredith", "Palmer", "Supplier Relations Representative")); list.add(new Person("Kelly", "Kapoor", "Customer Service Representative")); list.add(new Person("Creed", "Bratton", "Quality Assurance Representative")); list.add(new Person("Kelly Erin", "Hannon", "Receptionist")); list.add(new Person("Ryan", "Howard", "Temp")); list.add(new Person("Toby", "Flenderson", "Human Resources Representative")); list.add(new Person("Darryl", "Philbin", "Warehouse Foreman")); list.add(new Person("Roy", "Anderson", "Warehouse Dock Worker")); list.add(new Person("David", "Wallace", "Chief Financial Officer")); list.add(new Person("Jan", "Levinson", "Vice President of Regional Sales; Owner and Chandler of Serenity by Jan Candles")); list.add(new Person("Holly", "Flax", "Human Resources Representative of Dunder Mifflin Scranton; Human Resources Representative of Dunder Mifflin Nashua")); list.add(new Person("Charles", "Miner", "Vice President of North East Region")); } return list; } } When the component is rendered, you will see something like this: Currently, row selection is not supported, but that should be available by the time Scales hits 2.0 GA. One of the things that I think is really nice about this component is that your application doesn’t necessarily need to implement and Scales interfaces or extend any Scales classes. If, however, you need more control over pagination, you can extend the Paginator class (which, incidentally, is based on code created by NetBeans. Credit where credit is due : ). It’s likely that 2.0 GA will ship with a JPA-aware Paginator that your application can consume without require custom code. If you do extend the Paginator, all you have to do is return that as the value for your data table, and everything else works as expected. If you’d like to play with a live demo of the table, you can find one here. As the demo notes, the table is currently labeled as a beta, but the basic Ajax pagination seems to work, so please feel free to give it a try. In the next installment of this series, we’ll take a look at Scales' new autoComplete component. ### [Setting Up a New Web Site on DreamHost](/2009/setting-up-a-new-web-site-on-dreamhost/) Setting Up a New Web Site on DreamHost As a "computer guy," I get asked to help with all things computer-related. My church’s web site is no different. I was recently asked to help set up a new site. Since my time is limited and they need to get things going without waiting on me, I thought I would document my process for them, simple as it is. It occurred to me that it might be generally useful, so here it is. If I was wrong about that, please feel free to keep surfing. :) Table of contents Quick instructions for the impatient Creating the domain Installing the software Quick instructions for the impatient --- * Log on to the control panel * Click on "Manage Domains" * Enter the domain/sub-domain name on "Domain to host" * Select your "Do you want the www in your URL?" choice * Select the user under which to run the domain * Enter the domain web directory (e.g., example.com/mysite or example.com/www) * Click"Fully host this domain" * Click "One-Click Installs" from the Goodies navigation menu * Click "Install new website software - Advanced Mode" * Select WordPress as the software to install * Select the newly created domain/sub-domain for the "Install to" option * Click "Install it for me now" Creating the domain --- The first step, of course, is to log on to the DreamHost control panel. In the navigation tree on the left, you should see a "Domains" section. If it is not expanded, clicking on it will do so. Next, click on "Manage Domains." This will show you a list of your domain(s), with a "Add New Domain / Sub-Domain" button at the top. Click this. At this point, things start to get really subjective. This is how I like to set things up. You are, of course free to change things as you see fit. In the "Domain to host" field, enter the fully qualified domain name (e.g., mysite.example.com). For "Do you want the www in your URL?", my answer depends on the site I’m creating. In this example, I’m creating a sub-domain, so I select "Remove WWW." For new domains, I typically select "Leave it alone." Next up, "Run this domain under the user" will depend, again, on how you plan on managing the site. If you, the administrator, will handle everything, then this can be left as the main domain login. If, however, you need to allow other users to upload files, it might be a good idea to create a user for them. This way, you won’t need to give them your password. For the web directory, I group all my domains (and their sub-domains) into a directory named after the domain. That means, for example, that for example.com, mysite.example.com, and beta.example.com, the directory structure would look like this: $HOME/example.com/ | beta/ | mysite/ | www/ Hopefully that makes sense. What I like about that is that it leaves my home directory a little cleaner. Should I ever let a domain lapse, I can delete one directory and things are basically cleaned up. For the other options, I leave them as the default. I’m tempted to use Google Hosted Services for email on new domains, but that’s a personal preference. Installing the software --- Once the domain is created, which may take a few minutes, the software can be installed. We typically use WordPress. To install that, click "One-Click Installs" under "Goodies." We use custom themes and plugins, so I select the "Install new webiste software - Advanced Mode" option. Here, I select the WordPress option, then scroll way down to the "Install to" field. From the drop down, I select the new (sub) domain I just created. While I prefer to create and manage the databases manually, that’s not strictly necessary, so we’ll leave the check box checked, then click "Install it for me now." With that, you’re done. In just a few minutes, the software should be installed for you and ready to use. All that’s left is to login in to the site and begin configuring it, which I’ll leave as an excercise for the reader. :) ### [The Mojarra Scales Demo Has Moved](/2009/the-mojarra-scales-demo-has-moved/) The Mojarra Scales Demo Has Moved With the recent migration of Mojarra Scales to JSF 2, the old location of the Mojarra Scales demo was no longer adequate (upgrading that server posed some issues). For that reason, I have moved the demo to a new home. This server should be more up-to-date (both in terms of the application as well as the application server — which is GlassFish v3, of course — that runs it). When accessing the application, please keep in mind that it’s on an old server that’s running on an AT&T U-verse line, and the download times will reflect that. :) I’d also like to not that this showcases a couple of new components at the moment. I’ve begun an implementation of the YUI data table widget. At the time of this posting, basic table functions work, including client-side sorting. More complex functionality, such as Ajax updates, are in the offing. Another new component, which the demo uses extensively, is the excellent SyntaxHighligher script from Alex Gorbatchev. The demo uses this new component to show the page source for each demo, finally allowing you to see a given component in action, as well seeing the page markup that makes those components. The demo is still in flux, so some things aren’t quite "perfect" yet. For example, Safari really hates the markup the demo produces, which is a bug in the demo application itself. Hopefully, that will soon be fixed. For now, Safari users will need to use another browser. As I’ve noted, Scales has been migrated to JSF 2. While most components are working as expected, there are likely some minor issues to work out. If you run into any of these issues, or if you’d like to see extra functionality in any of the components, please feel free to file an issue on the Scales issue tracker on the Kenai project site. ### [JSF 2, h:dataTable, and Ajax Updates](/2009/jsf-2-h-datatable-and-ajax-updates/) JSF 2, h:dataTable, and Ajax Updates While JSF has had Ajax support for a long time now, it has always been through external libraries such as Ajax4Jsf/RichFaces, ICEfaces, DWR, DynaFaces, etc. With JSF 2, the framework now has first class, standardized support for Ajax. This is good news on several fronts. For those that want Ajax support but would rather not import another library, that capability is now baked in, and, for those familiar with a4j or DynaFaces, it should look very familiar. However, for those that don’t mind the external dependency, the standardized Ajax will make it much easier to mix and match component libraries on the same page, an issue that has plagued JSF for while. In this post, I’d like to take the first approach and show how easy it is to achieve Ajaxy updates on your h:dataTable using only standard JSF. In this example, we’re going to use a part of the JSF API that I have overlooked or ignored for a long time: the DataModel class. While you may not recognize the class, you’ve almost certainly used it. When you pass a List to the a h:dataTable, JSF wraps that list in a DataModel implicitly. However, if you use the class explicitly, you gain a lot more power over your data and your table. We’ll look at that in a moment. First, though, let’s start with our basic table: <h:dataTable id="memberTable" value="#\{memberBean.members}" var="member"> <h:column> <f:facet name="header"> <h:outputText style="font-weight: bold;" value="Last Name"/> </f:facet> #\{member.lastName} </h:column> <h:column> <f:facet name="header"> <h:outputText style="font-weight: bold;" value="First Name"/> </f:facet> #\{member.firstName} </h:column> <h:column> <f:facet name="header"> <h:outputText style="font-weight: bold;" value="Email Addresss"/> </f:facet> #\{member.emailAddress} </h:column> </h:dataTable> This should look pretty familiar to most of you. We’re simply creating a three column table, using the data return by MemberBean.getMembers(). As I mentioned earlier, we’ll be using the DataModel API directly, so let’s take a look at MemberBean now: @ManagedBean @SessionScoped public class MemberBean implements Serializable { public static final String NAV_LIST = "/admin/members/list"; public static final String NAV_REDIRECT = "?faces-redirect=true"; private DataAccessController dataAccess = new DataAccessController(); private DataModel dataModel; private int rowsPerPage = 5; private GroupMember current; private int selectedItemIndex = -1; private Paginator paginator; public void resetList() { dataModel = null; } public String prepareList() { resetList(); return NAV_LIST + NAV_REDIRECT; } public void resetPagination(ComponentSystemEvent event) { paginator = null; } public Paginator getPaginator() { if (paginator == null) { paginator = new Paginator(rowsPerPage) { @Override public int getItemsCount() { return dataAccess.count(GroupMember.class); } @Override public DataModel createPageDataModel() { return new ListDataModel( dataAccess.findRange(GroupMember.class, getPageFirstItem(), getPageFirstItem()+getPageSize())); } }; } return paginator; } public DataModel getMembers() { if (dataModel == null) { dataModel = getPaginator().createPageDataModel(); } return dataModel; } public void next() { getPaginator().nextPage(); resetList(); } public void previous() { getPaginator().previousPage(); resetList(); } } The interesting methods here are getPaginator(), getMembers(), next(), and previous(). Before getting too far along, I feel I should note that this code is based off that generated by the really nice JSF 2 support in NetBeans 6.8, though I have done some editing. At any rate, starting with getMembers(), we see the null check on the DataModel. If it’s null, we ask the pagintator to create it for us. In getPaginator(), we create a new instance of the abstract Paginator class (see below), overriding a couple of methods to make use of instance variables from our class. In createDataModel(), we see that we ask our DataAccessController [1] to return a List of GroupMember`s, starting at index `getPageFirstItem(), of, at most getPageSize() items. While the DataAccessController is not too important to our discussion here, the Paginator certainly is: public abstract class Paginator { private int pageSize; private int page; public Paginator(int pageSize) { this.pageSize = pageSize; } public abstract int getItemsCount(); public abstract DataModel createPageDataModel(); public int getPageFirstItem() { return page*pageSize; } public int getPageLastItem() { int i = getPageFirstItem() + pageSize -1; int count = getItemsCount() - 1; if (i > count) { i = count; } if (i < 0) { i = 0; } return i; } public boolean isHasNextPage() { return (page+1)*pageSize+1 <= getItemsCount(); } public void nextPage() { if (isHasNextPage()) { page++; } } public boolean isHasPreviousPage() { return page > 0; } public void previousPage() { if (isHasPreviousPage()) { page--; } } public int getPageSize() { return pageSize; } } There’s no real complex logic there, so I’ll let you read that, and we’ll move on to the next and previous links. Immediately under the table, I have this: <h:commandLink id="prevLink" action="#\{memberBean.previous}" value="Previous #\{memberBean.paginator.pageSize}" rendered="#\{memberBean.paginator.hasPreviousPage}"/>   <h:commandLink id="nextLink" action="#\{memberBean.next}" value="Next #\{memberBean.paginator.pageSize}" rendered="#\{memberBean.paginator.hasNextPage}"/> </div> If you were to click on the next link, MemberBean.next() would execute, which would increment the page number, and the table would rerender, getting us the next set of five `GroupMember`s. It does this, however, using a full page refresh (FPR), which is exactly what we’re trying to avoid. So, then, how does one ajaxify these links? Looking at just the next link for brevity and clarity, we add on simple line: <h:commandLink id="nextLink" action="#\{memberBean.next}" value="Next #\{memberBean.paginator.pageSize}" rendered="#\{memberBean.paginator.hasNextPage}"> <f:ajax execute="@this" render="@form"/> </h:commandLink> The f:ajax tag is all you need. There are many more options for the tag, but in this simple use case, we’re telling JSF to add Ajax behavior to the default event for the component (in this case, the click), we want to execute the current component (@this tells JSF to call the action method specified on the parent component, #\{memberBean.next}), and then rerender the form that encloses this component (@form). That’s all there is to it. Very easy and very clean. Let’s go a step further. Let’s add the ability to change the number of rows per page, and, of course, let’s do it in an Ajaxy manner. First, we must add some methods to our managed bean to make it all happen: public int getRowsPerPage() { return rowsPerPage; } public void setRowsPerPage(int rowsPerPage) { this.rowsPerPage = rowsPerPage; resetList(); resetPagination(); } public void resetPagination() { paginator = null; } This is the basic getter/setter pattern managed beans typically expose, plus some extra logic in the setter to destroy the Paginator, which will force its recreation when the table renders. The markup on the page might look something like this: <h:outputText value="#\{memberBean.paginator.pageFirstItem + 1} to #\{memberBean.paginator.pageLastItem + 1} of #\{memberBean.paginator.itemsCount}"/> ( <h:selectOneMenu id="rowsPerPage" value="#\{memberBean.rowsPerPage}"> <f:ajax execute="@this" render="@form"/> <f:selectItem itemValue="5" /> <f:selectItem itemValue="10" /> <f:selectItem itemValue="15" /> </h:selectOneMenu> ) per page This snippet adds some text telling the user the range he’s currently viewing, as well as a h:selectOneMenu listing some (hardcoded) options for the number of rows per page. If you’ve been doing JSF long, this looks pretty normal. The ajaxification, just like the `commandLink`s above, is a simple, one-line addition (line 4), that works the same way. Note that in each Ajax case, we’re rerendering the entire form. While convenient, it’s not necessary. If we wanted to, we could list each component clientId, separated by spaces, that we want to rerender. For large complex forms, a more selective rerendering would probably be desirable. However, if the number of components to rerender is high, it’s a better idea to group them (in one or more groups as necessary) with, say, h:panelGroup, and rerender the groups, as that makes for a more maintainable list. In this case, we simply rerender the form as it’s small enough to do that quickly. Before we finish up, let me touch on why I stressed the explicit use of DataModel. While not even indirectly related to Ajax interactions, its explicit use makes master/detail relationships, for example, a little easier. In this example, if we want to edit a particular member, the DataModel makes it really easy. Let’s add a "command" column to the end of our table: <h:column> <f:facet name="header"> <h:outputText value=" "/> </f:facet> <h:commandLink action="#\{memberBean.view}" value="View"/> <h:commandLink action="#\{memberBean.edit}" value="Edit"/> <h:commandLink action="#\{memberBean.delete}" value="Delete" onclick="return confirm('Are you sure you want to delete #\{member.firstName} #\{member.lastName}?');" /> </h:column> Now, lets take a look at MemberBean.edit(): public String edit() { current = (GroupMember)getMembers().getRowData(); return "edit?faces-redirect=true"; } This method asks the DataModel what the current row is and saves that in an instance variable. It then navigates, using JSF 2’s simplified navigation to the view "edit." The inclusiong of "?faces-redirect=true" in the action outcome tells JSF to redirect to the target view. This allows the location in the browser to reflect the current page, rather than being one page behind. JSF handles updating the state of the DataModel for you, so all that’s left for you is asking it what its state is. The approach I’ve seen (and used, sadly) most often, is to use either f:param or f:setPropertyActionListener to pass the id of the current member back to the server. My action method would then have to either query the Request or an instance variable for the ID, ask the model layer for the GroupMember that matched the ID, and then forward. While it worked, it was pretty ugly and often required more getters and setters than I cared to put on the bean. By using DataModel directly, we avoid all that cruft and left JSF do the heavy lifting for us, which is, of course, what frameworks are for. So there you have a basic Ajaxy data table using only standard JSF components. Given how simple it is to add Ajax to a JSF page with JSF 2, you can easily start adding such features to existing JSF 1.2 applications as you upgrade to the new version without requiring massive changes to your application. Of course, if you want more complex Ajax interactions, there are still myriads of third party component sets that offer that. For the simple case, though, you no longer need to shop around. [1] This class is simple a JPA 2 utility class. It performs the basic JPA functions, including transaction support, etc. It’s specific contents are not relevant here. :) ### [Mojarra 2.0 hits FCS](/2009/mojarra-2-0-hits-fcs/) Mojarra 2.0 hits FCS Ryan Lubke announced today the availability of the first production-ready JSF 2 implementation with the release of Mojarra 2.0. You can download the binaries directly from java.net, or, use the information Ryan posted for specifying a dependency in your Maven pom file. Congrats to (the rest of) the Expert Group and, of course, the Mojarra development team (Ryan, Jim, Ed and Roger). ### [GlassFish v3 FishCAT Announced](/2009/glassfish-v3-fishcat-announced/) GlassFish v3 FishCAT Announced During the GlassFish v3 Prelude development cycle, the GlassFish team launched an initiative called FishCAT, which is our Community Acceptance Testing program. The program was very successful for Prelude, resulting in many, many reported (and fixed! : ) issues for the Prelude release. As we press hard toward the release of GlassFish v3 final later this fall, this program has been re-launched to help us engage our user community. Through this program, testers will have a much greater impact on the final quality of the product when it finally ships. If you’d like more information, you can see the announcement here, and a description of the program here. If you’d like to sign up and help, the application can be found here. ### [Mojarra Scales 1.3.2 Has Been Released](/2009/mojarra-scales-1-3-2-has-been-released/) Mojarra Scales 1.3.2 Has Been Released Late last night, I published Mojarra Scales 1.3.2. This is mostly a bug and performance fix, but here are some highlights from the release: <sc:links /> (and related supporting classes and components) was modified to allow files only from /scales to fix a pretty glaring security hole in some scenarios When multiple, local requests for a given resource type (CSS or JS) are queued, they are now rendered to the page in such a way that they will be returned in a single request. That is to say, Mojarra Scales will now concatenate these files into one response, so as to reduce the number of network operations. Scales now correctly handles cached files. When a CSS or JS resource is sent, Scales now employs etags to help the client cache the file properly. On subsequent requests, if the client sends the last modified header, Scales properly handles the date, returning 304 when appropriate <tab/> now supports the style and styleClass attributes. The multi-file upload component has been moved out of the main jar into its own artifact so that those not using the component will have a smaller deployment. This component can be found under the upload artifactId in the maven repository. The jar files, including the demo app, can be downloaded from kenai.com or via maven (the demo is not in maven). With the architectural changes in 1.3 out of the way, the next version of Scales should include more components, as well as enhancements to existing components. At some point, the project will be branched for a migration to JSF 2. With the spec being final and Mojarra 2 scheduled to ship in a couple of weeks, it seems the time is right for the move. Time will tell, of course, how soon that move is made. If you have any issues, please comment in the forum. ### [FacesTester 0.3 Has Been Released](/2009/facestester-0-3-has-been-released/) FacesTester 0.3 Has Been Released After a lot of changes and a long delay, I’m pleased to announce that we have released FacesTester 0.3 tonight. This version has a large number of new features. Read on the for details. This release has three major changes: removal of almost all external dependencies, support for Servlet filters and listeners, and support for JSF 2. External Dependencies From the start, we have always depended on Spring Mock/Test to provide the Servlet API classes. While this works, it poses a couple of problems. For non-Maven users, gathering and managing the various required jar files can be tedious. While manageable, it’s nice not to have to do that. Another big issue is the "build from source" requirement on GlassFish technologies. As we looked into using FacesTester on Mojarra, this requirement became increasingly important, so the removal of external dependencies, where possible and reasonable, became a high priority. Servlet Filters and Listeners Support When I talked to Stan Silvert about his JSFUnit project, one of the things he lamented about other testing solutions is that they usually don’t exercise the Filters and Listeners a web app might have, so the testing, he says, is incomplete. That made good sense to me, so we added support for these two Servlet APIs to FacesTester. If there are filters or listeners configured in the application’s web.xml, they will be called automatically — no special steps required. JSF 2 Support With this release, we now support running in a JSF 2 environment, with full access to all annotation-based objects the new spec makes available. I should be a bit more precise here, in that when I say "JSF 2," I mean Mojarra 2, primarily as it’s the only JSF 2 implementation available. To use FacesTester with JSF 2, you will need one extra jar, which includes the Mojarra2-specific bits: <dependency> <groupId>com.steeplesoft.jsf</groupId> <artifactId>facestester-jsf2</artifactId> <version>0.3</version> <scope>test</scope> </dependency> On that note, after a good discussion with Matthias Wessendorf of MyFaces fame at JavaOne back in June, we did some restructuring of the code in FacesTester that will make it easier to add support for other implementations. Currently, there’s a small bit of Mojarra-specific code that’s used internally to bootstrap the JSF environment. In theory, equivalent functionality can be written, where needed, to make sure MyFaces bootstraps correctly, with no need for the Mojarra jars on the classpath. It may be that MyFaces is supported now out of the box, but I haven’t had the chance to test that. If there are any interested MyFaces users, we’d appreciate the contribution. If not, we’ll try to get to it eventually. Licensing was also addressed in this release. At the request of Matthias, and after some internal discussions, we’ve relicensed the project (or, more correctly, added an explicit license) under the BSD license, which should make all but the most license zealous users happy. There were also many bugs fixed and other minor improvements. I should note that we’ve gotten a lot of additional help from Imre Osswald, Ryan Lubke, Ingo Hofmann and Guy Veraghtert. I’m pretty happy with the progress we made on this release, but there’s much left to be done, so if you’re interested in helping, now’s as good a time as any. :) ### [I've Updated My About Page](/2009/i-039-ve-updated-my-about-page/) I've Updated My About Page I should note here, for those that don’t follow me on Twitter, that I have updated and expanded my About page, for those that are interested in that sort of thing. A word of warning: There’s some personal stuff in there! :) ### [JavaOne 2009 Day 4](/2009/javaone-2009-day-4/) JavaOne 2009 Day 4 It just occurred to me that I never posted my final wrap up on JavaOne 2009. While it may be that, at this last date, no one cares anymore, I feel I should finish what I started, even if only for me. With that said, here’s my closing thoughts on what I hope is NOT the last JavaOne. Friday was for me, as it was for many it seems, an abbreviated day. The day started with James Gosling’s "toy show" general session. I always look forward to these sessions, as you never know what you’re going to see. As expected, this year’s session had a wide range of Java-based products. <simon_cowell>If I’m being honest with</simon_cowell>, there wasn’t a whole lot in the session that appealed to me (which, of course, is not its intent ; ). The demo with the Wii remotes was pretty slick, but not anything I’m likely to tinker with any time soon. However, that we (that is, Sun) do things like that is one of the reasons I love this company. We may not be able to monetize the Wii-remote Minority-Report-esque drawing board, the research and (I’m guessing) out-right playing that goes into things like is what drives innovation. What our engineers learn from that very well could leave to a revenue stream for the company or, more importantly, push that type of technology further than it is now in ways no one has imagined yet. While tinkering of that sort is in no way unique to Sun, it is one of the things that has made us such a great technology company over the years. The FIRST robot competition was also pretty slick. While I won’t ever build a robot like that, I do have a son who’s shown some interest in that sort of thing (and who we will be hooking up with http://alice.org/ as soon as he sets our new puppy down :). It’s a neat organization and competition, so it was good to see it get such prominent exposure. The demo that impressed me the most was Visuvi, a visual search engine. I can’t do it justice with words, so just go watch this video. I’ve been wanting something like this for a long time. Unfortunately, I had to leave the session early as it was time to head for a web tier expert group meeting, in which the JavaServer Faces EG (on which I serve) and the Servlet EG met, as is our custom at JavaOne, to go over any outstanding issues. As these specs are developed, we want to make sure both the groups are pulling in the same direction where there is overlap, and this meeting is a great way to help with that since so many of us are all in one physical location, which doesn’t happen often. As is always that the case, there were a lot of really sharp people in the room. I had to leave early, but the the two hours I spent in the room were productive (and entertaining! : ), and it was good to see all those guys again. My departure from the EG meeting officially ended my JavaOne week (and started my Bay area vacation), but I do some general thoughts on the week. As I noted last year, one of the highlights for me was getting to spend some time with some of the people I work with over the internet. Ryan, Jim, Ed, Roger, etc from Sun. Andy and Matthias from Oracle. Dan from Red Hat/JBoss. Adam Bien and Felipe Gaucho. And lots more that I’m going to leave out so I’ll stop. :) They’re all really sharp people, and working with them pushes me to grow and improve in a variety of areas. I unabashedly admit a pretty healty case of fan-boyism. As others have noted, this year had a very odd feel to it, which some said "it felt like a wake" or described it as "funereal." From the keynotes (especially Tuesday’s, where Larry took the stage) to the mood on the floor, it seemed everyone expects this to the last JavaOne. If anyone knows for sure, they’re not saying. I hope it’s not, as it’s a great conference. While I enjoy getting to talk with people at the show, the technical sessions and BOFs are all really good. Of course, there are conferences (No Fluff, for example) that are extremely valuable, I like the size and scope of this one. The massive range of topics practically guarantees there’s something you’re going to want to catch, and the wide variety of vendors on the pavillion floor gives a great overview of what the industry is doing outside my little domain. More importantly than the possible demise of the conference, though, was the idea that this was, if all continues as planned, the last Sun-run JavaOne at the very least. JavaOne may live on, but Sun won’t be running it, so it will likely be a different animal come next June. It was that not-quite-a-demise that made the conference somber at times, for me. The end of Sun as a separate entity marks the end of a really cool era in technology. With Solaris on Sparc catching my eye in the early 90s, I’ve been a big fan of Sun’s for a long, long time, so it was a great deal of enthusiasm that I came on board. Now less than a year later, to see the company sold is bittersweet for me. Clearly, our revenues were hurting overall (though my area seemed to be doing OK), so we needed some sort of help. From that perspective, the acquisition is certainly a good thing, as Oracle is a solid, profitable company that clearly knows how to market and sell. The uncertainty of how much things will change inside of what was once Sun, though, in addition to the "end" of a great company gives me pause. I have high hopes for what Oracle will do with the technologies it’s acquiring (and I certainly to be part of that ; ), but it just won’t be the same. Despite all of that, I had a great time at the conference. I got to meet some new people (and some I’ve interacted with over the internet for quite a while), and learn a lot of new tricks and tools, so it was time well spent. Hopefully, I’ll be able to say the same after JavaOne 2010. :) ### [JavaOne 2009 Day 3](/2009/javaone-2009-day-3/) JavaOne 2009 Day 3 Day 3 of JavaOne 2009, the last full day of the conference, has come and gone. Like the rest of the crowd, I began to wind down a bit early. For no real good reason, I skipped the open general session this morning, or, rather, skipped most of it. I caught the tail end and got the see .Net and Java web services interoperating (using Metro on GlassFish, by the way! : ), which was good to see. I don’t do much with web services at the moment, though, which is probably why I didn’t attend all of the general session. My first and, as it turned out, only session of the day, was The New World: JavaFX™ Technology-Based UI Controls, led by Jasper Potts, Richard Bair, and Amy Fowler. They demoed some of the new controls in JavaFX 1.2, explained some the gotchas in using the controls, especially the finer points of component sizing, as well as showing off the skinning support. These controls are separate from their visual representation, making skinning very easy, which is really cool. As cool as the components were, my only real complaint is that there is still no serious offering for business applications (menus, data tables, etc). Other than that, these things are cool. As was my habit all week, after the session I headed by the Sun booths to see what was happening. This time, though, I was pulled into a couple of discussions with customers to discuss how JSF and GlassFish might help them with the problems they were facing, which was a lot of fun. It’s always good to interact directly with customers on a technical level to see how we can help solve their problems. After lunch, I decided not to attend the sessions I had scheduled, I roamed around the Pavilion, soaking in what I could before it closed. I ran across Dick Wall and Carl Quinn of Java Posse fame doing an interview at the java.net booth. Then, oddly enough, stumbled across Tor Norbye giving a really cool demo of the soon to be released JavaFX Authoring Tool in the Java Utopia section. Once the Pavilion closed, I headed back to my hotel to get ready for my team dinner that night. We met at the Canton Seafood and Dim Sum Restaurant. It would appear that every Sun employee on the GlassFish team was there. If there were any missing, it couldn’t have been many. :) Having worked so hard and so closely with all these smart people, it was a lot of fun to just hang out and chat, mostly about non-work stuff, oddly enough. As icing on the cake, my wife was invited to join us, so it was doubly good. :) After the dinner, it was about time for the Meet the GlassFish™ Server Team BOF, so we all filed back over to the Moscone. The session was really well-attended. Abhijit Kumar and Shreedar Ganapathy led the BOF, giving an overview of GlassFish’s history and where we’re going, highlighting the features and architecture of v3, due out this fall. They brought three GlassFish community members on stage, Adam Bien, Wouter Van Reeven, and Steve Giovannetti, giving them a chance to tell the crowd what they like — and don’t like — about GlassFish. I thought this was the best section of the BOF. At Sun, we really, really value our external community (if you remember, that GlassFish community is how I got my job at Sun), so it was gratifying to see a few of our users singled out and honored. Tomorrow is the final day of JavaOne. It’s been a quick week. ### [JavaOne 2009 Day 2](/2009/javaone-2009-day-2/) JavaOne 2009 Day 2 JavaOne 2009 Day 2 has come and gone, so here I sit on day 3 typing my recap. I never promised a punctual report! :) My day started with a talk by Max Katz on using JavaFX and Seam in an app. It was an impressive talk. The Exadel folks have done a lot of hard work in getting the two technologies working together. Next up was a talk by Vivek Pandey and Jacob Kessler on scripting on GlassFish. They covered JRuby and Jython deployment on GlassFish, describing not only the how, but the why (Java EE features such as clustering, access to Java classes, etc). Both the presenters were enthusiastic and knowledgeable, I thought. Very good presentation. After lunch, I hung out some in the java.net Community Corner, working on lunch and Tuesday’s recap. :) I got to meet Felipe Gaucho, a name well-known to subscribers of the JUG Leaders mailing list, which was pretty cool. Sun JUG liaison Aaron Houston hooked me up with a pretty cool treat for my JUG back home (hint: It comes on a USB thumb drive. You’ll have to come to July’s meeting to see what it is : ). With the blog finally posted and networking finished, I dashed off to my team mates' hands on lab, Building OSGi Plug-Ins for the GlassFish™ v3 Application Server. Since this lab covers what I do in my day job, there was much in it for me, but I went for moral support and to see if could help if things unexpectedly went south. As it turns out, things went well, over all, with the attendees successfully accomplishing the exercises in the lab. One attendee even went beyond the lab exercise and extended the Twitter console plugin to allow posting to Twitter, which was cool to see. Leaving the lab, I went back to the pavilion to see what was happening in the JBoss and Sun booths, and bumped into my (twin) brother. As luck would have it, we were wearing the exact same shirt, which was the source of some chuckles. I was talked into heading over to the Java EE Ancillary Event, I think it was called, which was a party for those interested in Java EE 6 technologies. It was really well attended, with lots of mingling and talking, and some game playing. In opposite corners we had two Wiis setup, so attendees could play Wii Sports or Rock Band. My brother got to play Marc Hadley, the co-spec lead of JSR 311, JAX-RS. Marc, BTW, won. :) After the party, I went to the JavaServer™ Faces Platform and Ajax BOF, led by Roger Kitain (JSR 314 co-spec lead, Sun Microsystems), Alexander Smirnov (RichFaces, Exadel/JBoss), Andy Schwartz (ADF Faces, Oracle) and Ted Goddard (ICEfaces). They discussed what we’ve done in JSF 2 with regard to Ajax, as well as touching on what some of the component frameworks are doing in the Ajax space. It was a good, informative, well-attended session, with lots of questions. That’s a good sign. Immediately following in the same room, Ryan Lubke and Jim Driscoll, the Mojarra implementation team from Sun Microsystems, led the BOF Writing a JavaServer™ Faces 2.0 Component That Uses Ajax: It’s Easy! (Really, It’s Easy!). It was a good talk that showed in detail how JSF 2’s composite component feature has greatly simplified JSF component development. They also showed how simple it was to add Ajax support using JSF 2’s new Ajax features. Very, very cool. Sadly, I had to duck out early, and headed back to my hotel. It was a long day, and my body is still on central time, so I was grinding to a halt. Thursday is the last full day, so I had better make the best of it! ### [JavaOne 2009 Day 1](/2009/javaone-2009-day-1/) JavaOne 2009 Day 1 JavaOne 2009 started yesterday. It was a long, fun day which started with an interesting general session and ended, for me, with my very first JavaOne presentation (source and slides linked below). The reviews and reactions to the conference have been pretty interesting. Hopefully, mine will be too. The opening general session started, as last year did, with entertainment. As opposed to the loud, attention-demanding dance team, this year we were treated to some very nice bass and drum beats courtesy of some DJ whose name I don’t know (not that it would matter if I did). After she finished her set, Sun Chief Gaming Office, Chris Mellisinos took the stage gave a quick introduction, with Sun CEO taking the stage and running the show. Jonathan’s part of the show was the expected "Java’s doing well, and you developers are a large part of that" speech. He brought up several Sun partners to demo how Sun and Java, in conjunction with those partners, are solving hard, real world issues. For me, the best part was when Jonathan invited James Gosling on the stage to discuss the new Java Store. James talked about what the store offers, it’s plan, etc. The store has been under development for over a now, so he described the project as having now "real engineers, as opposed to me slapping crap together." Very funny, and humble, I thought. At one point, he showed a solitaire game available on the store, which, Jonathan noted, Gosling himself wrote. Jonathan asked James, "You don’t play this at work, do you?" James took a l-o-n-g time to answer, send laughter rippling through the crowd. It was awesome. Having discussed the store, Jonathan turned the focus from the store to James Gosling himself. Dress in a jacket and tie, he described James, dressed in his typical t-shirt and blue jeans, as a role model, "wardrobe notwithstanding," to which James retorted, "Oh no. I think you have that exactly backwards." Again, the crowd erupted in laughter, prompting Jonathan to note that he was "speaking to the wrong crowd." Jonathan talked about courage, lauding James (and his team) for having the courage to create Java. Scott McNealy, to loud applause, joined the two on stage at some point. They played a quirky, but very cool Jib Jab type video detailing the creation of Java, during which Jonathan disappeared, not to be seen on stage again during the session. Scott spoke for a while, though everybody knew what this was leading too. Larry Ellison had already been spotted in the crowd, and, as expected, Scott invited Larry on to the stage. Larry spoke about Oracle’s commitment to Java, noting how every Oracle app, outside the database, was Java-based. As best as I can tell, what Larry said next was universally unexpected: he praised both JavaFX and OpenOffice.org, commenting that he’d like to see the OOo team use more JavaFX. The general consensus seemed to be the these two projects were likely to be scuttled, should the acquisition close, so this caught a lot of people off guard. It sure surprised me. After Larry’s speech, Scott spoke a bit more, finally telling the crowd thank you and good bye, before returning to his seat to a standing ovation. His closer had a very sad air to it, as if this might be the final JavaOne. Even Jonathan seemed to be getting a bit misty as he thanked James for all his hard work. The session ended, basically, on that somewhat down beat, leaving everyone, it seemed, in a pretty somber mood. Charles Nutter right described the session as "funereal," and Tim Bray noted that everyone in the press room thinks this is, indeed, the last JavaOne, though no one really knows for sure. Even if Oracle continues the conference, and I hope they (we? ; ) do, it will certainly be different, with Sun no longer around, so in that regard, this is the end of the line. What comes next may be better, but it will at the very least be different, which is kinda sad. Leaving the general session, I headed for the EJB 3.1 session led by Ken Saks. The line for the door wound all around the open area on the lower level of Moscone North. The line was absolutely huge. Inside, the room was packed as Ken walked through a lot of the enhancements 3.1 offers. He noted that EJB 3.0 intended to fix the usability issues with 2.1, while 3.1 aimed to add features, and that they did in spades. Enhancements like no interface session beans, portable JNDI names, embedded EJB3 container APIs, and a handful of others should make 3.1 a really, really nice rev of the spec. Since I was presenting in the evening, I didn’t actually make any of the other sessions I had scheduled. I was busy either actively or passively fretting over my talk. The time finally arrived, so my wife and I made our way to the room. It was nice getting to have her in the room. It was her first time to hear me give a technical talk. Overall, I think the session went pretty well. I felt comfortable on stage, and not a bit nervous once I started. As happened at the JUG, though, time went by too quickly. Hoping to have a more interactive session, I asked the crowd to help drive the agenda, though no one volunteered, so I just walked through my slides. I was shocked to see that I spent half my time going over the very odd variable scoping rules in JavaScript, so I had to hurry through the other slides. In the end, I only covered scope, objects/arrays, and classes (though I didn’t get to inheritance). I had to cut testing, the DOM, server-side JavaScript, etc, but that’s probably fine. Looking back, I probably prepared too much information, but that’s better than not enough I guess. I had several good questions during the session, and several other after, so it seemed that at least most people enjoyed the session. I noted on Twitter that no one yelled rude things as they left, so I’m going to take that as a good sign. I’ll know better when I get the eval results from the conference organizers. For those that attended the session and would like the slides and source, you can find those here and here. Feel free to email me (jason at steeplesoft dot com) if you have any questions. Today, as this is actually Wednesday morning, I will be able to relax and enjoy the rest of the conference. I’ll try to have a recap up tonight or early tomorrow. ### [CommunityOne 2009](/2009/communityone-2009/) CommunityOne 2009 Today was CommunityOne, the free conference that precedes, and this year, runs concurrently with JavaOne. This year, my wife was able to travel out with me for a little vacation after JavaOne concludes. With her CommunityOne pass, she got to attend today’s activities with me, which was a nice change from last year. When we landed in San Francisco, we checked in, ate a quick lunch, then jumped into the sessions. The first session we attended was "Sun Cloud APIs Birds of a Feather." As a Sun employee, I feel I should know what our cloud story is, but I don’t. While this session didn’t really explain a lot of the business side, Java luminaries Tim Bray and Craig McClanahan (ironically, one responsible for XML itself and the other for a very XML-heavy web application framework) demonstrated the RESTful APIs we provide to manage the cloud which uses…​JSON. :) Tim and Craig clearly know their stuff, handling both the presentation and the audience questions comfortably. I need to see if Sun employees or Java User Groups get any kind of special deal on a virtual data center, as I’d really like to play with one with breaking the bank. Next was "Developing RESTful Web Services with JAX-RS and Jersey," which, I must say, was quite a cool presentation. I haven’t done anything serious with web services since my Hobby Lobby days, and that was done with Axis. If you’ve used Axis, you know it’s painful. If pressed, I might even call it the EJB 2 of the web services APIs. Marc Hadley and Paul Sandoz gave a nice overview of the spec, and lots of clear, simple examples. JSR 311 looks like a really nice spec. I fear, though, that I’ve found a new hammer in search of a nail. :) After some time in the pavilion, I ended up in Frank Wierzbicki’s "Getting Started with Jython and Django." The presentation started off a bit rough, with Frank noticing that he had the wrong slides, and he never seemed to recover fully from the disruption (I probably wouldn’t either! : ). In the end, we got a good look at what Django offers, especially when used in conjunction with Jython, but we didn’t get to see enough of the actual code. The presentation seemed to focus more on Jython than on Django, but that didn’t dampen my eagerness to learn the framework. That being the last presentation of the day for us, we hung out in the pavilion for a while, talking with some of the Mojarra guys before heading to Hall A for the OpenSolaris and Sun Cloud Party. The half-naked freak show marching band (of which I should have a picture coming from Ryan Lubke soon) that descended on the Pavilion followed us to the party. As we ate finger foods, they played and danced and were generally a bit odd. When they finally quit being too loud, we were able to have conversations. Eventually, we have a veritable who’s who of the JSF world in one place. There were, of course, notable absences (Jim Driscoll, for example, left early), but we did get this snapshot of the group (thanks to my awesome wife) : Right to left we have Alexander Smirnov, Ryan Lubke, Jason Lee (me! : ), Dan Allen, Ed Burns, Anisaa Lam (GlassFish Admin Console team), Roger Kitain, Imre Oswald (JSF power user and ##jsf regular), Ken Paulsen, Matthias Wessendorf, and Andy Schwartz. The final part of the evening might have been the best. The real entertainment for the night was The Spazmatics, a very eclectic, and crazy, cover band. Words really can’t describe them, so here’s a bunch of pictures: It was a good way to start the conference. Tomorrow starts with the opening keynote, which is supposed to be chock-full of exciting news and surprises. We’ll see! :) ### [JavaServer Faces 2.0 Is Final!](/2009/javaserver-faces-2-0-is-final/) JavaServer Faces 2.0 Is Final! See the Executive Committee for SE/EE vote here. Download Mojarra, the reference implementation, here. ### [FacesTester 0.2 Has Been Released](/2009/facestester-0-2-has-been-released/) FacesTester 0.2 Has Been Released Today we released FacesTester 0.2. While this release has a number of bug fixes and more minor enhancements, one of the biggest new features is injection support. Leveraging the InjectionProvider Service Provider Interface (SPI) provided by Mojarra, FacesTester now supports the automagic injection of mock/test objects. For example, the following managed bean: public class ManagedBeanWithJpa { @PersistenceContext(unitName = "em") private EntityManager entityManager; public EntityManager getEntityManager() { return entityManager; } public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } } can be tested like this: @Test public void shouldHaveInjectionPerformed() { InjectionManager.registerObject("em", new MockEntityManager()); ManagedBeanWithJpa mb = tester.getManagedBean(ManagedBeanWithJpa.class, "jpaBean"); assertNotNull(mb.getEntityManager()); } In line 3 in the test code, we see the registration of our test EntityManager. When JSF (Mojarra, in our FacesTester environment) creates the managed bean, it delegates to the FacesTesterInjectionProvider, when then injects MockEntityManager when it processes the @PersistenceContext annotation. In a real test, one might create a test database using [HSQLDB or Derby and DBUnit. Also in this release is code to test the state saving on a component. A pretty common source of bugs with custom components is inadequate coverage in the state saving code. FacesTester will examine the component and insure that each property is correctly handled: @Test public void testMyComponentStateSaving() { FacesTester facesTester = new FacesTester(); facesTester.testStateSaving(MyComponentState.COMPONENT_TYPE); } FacesTester will create the component using Application.createComponent(), populate each property with a test value, and save the state. It will then create a new component of the same type and restore the saved state into this new component. Finally, it iterates over each property, comparing the results of each getter. If they don’t match, an Exception is thrown. Fancy! :) The FacesConfig object was also updated to cover more JSF artfiacts, so if you’re using this aspect of the tool, be sure to checkout the updated JavaDocs for full details. As always, FacesTester is available in the java.net Maven repository: <dependency> <groupId>com.steeplesoft.jsf</groupId> <artifactId>facestester</artifactId> <version>0.2</version> <scope>test</scope> </dependency> If you have any issues, please be sure to file issues here. ### [Making Tables Harder Than They Need To Be](/2009/making-tables-harder-than-they-need-to-be/) Making Tables Harder Than They Need To Be I know you’re not supposed to do this, but sometimes it’s just easier. Sometimes I use `table`s to layout out my forms. Especially for big forms, it’s just easier to put things in a table than deal with `label`s, CSS, etc. Right or wrong, I do it from time to time, but, thanks to David Geary, I just learned that I make it harder on myself than it needs to be. The sad thing is that I’ve known about this solution for years now, but never put two and two together. Typically, my form may look something like this: <table> <tr> <td>#\{msg.label1}</td> <td><h:inputText value="#\{myBean.field1}"/></td> </tr> <tr> <td>#\{msg.label2}</td> <td><h:inputText value="#\{myBean.field2}"/></td> </tr> // ad naseum </table> JSF, though, has a nicer approach, which David used in his article: h:panelGrid. This component will take each child component and put it in a table. The number of columns in the table is controlled by the columns attribute (of course, there is more to this component than just this option). My table, then would look like this: <h:panelGrid columns="2"> #\{msg.label1} <h:inputText value="#\{myBean.field1}"/> #\{msg.label2} <h:inputText value="#\{myBean.field2}"/> </h:panelGrid> The component then handles the creation of the table, rows, and cells automagically for me. Following David’s example, I put the label and input field on the same row, as that helps me visualize the resulting table better, but it’s not necessary. If you need more than one component in a cell, you simply wrap those in a h:panelGroup: <h:panelGrid columns="2"> #\{msg.label1} <h:panelGroup> <h:inputText value="#\{myBean.field1}"/> <br/> #\{msg.helpText1} </h:panelGroup> #\{msg.label2} <h:panelGroup> <h:inputText value="#\{myBean.field2}"/> <br/> #\{msg.helpText2} </h:panelGroup> </h:panelGrid> Fancy! Now I need to give some thought to a component that will help layout forms The Right Way! ### [UPDATED: Web Beans Webinar](/2009/updated-web-beans-webinar/) UPDATED: Web Beans Webinar On May 19th, Pete Muir, JSF 2.0 Expert Group member and Web Beans implementation lead (if I recall correctly) will be leading, in conjunction with The Aquarium, a webinar covering the forthcoming Java Contexts and Dependency Injection JSR (JSR-299, formerly known by the JSR’s former name, Web Beans). Unfortunately, that’s right in the middle of the Oklahoma City JUG’s meeting, so I can’t make it, especially since I’m this month’s speaker. For those of you that won’t be attending the OKC JUG tomorrow, this should be a good session on a great spec. I hope to catch the recording. Not as good as attending live, but it’s all I’ll be able to manage. Dan Allen was nice enough to point out that I misread the announcement, which means OKC people can hear me talk AND attend this webinar. Win win! (win! ; ) ### [Book Review: Practical RichFaces](/2009/book-review-practical-richfaces/) Book Review: Practical RichFaces One of the great strengths and successes, I think, of the JavaServer Faces specification is the proliferation of third party components. One of the older and better known component sets is RichFaces, which started out under a company called Exadel and is now part of JBoss. For many, RichFaces is the first add-on component set for a new JSF project, and with good reason. I recently had the opportunity to serve as a technical reviewer on Max Katz’s Practical RichFaces from Apress. Read on for my review of the book. First off, let me cut to the chase for those of you that just want the bottom line. I really liked this book. I think Max did a great job of covering the material in a very approachable manner. One might argue that all of this information is already available online, but I think Max did a great job of coalescing all of that information into one very readable book. Personally, as convenient as online resources are, I still prefer reading printed pages when I’m really trying to understand something. I think this is one of those books that’s worth the money to purchase, as it has all one needs to get a good handle on the library. The book is basically in three sections. After a short and not-too-in-depth introduction to JSF, the sections cover Ajax, the UI components, and skinning. I like that he starts off with the Ajax4Jsf (or a4j) components. In my mind, a4j is still the Ajax component set for JSF. While there are other JSF solutions, a4j established itself early as a solid and reliable Ajax framework for JSF, and has, I think, aged really well. Starting with, if I recall correctly, the 3.x line of RichFaces, a4j is part of the RichFaces library. That doesn’t mean you have to use the RichFaces UI components in your app, but they’re there if you need them. At any rate, Max walks through each of the a4j components, explaining what they do and how to use them, as well covering some of the more <a title: "Is that the right word? :)">esoteric</a> attributes such as ajaxSingle and process. In chapter 4, he covers some more advanced topics like controlling traffic with queues and Ajaxy user input validation. This section alone may be worth the price of the book." The next section deals with the visual components offered by RichFaces. Among the myriads of JSF component sets, RichFaces is one of the most complete sets on the market. In addition to the excellent Ajax support, RichFaces offers everything from in-place edits (rich:inplaceInput) to panels (rich:panel) to pick lists (rich:pickList) to trees (rich:tree). In this section of the book, which spans six chapters, Max covers each of the components, giving clear, simple examples of how to use each. With screen shots and sample code, you should have all you need to get up to speed on each of these components. The final section of the book covers the skinning support in RichFaces. In addition to the ten built-in skins and three add on skins, RichFaces exposes a means for creating your own. While he doesn’t show each and every CSS class and HTML DOM ID a skin author would need to know, he does show where to find those in the official documentation, and covers the basics needed for starting and wiring in a custom skin. For a component set as complex and comprehensive as RichFaces, to have such careful attention given to changing the look and feel is quite a nice feature. This section should give you a good push in the right direction for taking advantage of that capability. As I noted at the beginning, I really liked this book. I think it was well and clearly written. The material was covered in an easily consumable manner, managing to avoid the tendency to get buried in technical details that may not be immediately relevant (such as an in-depth discussion of the JSF lifecycle that plagues so many JSF resources). Whether you want a good resource for the excellent Ajax4Jsf library or a solid reference on the visual RichFaces components, I think you’d be well served by picking up a copy of this book. ### [Mojarra Scales 1.3.1 Has Been Released](/2009/mojarra-scales-1-3-1-has-been-released/) Mojarra Scales 1.3.1 Has Been Released Early this morning, I published Mojarra Scales 1.3.1. I’ve been remiss in making good updates where when I make release, so, rather than creating a new post for each release long after the fact, I’ll try to being everyone up to the current state in just one. Much has changed over the past few weeks. We started using Scales in the GlassFish Administration Console as part of UI update, which has been a great vehicle for driving change and finding bugs. One of the most pressing changes, which should have been in since day 1, is the namespacing of the JavaScript code. In 1.3 and earlier, all the JS functions and vars were in the global namespace. As of 1.3.1, they are now in the scales namespace. For the most part, this shouldn’t affect most users, except, perhaps, for those sc:panel. This namespace should go much farther in preventing naming collisions, which is is nice for all of us. :) In case I haven’t mentioned this (it’s really late here, and I honestly don’t remember : ), Scales is now available via the java.net Maven 2 repository. The dependency element looks like this: <dependency> <groupId>com.sun.mojarra</groupId> <artifactId>mojarra-scales</artifactId> <version>1.3.1</version> </dependency> Furthermore, all documentation and issue tracking are now done on Kenai.com (which, I must say, has been really nice so far). One of the things I’ve disliked about the build for the longest time was its dependence on Java 5. This was due to a very odd bug regarding the ant-run plugin, apt, and Java 6. I had never been able to track it down, so I just noted the Java 5 requirement and moved on. I finally got tired of it, and removed the need for apt, which was the annotations that produced the JSF metadata. This change, while certainly fixing the build system, brought another important, and not wholly distasteful change: the removal of JSP support. The XML for custom UIComponent`s in both `faces-config.xml and taglib.xml is not that onerous (though I’ll be happy to see it go in JSF 2 ; ). The TLD (and Tag class) required for JSP, however, is truly awful. Since fewer people are using JSP these days, and that it is all but deprecated in JSF 2, I decided not to reproduce all the JSP support metadata manually and just drop it altogether. If you’re using JSP, I know this may not be good news, but you really should be using Facelets anyway. :) I’ve also removed the dependency on JSFTemplating, which was being used for template-based Rendering. While the feature was nice for me, I had personally run into issue with the dependency in applications (e.g., JSFTemplating was processing my views and not Facelets. While that’s fixable, it’s a hurdle I’d rather not require). Furthermore, many of the components were using Java-based `Renderer`s anyway, so I decide to convert the others and remove the extra dependency. This allowed me to reorganize and clean up a lot of code. I also introduced the use of FacesTester, which I’ve mentioned here a couple of times. While FacesTester is still young and maturing, it has allowed me to test for certain classes of bugs, namely, I can easily insure that all components render correctly, and that UIInput components behave correctly on POST-back. I also test that the state saving code is accurate and complete for each component. In addition, I’m slowly expanding the suite of tests to cover as much of the library as possible, which is good for both libraries. In addition, I’ve added the use of Cobertura to help track and analyze unit test coverage, and Hudson for continuous integration. In addition to those "big ticket items," here’s a quick run down of some other smaller changes, in no particular order: Bug fix in Layout rendering and handling Added a helper function (getLayout()) to acquire a handle to a specific LayoutManager instance Do not render LayoutUnits if rendered=false Added the YUI compressor to the build. This saved up to 53% on some files Got rid of that ugly blue background on sc:layout I think that covers the highlights. If there are any issues I’ve missed or features you’d like to see, please feel free to open an issue, and I’ll get to it as quickly as I can. :) ### [FacesTester Can Now Test State Saving](/2009/facestester-can-now-test-state-saving/) FacesTester Can Now Test State Saving In my experience, a pretty common bug with custom components is improper state saving. Since JSF components are, currently, stateful, it’s important that custom components integrate with the frameworks state saving mechanism correctly. Unfortunately, it can be an error-prone process, as it’s a manual effort. Now, however, custom component authors can use FacesTester to exercise this aspect of their components to help insure proper state handling. This article will show how to use this new feature of FacesTester. Before we start, let’s take a quick look at a very simple component to see what things might look like: public class TestComponent extends UIOutput { public static final String COMPONENT_FAMILY = "com.steeplesoft.jsf.facestester.TestComponent"; public static final String COMPONENT_TYPE = COMPONENT_FAMILY; public static final String RENDERER_TYPE = COMPONENT_FAMILY; private Object[] _state; protected String property1; protected Date property2; public TestComponent() { super(); } @Override public String getFamily() { return COMPONENT_FAMILY; } public String getProperty1() { return property1; } public void setProperty1(String property1) { this.property1 = property1; } public Date getProperty2() { return property2; } public void setProperty2(Date property2) { this.property2 = property2; } @Override public void restoreState(FacesContext _context, Object _state) { this._state = (Object[]) _state; super.restoreState(_context, this._state[0]); property1 = (String) this._state[1]; property2 = (Date) this._state[2]; } @Override public Object saveState(FacesContext _context) { if (_state == null) { _state = new Object[3]; } _state[0] = super.saveState(_context); _state[1] = property1; _state[2] = property2; return _state; } } This is TestComponent, taken from the FacesTester test suite. Note that we declare two properties, the cleverly named property1 and property2, with the appropriate getters and setters. The saveState() and restoreState() methods are what are of interest at the moment. In saveState, we create a new Object[] whose length is the number of properties plus one. In the zeroth element, we put the output of saveState() from our component’s parent, with the remaining entries going to our properties. In restoreState, we pull these `Object`s out of the array, and set them on the properties, casting as appropriate. Conceptually, this code is pretty simple, especially in this simple case. Imaging, though, a more complex component that has, say, 20 properties. The methods quickly grow, making it much easier for errors to creep in. For example, in our 20 property component, we decide to add a new property, property21. We add the declaration to the top of the class, and instruct our IDE to generate our getters and setters, then move quickly to updating the Renderer to use this new property. In our excitement, though, we forgot to update the state saving methods. At first, this oversight is unnoticeable. When the newly update component is added to a page, everything renders as expected, and everyone’s happy. However, a user adds this component to a form and discovers that when the form is submitted and the page is restored, the component no longer renders correctly. To one who has never been bitten by this bug, the cause is subtle and elusive, but, in this case, the cause is broken state saving. On the first request, JSF builds the component tree, and populates the components with the values provided in the page markup. As the page is rendered to the client, JSF creates the saved state object for the UIViewRoot, which includes our component, and saves that either on the server or the client. When the form is POSTed to the server, the UIComponent tree state is restored from the saved state, and this is where the error occurs. Since the component didn’t save the state of this new property, there’s nothing to restore during the RESTORE_VIEW phase, so the property is set to its default value, which is not what the page author expected, so things don’t function or render as expected. So how does one catch this class of error? With FacesTester.testStateSaving(): @Test public void validateTestComponentStateSaving() { FacesTester facesTester = new FacesTester(); facesTester.testStateSaving(TestComponent.COMPONENT_TYPE); } When this method is called, FacesTester creates an instance (origComp) of the component type and queries it, trying to identify all of the properties based on the existence of getter/setter pairs. Once a list of properties has been identified, it passes dummy data to each setter, and then calls origComp.saveState(). Next, it creates a new instance (newComp) of the component, and calls restoreState() on it, passing origComp’s saved state. With the state restored, it then iterates over the identified getters, calling each getter on both components, and compares the returned values. If the values do no match, and `AssertionError is thrown indicating that the property was not correctly handled in the state saving code. As exciting as I think this addition is, I must note that it’s not perfect or bullet proof. It’s certainly possible that a component author might put getter/setter pairs on a component for values that are not considered part of the components state. In those cases, this test will cause invalid failures. For those situations, we may add a "black list" of method names that should not be called. It’s also possible that I’ve missed some other corner cases that will make this test problematic, so if you plan on using this, please note that the interface my change — or even move — as we push toward a 1.0 release. Right now, though, it seems to work fairly well in the tests I’ve put it through. This new API change should be available in the java.net Maven repo for FacesTester 0.2-SNAPSHOT soon. If you use this feature, please let me know how it works for you and what, if anything, you’d like to see changed or added. ### [Happy Easter](/2009/happy-easter/) Happy Easter In Christ Alone: There in the ground His body lay Light of the world by darkness slain Then, bursting forth in glorious day Up from the grave He rose again And as He stands in victory Sin’s curse has lost it’s grip on me For I am His and He us mine Bought with the precious blood of Christ No guilt in life, no fear in death This is power of Christ in me From life’s first cry to final breath Jesus commands my destiny No pow’r of hell, no scheme of man Can ever pluck me from His hand 'Til He returns or calls me home Here in the pow’r of Christ I’ll stand ### [FacesTester 0.1 Released](/2009/facestester-0-1-released/) FacesTester 0.1 Released About a month ago, I announced a new project, FacesTester, a JUnit-based testing tool for JSF that my good friend Rod Coffin and I have undertaken. Since then, Rod posted a very nice introduction to FacesTester usage. Today, we made our first official release, FacesTester 0.1. The version number should indicate that it’s still a work in progress, but it is already quite functional (I, for one, have been using it to build a test suite for Mojarra Scales, which has helped drive out features and resolve bugs very quickly). We wanted to push out a release to encourage people to download it, use it, and give us feedback. So what does FacesTester currently support? Quite a bit. In this entry, we’ll take a quick look at what FacesTester offers, and what we have planned. Without diving into code too much, which Rod has covered nicely, here’s a quick list of what we support: Requesting a page from your JSF app Verifying the existence of a component in the UIComponent tree of a rendered page Verifying the existence of arbitrary substrings in the rendered page Exercising managed beans via EL on a requested page Exercising custom components via a requested page Acquiring a handle (FacesForm) for a form on a rendered page Manipulating form values and submitting the form Validating managed-bean declarations in faces-config.xml Validating custom component declarations in faces-config.xml While that is, I think, a pretty nice set of features, we have more work planned. For example, the faces-config.xml static analysis will eventually cover as many of the valid configuration elements as possible (e.g., Renderer declarations, navigation cases, PhaseListeners, etc); we currently do not support query string parameters, which I’ll be fixing shortly; and so on. If you’re a JSF developer, we’d love for you try this out and tell us what works, what doesn’t, and what you’d like to see. The project is hosted on kenai.com, where we have forums and, most importantly, an issue tracker. You can download the jar file directly from the Kenai project site, or, if you’re a Maven user, the jar is available from the java.net Maven 2 repository: <dependency> <groupId>com.steeplesoft.jsf</groupId> <artifactId>facestester</artifactId> <version>0.1</version> <scope>test</scope> </dependency> Any and all feedback is welcome! ### [My JSFCentral Interview Has Been Published](/2009/my-jsfcentral-interview-has-been-published/) My JSFCentral Interview Has Been Published Careful readers of my blog (thank you, dear wife! : ) will remember that I was interviewed at JSFOne by the conference co-founder and JSFCentral founder Kito Mann. That interview, complete with transcript, has been published on JSFCentral. I was a bit nervous about how it would turn out, but I think it turned out pretty well. I’m not a big fan of hearing my recorded voice, but there’s not much to be done about that. :) ### [The Maven Release Plugin Is Pretty Slick](/2009/the-maven-release-plugin-is-pretty-slick/) The Maven Release Plugin Is Pretty Slick Maven catches a lot of flak from a lot of people. I’ve even been known to bemoan some its eccentricities from time to time. Over the past year and a half, though, I’ve done more and more with Maven, and I’m to the point now where that’s all I use. In fact, Maven and Ant have traded positions in my praise and scorn playbook. At any rate, in releasing FacesTester 0.1 yesterday, I was shown how to use the release plugin (which, by the way, has no parallel in Ant-space that I can see). This plugin helps in releasing a version of a project, updating all the version numbers as appropriate. Here’s a rough blow-by-blow of what happened: I issued mvn release:prepare and mvn release:perform. The plugin asks me what the release version number should be, what the next version will be, and what the SCM tag should be. It has reasonable defaults for all of these, or you can specify something different. The plugin the did the following: Updated the version from 0.1-SNAPSHOT to 0.1 for the parent POM and each submodule Built each module Checked the POM changes into my SCM (Mercurial, btw) Tagged Mercurial to mark the release Deployed the artifacts to the configured Maven repository Updated the version number from 0.1 to 0.2-SNAPSHOT Checked the POM changes into Mercurial Once that was done, I was able to update my development working copy, which got me to 0.2-SNAPSHOT and continue development. It was very, very slick. It’s a two-step process, and I can’t begin to explain the difference between prepare and perform in terms of what gets changed when and where. All I can tell is that it worked really well for me. :) To make it work, though, you need to make sure your parent POM has these two entries: <distributionManagement> <repository> <id>java.net-m2-repository</id> <url>java-net:/maven2-repository/trunk/repository/</url> <uniqueVersion>false</uniqueVersion> </repository> </distributionManagement> <scm> <connection> scm:hg:https://kenai.com/hg/facestester~mercurial </connection> <developerConnection> scm:hg:https://kenai.com/hg/facestester~mercurial </developerConnection> </scm> Of course, your Maven repository and SCM URLs will be different. ;) I also needed to tell the SCM how to login to Mercurial. I did that by adding this to $HOME/.m2/settings.xml: <servers> <server> <id>kenai.com</id> <username>jasondlee</username> <password>...</password> </server> </servers> I didn’t actually try it without the password element there, which I will do next time I use the plugin. I’m not comfortable with putting my password in cleartext there, which is compounded by the fact that the plugin then echoes that password to the console as it runs. Other than that, I was really pleased with the process. Maven, when properly understood, is a much, much better tool than Ant. :) ### [Webinar: From Ajax Push to JSF 2.0: ICEfaces on GlassFish](/2009/webinar-from-ajax-push-to-jsf-2-0-icefaces-on-glassfish/) Webinar: From Ajax Push to JSF 2.0: ICEfaces on GlassFish The GlassFish webinar series is, I think, a pretty valuable resource for regular readers of my blog, as it covers a lot of topics that I cover here. Today’s webinar, "From Ajax Push to JSF 2.0: ICEfaces on GlassFish," is particularly relevant, as it’s a JSF-related session. Here’s the abstract: Ted will provide details on how to build and deploy rich web applications with Ajax and Ajax Push (aka Comet) and catch a glimpse of the future with an overview of JavaServer Faces 2.0. This presentation illustrates the fundamentals of Ajax Push, covering application design, development, and deployment, drawing on ICEfaces sample applications and implementation. Topics will include network protocols, application-level push APIs, GlassFish Grizzly integration, and the ramifications of the two-connection limit. Looking forward to JSF 2.0, we will cover Ajax integration, new scopes and annotations, and custom components. I had the opportunity to see Ted present Ajax Push (their term for Reverse Ajax or Comet, if you prefer those monikers) at last year’s JSFOne conference. The ICEfaces demos are very, very slick, and the level of simplicity they managed to achieve is absolutely amazing. If you have any interest in Ajax Push/Reverse Ajax/Comet, you should certainly attend this session. If you are currently using JSF, this is a really good example of the power of component-based frameworks like JSF. ### [Announcing FacesTester](/2009/announcing-facestester/) Announcing FacesTester One of the issues that has always troubled me with regard to writing JSF applications (or any web application, really) is how hard it is to test them. Some time ago, while discussing various Java web frameworks, I stumbled across a class called WicketTester, which is part of the Wicket project. Using this class, as best as I can tell, Wicket authors can easily test their applications very quickly. Having taken the advice of Dale Hanchey, and old college professor of mine, "Never be too proud to steal a good idea," FacesTester was born. Unit testing a JSF application can be tricky, and there are a lot of different opinions and techniques for doing so. Stan Silvert from JBoss, for example, just released a GA version of JSFUnit, an in-container end-to-end testing framework for JSF. Dan Allen, also of JBoss but working on the Seam project, recently discussed SeamTest in this wiki entry. What bothers me about both of those solutions, though, is the need for a container. What I’d like to be able to do is write a plain, simple JUnit test to exercise my managed beans, converters, etc. without the start-up penalty of starting a container (even if it’s embedded) or deploying a .war to a container. That’s where FacesTester fits in. Though in a very early stage, FacesTester is intended to allow a JSF application developer to inspect the component tree, validate the logic and/or output of managed bean methods, etc. with a very simple and light weight API. As exciting as that may sound (I don’t know about you, but in my head, it’s REALLY exciting : ), don’t get carried away yet. I started this project in a very low-key fashion several weeks ago, and poked at it in my scant free time. Last week, though, I got a call from my good friend Rod Coffin, who had some unrelated JSF questions. In the course of the conversation, testing came up, and I mentioned this pet project of mine. Rod, a huge proponent of testing in general, immediately bit on the idea and volunteered to help. Since that conversation, we have gotten the project to the state where we can instantiate the FacesServlet and request a page from our application. We can then request a specific component and perform various tests on it. Since we’re leveraging the real, live FacesServlet, we get all the JSF goodness, including EL support, for free. Here’s an example (contrived, dumb, simple, etc) test: <h:form id="form"> <h:outputLabel id="stateLabel" value="State"></h:outputText> <h:outputText id="elTest" value="#\{4+5}"></h:outputText> <h:outputText id="renderedTest" rendered="false" value="RenderedTest"> </h:outputText> </h:form> Given that page definition, we can then test it like this: public class WhenNavigatingToPage { private FacesTester tester; @Before public void setUp() throws Exception { tester = new FacesTester(); } @Test public void shouldBeAbleToAssertValueOfComponents() throws Exception { assertThat(tester.requestPage("/address.xhtml").getComponentWithId("form:stateLabel") .getValueAsString(), is("State")); } @Test(expected = AssertionError.class) public void shouldBeAbleToAssertValueOfNoExistentComponents() { tester.requestPage("/address.xhtml").getComponentWithId("unknown"); } @Test public void shouldBeAbleToEvaluateEl() throws Exception { assertThat(tester.requestPage("/address.xhtml"), is ("9")); } @Test public void shouldBeAbleToTestRendered() throws Exception { FacesComponent component = tester.requestPage("/address.xhtml") .getComponentWithId("form:renderedTest"); assertThat(component.getValueAsString(),is ("RenderedTest")); assertEquals(component.isRendered(), false); } } As cool as that is, that’s about the extent of the API at the moment, but Rod and I are very excited about what we might be able to offer with this. The next big step for me is to get form submission working, and Rod is going to look at writing more tests and letting those drive the capabilities of FacesTester, as well writing some unit tests around bootstrapping the environment from different web.xml files. There’s a lot to be done still, so if you’re interested, head over to the project home page on kenai.com and join the fun! ### [Opinions Wanted: v3 GUI Prototype](/2009/opinions-wanted-v3-gui-prototype/) Opinions Wanted: v3 GUI Prototype As I mentioned in a recent post, we’re investigating some changes to the GlassFish v3 Administration Console. We finally have something fairly concrete to show, and have set up a demo site for you to play with. Ken Pauslen sent an email regarding our demo to the GlassFish users' list, so instead of repeating all of that, I’ll simply quote his email for you below. Note the comment on performance toward the end. :) Please send feedback to the link:mailto:webtier@glassfish.dev.java.net?subject=RE: Opinions Wanted: v3 GUI Prototype[webtier list] or the link:mailto:dev@glassfish.dev.java.net?subject=RE: Opinions Wanted: v3 GUI Prototype[dev list]. Many thanks! :) Hi everyone, The GlassFish admin console team has been working hard on ways to simplify our development, while at the same time attempting to improve the experience of using the console. We have created a prototype which shows a couple different designs we are considering…​ we’d like your feedback on what you think of it. Here’s how you can help: Try the working prototype at: http://63.227.208.233:9999/admingui/ Respond to this email or to my blog that I am about to write about this (http://blogs.sun.com/paulsen). I think Jason and Anissa will probably write too (http://blogs.steeplesoft.com/ or http://blogs.sun.com/anilam/). Here are some things we are particularly interested in feedback on: Do you like/dislike the menus? Do you like/dislike the tree? Do you like/dislike the tagging feature? Of course all other comments are also welcome (what’s missing? what do you really like? what do you dislike? etc.). We know there are many issues with this UI, it is an early prototype — far from production ready. Some major issues we’re aware of: Many broken button clicks (particularly posts that don’t do a redirect) Performance — it’s not good right now, it will be MUCH better when it’s not a prototype (note: it also doesn’t help that this prototype is running on a small desktop machine over a DSL-line…​ ;) ). Many pages are broken (some intentionally for the public demo, others are simply not implemented) List of tagged pages can sometimes show duplicates Ajax for updating tags and other portions of the screen is not implemented Breadcrumbs do not exist So…​ as you can see we’re not looking for bugs, but rather general feedback on the navigation and L&F. Thanks for taking a look! Thanks, Ken Paulsen (and the rest of the GF Admin Console Team) ### [What's Happening In the World of Mojarra Scales?](/2009/what-039-s-happening-in-the-world-of-mojarra-scales/) What's Happening In the World of Mojarra Scales? I’ve been a bit silent of late on what’s happening with Mojarra Scales, so I thought I’d take a moment to bring everyone up to speed. For starters, and I guess this is the official announcement of this, I’ve moved the project from java.net to kenai.com. Anyone who has used java.net knows that it has gotten a bit long in the tooth, as they say. Frustrated with grossly inadequate site support and desiring to use Mercurial for source control — not to mention flee the frequent outages and slow downs — I jumped to Sun’s new community platform, Kenai. It offers several SCM choices, bugzilla or (drum roll, please!) JIRA support, and sports a nice wiki for web site development, which alone has made documentation MUCH easier. I’ve been very, very happy with Kenai. If you can snag an invite to create a project, you should do so. If you’re interested in helping with Scales development, I can easily add you to the project without an Kenai invitation. Secondly, I released version 1.1, somewhat sooner that I had hoped. As I noted in an earlier entry, we’re investigating some possible changes to the GlassFish Administration console. As part of the work, we integrated Scales into the console to handle the menu work. At the time, the version was 1.1-SNAPSHOT. Our release engineers balked at the version number, as the GlassFish promoted builds can not rely on SNAPSHOTs of external projects, as the build is not reproducible. Given that very sensible requirement, I tidied things up as much as possible and pushed out 1.1, which can be downloaded here. So what’s happened since then? A fair amount: As part of the Scales 1.1 release, I added the "flat" option to the panel, which will render the panel inline in the document. This allows one to embed the panel "in" the document, rather than having it "float" above it. A couple of the default values for the panel have changed as well: o draggable: true o visible: true I’ve done some work to reduce the weight on the page. Since the YUI resources are all stored in a JAR file, the URLs to images, CSS, JS, etc have to be changed so the server can find and send them. Until recently, the CSS override snippets that handled that was rendered once for every component on the page, which is obviously overkill. I added some logic to make sure that renders only once. I’m planning on some additional work there to render only what’s needed, but this is a good start. I also switch from sending yahoo-min.js, dom-min.js, etc., to utilities.js, which includes a number of JS files needed by most of the components. While this will end up sending more data than is needed in some cases, it also reduces the number of requests a great deal, which I think is a good trade-off. One complaint we heard when working with Scales in the GF admin console was the size of the JAR, so I spent some time tuning what gets included. We now only package the minimized JS files that we actually use. I was blindly including every file (minimized, non-minimized AND debug versions) of every component Scales wraps. That was an obvious waste, so the build is now much more specific in what gets included, which, when coupled with the removal of old images and JavaScript that are no longer used, resulted in a JAR about 1/3 of its original size. In 1.2-SNAPSHOT, Scales now uses YUI 2.7.0. This gets us a number of bug fixes, the most notable of which concerns the vertical carousel demo. I added a couple of simple CSS tweaks, which now allows the vertical carousel to render and function as expected. As part of the GF console redesign, I implemented a wrapper for the YUI Layout Manager component, giving rise to two new Scales components, sc:layout and sc:layoutUnit. Their usage looks like this: <sc:layout fullPage="true"> <sc:layoutUnit position="top" height="75" gutter="5px" resize="true" collapse="true" maxHeight="100" minHeight="50"> <span style="font-size: large; font-weight: bold"> This is my header. There are many like it, but this one is mine! </span> </sc:layoutUnit> <sc:layoutUnit position="left" width="125" minWidth="125" maxWidth="200" gutter="5px" resize="true" collapse="true"> This would probably be some navigation stuff. </sc:layoutUnit> <sc:layoutUnit position="right" width="125" gutter="5px" resize="true" collapse="true"> Some random site stats, links, etc to clutter the page. </sc:layoutUnit> <sc:layoutUnit position="bottom" height="75" gutter="5px" resize="true" collapse="true"> <span style="font-size: large; font-weight: bold"> This is my footer. There are many like it, but this one is mine! </span> </sc:layoutUnit> <sc:layoutUnit position="center" gutter="5px"> <!-- snip! --> </sc:layoutUnit> </sc:layout> You can see how that renders on the demo site. I think those are all the major changes worth noting. Hopefully, by the end of the week I’ll Scales in the java.net Maven repo, but I’m waiting on a package/groupId decision to be made for Mojarra, which we’ll then follow with Scales, since it is a sub-project of Mojarra’s. If you have anything else you’d like to see (that’s not already in the java.net issue tracker), please file a request on the Scales JIRA instance. ### [Another NetBeans Update](/2009/another-netbeans-update/) Another NetBeans Update Since the announcement in the recent layoffs at Sun on how the NetBeans team was affected, there’s been much concern over the health of the project. I’m not on the NetBeans team (I’m just a big Finkel fan! ;) so I can’t say for certain what’s going on, but it seems to me that Sun is still committed to the platform. Evidence of that comes in the form of an email I got today about the upcoming 6.7 release. Here is the email: For those of you who have been following the NetBeans release train, you may be puzzled by the version number switch in our upcoming milestone release, from NetBeans 7.0 to NetBeans 6.7. To get innovation and quality improvements out to the community faster, and to have the NetBeans IDE be better aligned with the release schedules of other technologies that it supports, we have decided to concentrate on a series of smaller releases rather than the traditional two big releases per year. With this new focus on smaller releases, we renamed the next release according to our numbering guidelines: Point versions (for example, 6.0 to 6.1) indicate less change, and API compatibility. A whole number version jump (for example, 5.0 to 6.0) reflects major feature changes within the NetBeans IDE, and possible API incompatibilities. These guidelines communicate, in a general way, the level of change to expect in the NetBeans IDE, and we always want to meet these expectations. At this time, NetBeans 6.7 is the best possible product that we can deliver by June 2009. We are confident that this is the right move for the NetBeans IDE and for our users who have come to expect top quality releases. And why are we skipping a version between 6.5 and 6.7? Well, there are negative associations with the number 6.6...6. Though we appreciate a good laugh, this is not the permanent association we want for the IDE. NetBeans 6.7 is scheduled for release in June 2009. The main features are Maven and http://kenai.com/[Kenai] integration, and there are many smaller features that you can read about on the http://wiki.netbeans.org/NewAndNoteWorthy[New and Noteworthy] page. Java EE 6 support is planned for a future release. *NetBeans 6.7 Milestone 2 is due out next week*. We encourage you to download the release when it becomes available and to give us your feedback. Thank you for your continued support of the NetBeans IDE. The NetBeans Team While you’re all capable of reading things for yourself, I’d like to highlight two things. First is the rationale behind the version number: "And why are we skipping a version between 6.5 and 6.7? Well, there are negative associations with the number 6.6…​6. Though we appreciate a good laugh, this is not the permanent association we want for the IDE." Not in any way important, but I thought that it was hilarious. :) On a more serious note, here are some of the highlights (for me) of the major changes coming in 6.7 (or full details, click the New and Noteworthy link in the email above): Importing plugins from previous release into new one Maven project support Compile On Save support Improved, more powerful Add Dependency dialog with as-you-type searching in Maven repositories…​ Better POM xml editing support like support for generating profiles, dependencies via Alt + Insert shortcut PHP Generating Getters and Setters Improved SFTP support added Parameter Info Code completion for constructors Marking returns Go to type for class members - improved SQL code completion in the PHP editor Marking occurrences improved JavaScript - Support for JavaScript 1.7 (More information) Lots of neat stuff, but the one I’m most excited about is that first one: importing plugins. That I had to re-install all of my plugins. Since I don’t have to do that anymore, I think I’m going to go grab M1, even though M2 is coming out tomorrow. I love the bleeding edge…​ :) I didn’t see any mention of Python support, though. I hope I just missed that…​ ### [Leveraging Identity with GlassFish and MySQL](/2009/leveraging-identity-with-glassfish-and-mysql/) Leveraging Identity with GlassFish and MySQL Late last year and early this year, I spent a great deal of time to author/edit a white paper detailing the deployment of Sun Identity Manager using GlassFish and MySQL. The paper, with additional input from Ed Ort, Suveen Nadipalli and John Clingan, gives a brief introduction to what identity management is and why you’d want it, then covers the whats, hows, and whys of MySQL and GlassFish installation, the installation and configuration of Sun Identity Manager, tuning the system, and ends with a quick look at the total cost of ownership. I think we put together a very nice paper on a very interesting and oft-overlooked piece of enterprise data management. If you’re interested in reading more, you can click here for the download page. ### [NetBeans Program Update - Feb 2009](/2009/netbeans-program-update-feb-2009/) NetBeans Program Update - Feb 2009 Are you a NetBeans user? Are you wondering what’s going to happen to your IDE of choice given the recent Sun restructuring? The NetBeans Dream Team Call with Matt Thompson the new Sun NetBeans Director, which starts at 10:00am CST today (I just learned about it too) should answer some of your questions. Here are the details: NetBeans Program Update - Feb 2009 with Matt Thompson (the new NetBeans Director + Developer Cloud Tools Engineering) SLIDES ARE HERE WED Feb 11th at 0800am Pacific; 11am US East Coast; 5 pm Europe US Toll Free Dial-in Number: 866-803-2141 CALL ID: 5121251 Participant Code: GO Here: http://nbdt-feb09.eventbrite.com/ We will be recording this call for later playback on this event page. Tentative AGENDA: * Intros and NetBeans team changes + Sun’s Cloud Initiative – Matt Thompson (15 minutes) * Discuss future topics about upcoming NetBeans Technical Calls — What does the dreamteam want to talk about first…​open mic vote if necessary w/Matt…​ (15min) * Open Communication Q & A What is on your Mind?? – All (30 minutes) ### [Webinar Covering GlassFish's ASadmin Tool](/2009/webinar-covering-glassfish-s-asadmin-tool/) Webinar Covering GlassFish’s ASadmin Tool Today at 1:00PM CST, the GlassFish team will host a webinar discussing the asadmin utility that ships with GlassFish. Here’s the official annoucment by Eduardo Pelegri-Llopart (webified be me : This week’s webinar set presents ASadmin, the GlassFish administration CLI. The GlassFish GUI console is well designed and very well appreciated by the users but GUIs are not best for automation and power users tend to use CLIs for that reason. The ASadmin console has been called the "hidden gem" in GlassFish; hopefully this webinar will make it a bit less hidden. The presenter is the asadmin lead, Jane Young. We are likely to also have a panel on the value of asadmin with two non-Sun heavy users of asadmin: Dan Allen and Dick Davies. This is a free, online, presentation. The presentation will be recorded and made available later for replays. Presentation Date/Time: Jan 22nd, 11amPT - Other TZs Online at Ustream. Concall for Speakers (others, please mute with *6) Toll Free: (866) 545-5227 Int’l Access: (215) 446-3648 (caller paid) Access Code: 3535518 Additional details: here ### [Free JCP Membership for JUGs Through the End of February](/2009/free-jcp-membership-for-jugs-through-the-end-of-february/) Free JCP Membership for JUGs Through the End of February If you are a member of a JUG (or happen to run one) and would like to be able to join the Java Community Process (JCP), you now have two options. For US-based JUGs, you can affiliate yourself with the new umbrella JUG-USA. According to Van Riper of the Silicon Valley JUG and the coordinator of the JUG-USA effort, all you need to do to be affiliated with JUG-USA is promise to link back to the JUG-USA Map and let him know. As an affiliated JUG, you have access to the JCP, including JSR submission as well as Expert Group membership, through JUG-USA. If, however, you’d like to have your JUG become a member directly, which is currently the only option (that I know of) for non-US JUGs, you can follow these directions (thanks, again, to Van Riper): If you want to do this, it is actually quite easy to do and the process is fairly well documented here for organizations joining the JCP: http://jcp.org/en/participation/membership2 You simply follow the 6 steps listed on the page above. Since JUGs are being given special treatment with organization membership fees waived, two of these steps are a bit fuzzy. I had a chance to talk to Patrick Curran at the recent JCP Birthday Party to clear up the fuzziness though. So, follow the 6 steps with these two clarifications: You can skip step 4. You should not initial any of the listed "Process Cost Sharing" choices on page 3 of the agreement. There is none that apply to our special situation. For step 6, you do need to fill out both sections on page 11 of the agreement. Even though your JUG membership cost will be zero, Patrick indicated that they will need the "Accounts Payable Contact Person" section filled in. However, that person won’t be receiving a bill or the bill will have an invoice amount of zero. Once you have completed the agreement, you follow the instructions on this page to either FAX it or mail it to the JCP Management Office for processing: http://jcp.org/en/participation/membership_submit That is all there is to it. As a point of reference, my individual membership agreement was processed in just two days time after faxing it in. It is possible that organization memberships will take longer to process than that. If you do not get confirmation back within a week, I would contact the JCP Management Office to check on your membership processing. The Oklahoma City Java Users Group, Inc. will be utilizing both methods. :) ### [Mojarra Scales Gets a Z-Order Update](/2009/mojarra-scales-gets-a-z-order-update/) Mojarra Scales Gets a Z-Order Update As I noted in a recent entry, we are considering moving to a desktop-like interface for the GlassFish Administration Console, where the content is in separate "windows" (decorated DIVs, basically) which can be moved, closed, minimized, etc. As I’ve started working on a concrete implementation of some of those ideas, I quickly realized that we were going to have issues with multiple, overlapping windows. Once you have multiple windows open, the user has to be able to bring the desired window to the front, but YUI, which will likely be the library used, doesn’t support that natively. Fortunately, that’s easy to fix. First, an example of the problem: With stock YUI, as best as I can tell, if you want to look at Window #2, you’re out luck. With this simple JS, though, the problem is quickly solved: var currentMaxZ = 1; registerPanel = function(id, panel) { scalesPanels[id] = panel; YAHOO.util.Event.addListener(id, "mousedown", bringToFront); currentMaxZ++; } setZToMax = function (target) { YAHOO.util.Dom.setStyle(target, 'z-index', ++currentMaxZ); } bringToFront = function (event) { setZToMax(event.target.parentNode.parentNode); } There may be more elegant approaches, but here’s how this one works. When the page first loads, the variable currentMaxZ is set to one. As each windows is registered (a requirement I put on the page), the variable is incremented, and an "onclick" handler is attached to the DOM element. Now, when someone clicks on the panel/window/dialog, whether it’s a simple click or a click to drag, bringToFront is called, which determines the actual DOM element that needs to be manipulated (due to how YUI works, the DOM isn’t as simple as it may look in your markup), then delegates to setZToMax (it’s a separate function so that other parts of Scales can reuse the functionality) which increments currentMaxZ and sets the target’s z-index style property to that value. Once that’s done, the window is brought to front, as expected. Having worked out how to do that, I’ve added this functionality to Scales (which will likely be used in the GlassFish console, if only just for this exploration) and committed that to the repository (about which I need to post, but that will have to wait a bit longer). If you’d like to see this in action, point your browser here (there is, at the moment, an odd rendering bug I’m trying to track down) and let me know what you think. ### [Bootstrapping a JSF 2 project](/2009/bootstrapping-a-jsf-2-project/) Bootstrapping a JSF 2 project I needed a break this afternoon, so I thought I’d see how easy it is to bootstrap a JSF 2 project. One of the biggest complaints about JSF 1.x is all that XML, so JSF 2 is aiming to fix that. How have we done so far? Based on this quick look (which is my first from-scratch JSF 2 app), really, really well. Here are the steps I took: Create a web app project using the Maven archetype (because I’m lazy that way : ) : mvn archetype:create -DgroupId=com.mycompany.app -DartifactId=my-webapp \ -DarchetypeArtifactId=maven-archetype-webapp Add FacesServlet to web.xml: <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> Add the JSF 2 jars (and their repo) to pom.xml: <repositories> <repository> <id>maven2-repository.dev.java.net</id> <name>Java.net Repository for Maven</name> <url>http://download.java.net/maven/2</url> </repository> </repositories> <dependencies> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.0.0-b08</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.0.0-b08</version> <scope>compile</scope> </dependency> </dependencies> Create a managed bean: @ManagedBean(name="main", eager=true) public class MainBean { public MainBean() { System.err.println ("MainBean starting up!"); } public String getText() { return "Here is some text!"; } } Create the view: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"> <head> <title>Should Not Be Displayed</title> </head> <body> <ui:composition> <ui:define name="content"> #\{main.text} </ui:define> </ui:composition> </body> </html> Build, deploy, browse Your web browser should now say "Here is some text!" Did you notice that all but two of those steps are things you would do for any Java web app? As soon as someone creates a JSF 2 Maven archetype, even that can be simplified. Also notice that there was no mention of faces-config.xml. The application doesn’t have one. Granted, this is an insanely simple application, so the need for faces-config.xml may still arise (navigation comes to mind, but I think we’re working on a simplification for that too). The rule of thumb seems to be that JSF is not well-suited for smaller, simpler apps where things like Grails, RoR, etc. are a better choice. I think we’ll see that JSF 2 changes that. ### [My Thoughts on AT&T U-verse](/2009/my-thoughts-on-at-t-u-verse/) My Thoughts on AT&T U-verse In a recent discussion, the fact that I have AT&T U-verse came up. I was asked what my thoughts on it are, and I promised a blog about it. This entry is the somewhat belated fulfillment of the promise. First off, for those that don’t know, U-verse is, as best as I can tell, their answer to cable television. With the full package, which we have, you get a digital phone line, digital television, and high-speed internet all over fiber. Since the cable companies are offering telephone, it seems the phone companies are now offering television, with everyone in on this internet thing. For the impatient, the punch line here is that it’s a nice, but not perfect, offering. Let’s jump into the details. As I noted, U-verse offers phone, internet, and television. We’ll start with the phone, as it’s probably the least…​interesting of the three. If you have digital telephone, there’s not much exciting here. If you have a plain ol' telephone (POTS) line, then you’re in for a treat. As you may or may not know, I work for Sun Microsystems from home. Being remote, I spend a lot of time on the phone. On my POTS line, I had a pretty awful buzz on the line, even though my house is brand new. After U-verse phone was installed, calls are crystal clear. No more I’m-sorry-can-you-repeat-thats. It’s made a huge difference for such a simple thing. The internet, much like the phone, is not that interesting, I guess. If you have cable or DSL (I’m inclined to think U-verse high-speed internet is not DSL, but I’m not 100% sure), then you may not be immediately excited. While I discuss the physical part of U-verse in a moment, it’s worth noting here that I have a fiber optic line to the wall of house, with copper on the inside. Given the fiber…​backbone, I expect I’ll be able to get some really fast speeds, and that’s already proving to be true. Currently, the offerings are 1.5/1.0, 3/1.0, 6/1.0, 10/1.5, and 18/1.5 Mbps down/up. Unlike the shared medium of cable, in which performance is said to degrade as more people in your neighborhood use the network, you get all your bandwidth with U-verse. For example, I recently upgrade my line from 1.5Mbps down to 3Mbps down. Here’s the before and after from speedtest.net. Note that both are near their max speeds in both directions. The most interesting thing to me from U-verse is the TV/DVR package. As a (sadly) former MythTV user, I have extremely high expectations from my DVR. As a High Def (HD) customer with a low (these days) tolerance for hardware and software hacking, I’m forced to use the provider’s DVR. On the whole, the U-verse DVR is OK, but it falls far short of the MythTV experience, as well as that offered by DishNetwork. On the up side, it has a pretty intuitive interface, the channel line up is great, and the picture quality is excellent (and doesn’t degrade or disappear during storms, thank you DishNetwork!). Having said that, the DVR does have its faults. One of the things we actually liked about the DishNetwork DVR was the ability to restrict the number of episodes of a given show that are kept. In our case, there are a number of children’s programs we record for our boys which come on just about every day. After just a week or two, that’s a lot of disk space taken up Curious George, Imagination Movers and Sid the Science Kid. With DishNetwork, we could easily limit the number to, say, five episodes, and the DVR would automatically purge the oldest episode. With the U-verse DVR, I do that manually. As you can probably imagine, it’s tedious and annoying. Another oddity is DVR access from other rooms. When the system was first installed, if we wanted to watch a recorded program, we had to do it in the living. Typically, that’s OK, because that’s where the 52" is, but, occasionally, we might want to watch a Psych from our bedroom before we turn in. Until recently, that wasn’t possible. To their credit, AT&T recently released "Total Home DVR" which was a transparent upgrade (transparent in that I have no clue when it was installed. The system just did it automagically), which enabled limited DVR usage in other rooms. This is an improvement, of course, but it appears to be read only. We don’t seem to be able to schedule new recordings or delete existing ones. Better than nothing, I guess, but it still has a way to go. Of course, what DVR from an internet provider would be complete without web access? The good news is that U-verse offers that. The bad news is that it is leagues behind MythWeb. Look at the screen shot to the right. What you see there is pretty much the most exciting page in the system. Like Total Home DVR, it’s better than nothing, but I think the developers on that part of the system would be well-served to look at MythWeb. The search functionality also is not quite up to par with either MythTV or DishNetwork. U-verse only searches by program name, whereas the other two solutions would allow me to search by program type (TV show, movie, documentary, etc). This lack isn’t a major issue for us, but it’s little usability features like this one that make the U-verse DVR sub-par. While it may sound like I’m being really harsh on the system, I do enjoy and recommend it, but it certainly has a long way to go to catch the competition (with MythTV being the best by far of all those I’ve seen, including U-verse, DishNetwork and Cox). Before I wrap this up, I thought I’d give a little insight into what one can expect physically in a U-verse installation. That is, what will the technician do to your house? In my case, it wasn’t too much. As I noted earlier, U-verse is fiber-based, so AT&T had to run fiber to my property (which it had already done for every lot in the neighborhood). From there, they ran more fiber to a box they installed on the outside of my house, in my case, to the back of my garage. The installer then drilled a hole through the brick, all the way into the interior of my garage. Next, he went inside the garage and hung two boxes on the wall next to the hole. One is a power supply, and the other is the "brains" (if I recall correctly) of the system. I won’t pretend to know exactly what it does in detail, but suffice it to say that it makes the system work. From there, he hooked the brains into the wiring in my house. Since my house is brand new (well, as of November 2007), I had cat 5e and coax run all over the house, so he was able to use that. If you don’t have at least cat 5 wiring, I expect your installation will take longer and be more invasive. Having done that, he then installed a 2Wire device that manages the voice and data network. This device serves as my "modem" as well as my access point, even offering basic firewall functionality (port forwarding, protocol blocking, etc). Once this was installed, all my normal phones began working again with no additional setup or hardware required. On the DVR front, the set top boxes (sadly powered by Windows Media Center, thus making my "Microsoft-free home" claim not completely accurate :) were installed on each TV requested. These boxes used the coax installed when the house was built, so there was no additional configuration here, either. He may have had to do some wiring in the wiring "cabinet" the builders installed, but there was not hole cutting required, which please both me and my wife. : ) One last thing to note: In the event of a power outage, the system DOES have a battery backup, but it will only last for so long. That being so, AT&T suggests that network usage (including voice, internet, and TV) be limited, as the more network traffic that occurs, the shorter the battery backup will last. They also strongly urge an alternate means for making phone calls, such as a cell, just in case the outage lasts a long time. We haven’t been hampered by this yet despite a couple of power outages, but we also have cell phones, so it’s not a big deal. For the security conscious, our home security system works seamlessly with the U-verse phone system. For all the phones and security system can tell, they’re hooked up to a POTS line and are as happy as can be. Clearly, U-verse, as a whole, is not a perfect system, but the release of Total Home DVR shows that AT&T engineers and technicians are still working on improving the system, so any faults it has today may not be there tomorrow, which is always a good thing. Overall, we are very happy with the system and recommend it whole-heartedly. In our books, despite minor irritations, the speed, clarity, and availability make it worth the money. ### [JSF 2 Gets Declarative Event Handling](/2008/jsf-2-gets-declarative-event-handling/) JSF 2 Gets Declarative Event Handling If you’ve been following the evolution of the JSF 2 spec closely, you have probably seen the addition of a finer-grained event system (if you haven’t seen it, section 3.4 of the spec is the relevant one). These events include things like AfterAddToViewEvent, BeforeRenderEvent, ViewMapCreatedEvent, etc. An application developer could subscribe to these events from a managed bean by using the API exposed by the new system. While that is a big improvement over the way things work in 1.2, it still leave page authors out in the cold until, that is, this week. Yesterday I committed the code to support declarative even handling to Mojarra. In this short entry, we’ll take a look at what that entails, and how to use it. This change really has two parts: a new f:event tag, and a new @NamedEvent annotation. Let’s start our discussion by looking at the tag. The syntax for the tag is really quite simple. You just add the tag to any component you desire, provide values for the tags only two attributes, and you’re done. For example (from the Mojarra systests): <h:outputText id="beforeRenderTest1" > <f:event type="beforeRender" action="#\{eventTagBean.beforeEncode}" /> </h:outputText> In this simple example, we see that we an outputText component, beforeRenderTest1, with no value. We also have the child f:event tag. The first parameter, type, tells the tag which event type to which to subscribe. The second attribute, action, specifies the method on a managed bean that will be called when the event requested is fired for the component in question. In plain English, when JSF broadcasts the BeforeRenderEvent for the component beforeRenderTest1, EventTagBean.beforeEncode() will be called. So what does that method look like? The specification states that the action must match this signature: public void methodName(ComponentSystemEvent event); Note that we are only dealing with ComponentSystemEvent, a child of SystemEvent not SystemEvent`s directly. Why? Well, `ComponentSystemEvent is the base class for SystemEvent`s that are attached to a specific component instance, which is `HtmlOutputText in our example. That method might look like this: public void beforeEncode(ComponentSystemEvent event) { UIOutput output = (UIOutput)event.getComponent(); output.setValue("The '" + event.getClass().getName() + "' event fired!"); } Your method would, I hope, do something more interesting, but we can see here how we handle the event. We pull the UIComponent from the event object, optionally cast it to what we’re expecting (probably using a healthy dose of instanceof), and perform some actions on the component, but you might not even need the component. Maybe you just need to fire off some sort of backend logic/process when a component is rendered, for example. I’m not sure why, off hand, but you could, and this new tag makes that possible. Before we close our discussion of this new tag, let’s take a quick look at the new annotation, @NamedEvent. One of the envisioned uses of this new event system is that application authors will likely want to create their own custom events. All that is required to do so is to extend SystemEvent, either directly or indirectly through one of its children, and the broadcast the event when appropriate. What if, though, the application author wants to make this event available to the page authors? That’s where @NamedEvent comes. This annotation, which has the single, optional attribute shortName, can be placed on custom events to register them with the runtime, making them available to f:event. During application startup, JSF scans for a number of annotations, including our new one. If @NamedEvent is found on a class, the following logic is applied to get the name(s) for the event: Get the unqualified class name (e.g., BeforeRenderEvent) Strip off the trailing "Event", if present (e.g., BeforeRender) Convert the first character to lower-case (e.g., beforeRender) Prepend the package name to the lower-cased name (e.g., javax.faces.event.beforeRender) If the shortName attribute is specified, register the event by that name as well. For the spec classes, the only events registered for use with f:event are BeforeRenderEvent, AfterAddToParentEvent, and AfterAddToViewEvent, with the appropriate short names as well, giving us these possible events out of the box: Long Name Short Name javax.faces.event.beforeRender beforeRender javax.faces.event.afterAddToParent afterAddToParent javax.faces.event.afterAddToView afterAddToView Armed with that knowledge, we could easily rewrite our markup below as <h:outputText id="beforeRenderTest1" > <f:event type: "javax.faces.event.beforeRender" action="#\{eventTagBean.beforeEncode}" /> </h:outputText> Which you use is up to you. It’s important to note that, while the spec is currently in feature freeze, that doesn’t mean it’s done. While what you see now is largely what you’ll see when we ship JSF 2 and Mojarra 2.0, some things may be slightly different. If anything changes in this are before we finalize the spec, I’ll make sure I update you here. ### [Changes Are Coming to the GlassFish Admin Console](/2008/changes-are-coming-to-the-glassfish-admin-console/) Changes Are Coming to the GlassFish Admin Console GlassFish isn’t just an application server. It’s a community. For that reason, we on the admin console team want to take some time to run some ideas by the user community. For the GlassFish v3 final release due in the middle of next year, we plan to redesign the admin console. Since the admin console is usually high on the list of differentiators, we are approaching these changes very cautiously, as we don’t want to ruin a good thing. Our goals are to make the console lighter and faster, and use a more modern design. Our plan, then has several parts, which we’ll look at individually. Table of Contents What we’re removing Frames Tree Navigation What we’re adding Menus Desktop Paradigm Dock Bar Searching and Tagging Preferences What we’d like from you What we’re removing Let’s start this discussion by listing what we want to get rid of. Frames --- The general concensus amongst web developers these days is that frames are no good, and we agree, so we’re going to get rid of them for several reasons: Less redundancy in serving multiple resources to the various frames - Since each frame is bascially its own document, various resources are requested by each frame. Specifically, since each frame uses the same JSF component set, each frame requests the various Javascript and CSS files, for example, resulting in many, many duplicate trips to the server. If we can cut down on the number of trips back to the server, we’ll see a lighter, snappier UI.</li> Better UI experience - Having frames either breaks a lot of things, or makes them difficult or awkward. For example: Printing a page in a frameset ie harder than it ought to be. Extra care must be taken when using the mouse wheel to scroll to make sure you’re over the correct frame. The use of the back button sometimes doesn’t do what you think it might. Screen real estate is wasted on the the frames' scrollbars, etc. </li> Opportunity for bookmarkable URLs - One of the big problems with frames is that they make it difficult to link easily to a specific page. Sure, the user can right click on the frame, open that frame in a new tab and then get the correct URL, but that’s not user friendly at all (in fact, it’s as un-funny as its namesake comic strip!). If we remove the frame, the page you’re on is the location bar at the top. Copy. Paste. Done.</li> Reduce implementation complexity - JSF only caches a certain number of pages for you, so if you don’t use a frame for while (the header is the best example of this), it’s server-side state may no longer be cached, which will cause the application to throw an exception. If the pages don’t live in a frame, there’s no chance for the view’s state to be purged from the cache.</li> Don’t need to worry about the artificial boundaries that frames impose (menus overlapping frames, JS across frames, etc). - Our UI choices are a bit limited, especially in the tree navigation and header frames, as content from the frame can’t extend beyond the frame’s boundaries. It is either clipped, or the frame displays scroll bars. For that reason, we have to make sure our content fits inside the frame, or increase the frame size when we need more room. It makes for a less than ideal user experience, and some pretty ugly code, so it has to go. :)</li> Tree navigation --- For years now, we’ve used a tree on the left side of the page for navigation. It works well enough, I suppose, on the client side, but maintaining the tree has issues, primarily that it’s slow to create. Since it is so slow, so we put in a frame (see above : ) to avoid recreation as much as possible. Moving to a lighter-weight solution will remove the need for a frame. What we’d like to add If we get rid of the tree navigation, we obviously need to replace it with something. We have several ideas as to what can replace the tree, and what can be added to improve further the user experience in the console. Menus --- The direction we’re heading is a menu bar, the horizontal application menu bar type. This gets us a way to organize the navigation options, but also greatly reduces the amount of real estate the navigation aid consumes (the tree takes a large chunk out of our usable space, especially at lower resolutions). We’re also considering changing how things are grouped. Currently, the tree is grouped largely by objects: applications, JNDI entries, connection pools, etc. What we’re considering is moving to a more action-oriented grouping: deploy, configure, edit, etc. Desktop Paradigm --- In my experience, when interacting with the console, I often have to work in different areas. Take creating a JDBC resource. Currently, I have to create the connection pool, then navigate to the JDBC resource page. To help reduce the amount of navigation needed for common tasks like this, we’re experimenting with a window-based interface — not multiple windows, but those fancy DIV-based "windows" that so many sites have these days. Our ultimate goal, should be implement this particular change, is to allow multiple open windows, allowing the user to work in several area "simultaneously." Our initial plan is to support only one window at a time, given our time frame, but this will get us moving in the right direction. Dock Bar --- In addition to having multiple windows, we’ve kicked around the idea of a Mac OS X-like dock bar. Exactly how it would work hasn’t been decided yet. One proposal is that it is just like the Mac dock bar: certain aplications (which would be windows, in our case) are opened automatically and are always in the dock bar, while some windows are avaiable in the dock bar, but not yet opened, as well as any minimized windows. The other proposed approach is closer to the Windows task bar in function, where the dock would contain only windows that have been opened via the menu bar and minimized. Searching and Tagging --- In the course of discussing all this, the idea of searching, which was raised initially as a possible feature for v2, came back up. Let’s say you need to create a JMS destination, but you’re not sure where all of the JMS-related options are in the console. With the search feature, you would be able to enter the phrase "JMS" into the search bar and see a list of options you can click, which will open the appropriate window. To complement the search, we’re also discussing the idea of "tagging" the windows. Let’s say, for example, the every Monday morning and do the same tasks, such as monitoring, checking logs, etc. Using this proposed feature, you would be able to tag each of those windows with, for example, "monday" and then, each Monday morning when you get to work, you can simply search for "monday" and see every window you need to visit. This has the potential to be a huge timesaver. Preferences --- Of course, if we add features like tagging, we’ll need somewhere to save it, so we’re investigating the use of the Preferences API. This would allow for a per-user set of preferences that would follow him/her from one browser/workstation to another. It would also allow us to do such things saving window locations, so you won’t have to constantly rearrange windows. We would also be able to customize the task bar or a common tasks page, remembering frequently entered values, etc. What we’d like from you As I stated at the top, we on the admin console are very aware of the fact that users love our console. It’s a very powerful and usable addition to GlassFish, we think, and market research seems to bear that out. With that in mind, we don’t want to make sweeping changes that our users don’t want, need, like, etc. We’d also really like to make sure that we integrate as many changes as possible (and make sense ; ) that our users would like to see. So, then, what do you think? Are the ideas I listed above heading in the right direction? Is there something you’d like to see us do? Is there something you’d rather see us NOT do? Now is your chance to affect the admin console that GlassFish will have for the foreseeable future. You can join the discussion on our mailing list or on IRC (#jsftemplating on irc.freenode.net) where our team is almost always on. Speak now, or forever hold your peace! :) ### [Interested in Servlet 3.0?](/2008/interested-in-servlet-3-0/) Interested in Servlet 3.0? If so, you might be interested in the latest webinar from The Aquarium covering Java EE 6 and Servlet 3.0. Spec leads Roberto Chinnici and Rajiv Mordani will be leading the next session covering these two topics. Eduardo has the details. ### [A One-Man JSF 2 Blog Storm](/2008/a-one-man-jsf-2-blog-storm/) A One-Man JSF 2 Blog Storm As the specification writing part of JSF 2 comes to a close, we’re getting a more complete implementation done on the reference implementation, Mojarra. One of the primary developers on Mojarra is Jim Driscoll (the other being Ryan Lubke, who has done such an excellent job on the 1.2 series). Jim, apparently, has been in a writing mood and has posted a number of very good (and small) posts on some of the features coming in JSF 2 (similar to Ryan’s series from earlier this year). I was about to start planning a smallish app, to be based on JSF 2, so I was perusing Jim’s entries, and it occurred to me that a list of the links would be helpful for those following JSF 2 but not Jim’s feed, so here it is. I hope it helps. :) Writing a simple Composite Component with JSF 2.0 A simple Ajax JSF 2.0 example JSF 2.0: Writing a Spinner component JSF 2.0: Adding Styles to the Spinner Component JSF 2.0: Writing fully reusable Ajax Component Another JSF 2.0 Ajax Component: Editable Text JSF 2.0: The Switchlist example JSF 2.0: The f:ajax tag I know Jim has more planned, so subscribe to his feed. It should be well worth your time. ### [JavaFX 1.0 Release Set for December 4](/2008/javafx-1-0-release-set-for-december-4/) JavaFX 1.0 Release Set for December 4 With the release of JavaFX 1.0 scheduled for this Thursday, December 4, the JavaFX team set up a technical pre-launch call and invited JUG leaders, Java Champions, NetBeans Dream Team members and others to call in and get a sneak peak at what was coming (audio and slides available here). Josh Marinacci was the engineer on hand to give us the preview. A couple of things stood out to me that has me pretty excited. The first thing, of course, is the language itself. I’m not a language geek, so I can’t really get into the nitty gritty of what makes a language good or bad, but I do like the declarative approach to GUI building. I haven’t used Swing as much as I’d like, but I have done a lot of AWT in a "former life" and that was painful. Swing fixes quite a bit there, but it still seems like a whole lot of code. JavaFX goes a step further, making GUI code more concise and readable. It does, though, unless I’m misreading things, emphasize a node-centric approach to GUI building, which I’ll confess I don’t completely understand. It sounds like it’s a lot different from what I’m used to, so there’s going to be a curve I’ll have to overcome, but I’m excited by that. New challenges are always fun. Usually. :) Remember those fancy videos at JavaOne 2008 with 200 videos playing at once at a three dimensional, rotating surface? That video — and MP3! — support will finally ship. Sun licensed the On2 codec for use in the JavaFX run-time, finally giving Java developers a video codec we can depend on. Having MP3 playback will also be nice, as it’s the dominant format. As nice as Ogg Vorbis might be, the world runs on MP3, so native support is huge improvement. One of the things that has me most excited, though, is the improved Java applet support. Granted, some of this comes as part of Java 6 Update 10, but, combined, I think we might finally see client Java getting some respect. Look at this example code Josh shared. This will launch a JavaFX-based applet from any browser, if I understood him correctly: <script src='http://dl.javafx.com/dtfx.js'/> <script> javafx( { archive: "MyApp.jar", width: 500, height: 300, code: "myapp.Main", draggable: true, name: "appl" } , { doStuff: "true"` } ); </script> If I heard him right, that bit of Javascript from dl.javafx.com handles all the dirty work for browser-specific options, version checking, etc. If you don’t want (or can’t support) your clients' browsers hitting the internet every time the applet loads, Josh indicated that the file could be downloaded and cached locally (and who’s going to know if you do, right? ; ) With Update 10, Java Web Start and Applet launching became much more interoperable, so you can now launch your applet using JNLP code. All it takes is one additional line in your .jnlp file (again, assuming I understood him correctly. Are you catch the theme here? : ) Another nifty feature is the updating of the venerable old javadoc with javafxdoc. I read a bit about this a few weeks ago, and I believe it allows running code in your documentation. If, then, you have a bit of code for which you want to include sample output, you just markup your docs correctly, and the doc processor will run that code and insert a "screen shot" produced by the code. Fancy! So is the new look (sorry for the low quality. I did a screen grab from the slides PDF. :): He also covered, of course, the draggable applet feature of Update 10, which is really, really cool. Perhaps as exciting is the new Javascript/Java integration the update offers. Suppose you have this code running in an applet on the page: public function doSearch():String { return "I searched, honest!"; } If you want to call doSearch from your Javascript code, you would do this: <script> function doSearch() { var appl = document.getElementById("appl"); appl.script.doSearch(); } </script> Slick. He finished up covering the supported platforms, the roadmap, changes from the preview release, etc. It was nice to see JavaFX Mobile, which should be final in February of next year, getting some attention too. For obvious reasons, it seems the language has gotten all the attention, and I’ve not heard anyone in the JavaFX camp mention mobile until today, though it’s possible that I just wasn’t listening closely enough. At any rate, JavaFX looks like it will be a great development platform. Time will tell if it can take the lead against Flex, Sliverlight, etc., but I, for one, am pretty excited about it. If you’re interested, there’s more information in the slides and MP3. Go give it a listen. ### [JSF 2.0 Public Review is online](/2008/jsf-2-0-public-review-is-online/) JSF 2.0 Public Review is online The current state of the JSF 2 spec has entered the Public Review phase. If you have any interest in JSF, now is a good time to review what we’ve done in the spec thus far and send feedback, which we will discuss and digest for the Proposed Final Draft due out next. You can find the Public Review here, and you can send your comments here. ### [NetBeans 6.5, Python Support, and Mac OS X](/2008/netbeans-6-5-python-support-and-mac-os-x/) NetBeans 6.5, Python Support, and Mac OS X The NetBeans team recently released version 6.5 of the NetBeans IDE, which I really, really like. They also released an Early Access peek at the Python support coming for NetBeans. Unfortunately, it’s not straightforward to get Python and Java EE support in the same installation. The Python EA release is a complete NetBeans installation, i.e., you can’t just add the modules to an existing NetBeans installation. Fortunately, there is a pretty easy solution to this: if you already have an existing 6.5 installation, you can simply run the Python EA installer, which will detect the existing 6.5 install and update it to add Python support. Unfortunately, the installer has a bug on OS X, which breaks this functionality. The end result is that your existing installation is replaced, which is likely not what you want. The good news is that there is a workaround, albeit ugly and manual, to get us Mac users running while they fix the installer issue. Here are the steps I followed to add Python support to NetBeans 6.5 on the Mac (big thanks to the NetBeans Users list for the tips that led to this solution): Make sure NetBeans is not running Download python cluster separately from http://download.netbeans.org/netbeans/6.5/python/ea/zip.html (search for netbeans-6.5-200811131701-python.zip — or whatever the latest is — in the second list "Module Clusters") Put contents of the python1 directory in the zip in $HOME/.netbeans/6.5 Delete directory $HOME/.netbeans/6.5/var/cache Add "python1" to /Applications/NetBeans/NetBeans 6.5.app/Contents/Resources/NetBeans/etc/netbeans.clusters Start NetBeans Profit? :) You should now be able to create a new Python project. The installer bug should be fixed in the next release (my guess is that it’s already fixed in the NB hg repo), but these "easy" steps should get you going in the interim. ### [Seam, WebBeans and GlassFish](/2008/seam-webbeans-and-glassfish/) Seam, WebBeans and GlassFish For some time now, Sun has made use of Ustream.TV to broadcast webinars covering various topics of interest to GlassFish users. That effort continues on November 20th at 11am PST as Eduardo Pelegri-Llopart hosts Dan Allen, author of Seam in Action to discuss Seam, WebBeans, and GlassFish. Some of WebBeans' companion specs (EJB 3.1 and JSF 2) will also be covered by spec leads Ken Saks and Roger Kitain, respectively. For more information, see this page on Sun’s wiki. To catch previous broadcasts on The Aquarium’s Ustream.TV channel, you can go directly there. ### [Extending the GlassFish v3 Prelude Administration Console](/2008/extending-the-glassfish-v3-prelude-administration-console/) Extending the GlassFish v3 Prelude Administration Console Today, the GlassFish community is launching GlassFish v3 Prelude (Release Notes and Quick Start Guide). If you are not familiar with what Prelude is, here is a short write up giving the high level details. In this article, I’d like to focus on the third bullet there, "CLI and administration console extensibility." Specifically, we’ll look at what it takes to create a plugin that will extend GlassFish v3’s Administration Console. Table of Contents The Java Class The Config File Integration Points Integration Type Plugin Priority Parent ID Plugin Content Defining the Plugin Content JSFTemplating Events JSFTemplating Handlers Summary Creating a plugin is really quite simple. The bare minimum is one Java class, a ConsoleProvider, and one XML config file, console-config.xml. The Java Class The Java class is very simple. It must implement the ConsoleProvider interface, which will require one method, getConfiguration, and it must be annotated with the HK2 annotation, @Service: @Service public class ConsolePluginExample implements ConsoleProvider { public URL getConfiguration() { return null; } } Despite its apparent simplicity, this class does a couple of things for us. By implementing the Interface, of course, it gives the Plugin service a type it knows about. By using the @Service annotation, the Plugin service will able to locate this plugin (and any others in the system) by asking HK2 for all the ConsoleProvider instances it knows about. But what about that getConfiguration() method? That method tells the Plugin service where to find the plugin’s configuration file. Unless you put that in a non-standard location, this implementation is what you will see. If, however, you would like to move or rename the file, then this method will return a URL to that file. The Config File So that defines the plugin for the console, but how do we make it do anything interesting? For that, we need to take a look at /META-INF/admingui/console-plugin.xml: <console-config id='console-plugin-example'> type: "org.glassfish.admingui:treeNode" priority="40" parentId="Resources" content="treeNode.jsf" /> type: "org.glassfish.admingui:tab" priority="22" parentId="jvmSettings" content="newTab2.jsf" /> type: "org.glassfish.admingui:tab" priority="28" parentId="serverInstTabs" content="newTab1.jsf" /> </console-config> This file does two things: it gives a name for the plugin, "console-plugin-example," and defines a number of integration points, which are the really interesting part here. Integration Points An integration point defines a small, discrete bit of content to be included in the console, providing information about what it is and where it should go. Let’s take a look at each piece of the integration point definiton. Integration Type Each integration-point element has several important pieces. The first is the ID. This must be unique for the current plugin. Next is the type. This describes the type of content we want to insert via this integration point. The admin console defines several integration point types: Integration Type Description Screen Shot org.glassfish.admingui:applications This integration type allows a plugin to add itself to the list of managed applications (e.g, enterprise, web, etc). This screen shot shows how the web plugin adds the "Web Application" link. org.glassfish.admingui:commonTask This type allows users to add entries to the Common Tasks page. The implementation of this type is a good example of how flexible an integration type can be. With this, plugin authors can add common tasks to existing sections (as the web plugin does) or create a new section (as the updatecenter plugin does). org.glassfish.admingui:configuration Like the applications type, this type allows a plugin author to add modules to the configuration start page. org.glassfish.admingui:mastheadStatusArea This type allows the user to add content to the status area of the masthead, which is the area in the header right below the product name (see screenshots). Multiple plugins are allowed to use this integration type, with entries being list left to right, based on priority (see below). org.glassfish.admingui:resources This type allows a plugin author to add modules to the resources start page. org.glassfish.admingui:serverInstTab This integration type allows a plugin author to create a new tab on the Application Server page, or to add content to an existing tab. In this screen shot, the web plugin adds the Monitoring tab to the main tab set, as well three tabs to the newly added Monitoring tab. org.glassfish.admingui:treeNode This integration point allows plugins to add nodes to the navigation tree. The nodes can be added either to the root, or to any other node in the tree. In this screen shot, we can see how the web plugin added the "Web Applications" node to "Applications,", and the "Web Container" and "Monitoring" nodes to "Configuration." Plugin Priority The next attribute is priority. This attribute controls the order in which integration points are included, with the lower numbers coming <i>first</i> (It might be best to think of this as "order" rather than "priority," despite the name). Parent ID The next attribute is parentId. This tells the plugin service to which component to parent the included content. Using our example above, the integration point tabtestTreeNode will be a child of the component whose ID is Resources. Plugin Content Finally, the content attribute tells the plugin service where to find the content of the integration point. This value is typically the path, relative to the plugin’s root, to the file that defines the content, which is simply a JSF page. In our example, we point to "treeNode.jsf." In a Maven project, this file would be in src/main/resources, and would be in the root directory of the resulting jar. This example file’s contents look like this: <sun:treeNode id='tabtest' imageURL='resource/images/instance.gif' target='main' text='Test Node #1' url='tabtest/jdbcLists.jsf'/> <sun:treeNode id='tabtest2' imageURL='resource/images/instance.gif' target='main' text='Test Node #2' url='tabtest/jdbcLists.jsf'/> The contents, of course, will vary depending on the plugins needs, and the type of the integration point, but, as you can see, this is just a snippet of JSF markup, which, in this case, defines two `sun:treeNode`s that will be inserted into the navigation tree. Defining the Plugin Content At this point, we’ve created the plugin. We’ve defined the integration points and specified their contents. If that’s all a plugin needed to do, we’d be done, but it’s not, so we aren’t. :) Once you have the UI elements specified and integrated with the console, you have to be able to make those components display data, perform actions, etc. From this perspective, the plugin is just a normal JavaServer Faces application. Given the architecture of the GlassFish v3 Prelude Administration Console, a plugin author has two options: the normal JSF managed bean approach, or the JSFTemplating events/handlers approach. JSF managed beans are a well understood and documented approach, but the same can’t be said about JSFTemplating Handlers and events. While an exhaustive discussion is outside the scope of this article, I’d like to offer at least a cursory introduction. JSFTemplating Events JSFTemplating provides a number of events that much more finely-grained than the standard JavaServer Faces lifecycle phases. There are a number of events, but the ones of interest here are (for more information, please see the JSFTemplating site): Event(s) Description beforeCreate/afterCreate This event fires before/after a component is created. It fires once per view, so, as long as the user stays on the same page, this event will not fire over and over. beforeEncode/afterEncode This event fires before/after a component is rendered. Since this is at render time, this event fires every time the page is requested, so care should be taken in handling expensive operations in this event. initPage This event fires everytime the page is requested. As with beforeEncode/afterEncode, care should be taken in handling expensive operations in this event. command This event is for ActionSource components only and fires when the UICommand component is clicked. JSFTemplating Handlers To attach a handler to an event, using JSFTemplating’s "template" syntax, one would do something like this: <sun:button id='button' text='Push Me!'> <!command executeSomeBusinessLogic(amount="5.25", result=>$pageSession\{businessLogicResult}); /> </sun:button> This creates a sun:button and attaches the Handler executeSomeBusinessLogic to button. When the button is clicked, the Handler is called, with the input variable amount being set to 5. After execution, the value of the Handler’s output variable result is assigned a page-scoped variable called businessLogicResult, which can be referenced on the page using the EL expression {businessLogicResult} or \{pageSession.businessLogicResult}. The Handler, executeSomeBusinessLogic might look like this: @Handler(id="executeSomeBusinessLogic", input = { @HandlerInput(name="amount", type: Double.class, required=true) }, output= { @HandlerOutput(name="result", type: String.class) } ) public static void myBusinessLogicMethod (HandlerContext handlerContext) { Double amount = (Double)handlerContext.getInputValue("amount"); // Do some work. // Get a reference to some external server // Perform all calculations locally // Whatever you need... handlerContext.setOutputValue("result", "Some string built from the business logic."); } There are several things to note. First, the annotation defines the id by which we reference the Handler (executeSomeBusinessLogic) and it need not match the actual method name. Second, we have one input, amount which must be a Double, and is required. If it is not provided, an Exception will be thrown. Third, a single output variable, result of type String is returned. Last, the method must be public static void and must take a single parameter of type HandlerContext. Inside the method, we extract the input parameter using HandlerContext.getInputValue() and cast it to the expected type. When we reach this point in the code, we can cast with out worrying about a ClassCastException, as JSFTemplating insures that the type is correct. Since null could be a valid value, though, the Handler must perform null value checking as appropriate. Next the Handler performs the business logic, whether it does it internally or delegates to another object, be it local or remote, then sets the value of the output variable, result. The JSFTemplating event and Handler mechanism is, conceptually, a very simple, yet very powerful mechanism, of which the GlassFish v3 Prelude Administration Console makes heavy (and exclusive) use. Summary And that’s all there is to writing a plugin for the GlassFish v3 Prelude Administration Console: one simple class, an XML config file, a few managed beans or Handlers, and just a few JSF markup files as necessary for your plugin. These simple building blocks make it extremely simple to http://docs.sun.com/app/docs/doc/820-6583' title: "'Sun GlassFish Enterprise Server v3 Prelude Add-On Component Development Guide[extend] the GlassFish v3 Prelude Administration Console. In fact, most of the functionality that ships in the console uses this approach, demonstrating the power of the mechanism quite nicely. The modularity of the GlassFish v3 kernel provides system integrators a practically unbounded array of opportunities for extending the application server, and the administration console’s plugin service makes it extremely easy to add administration support for any extension you might create. How will you extend GlassFish?" ### [GlassFish Day Online](/2008/glassfish-day-online/) One more note (for now :) on GlassFish v3 Prelude. Sun is holding an online event called GlassFish Day, which is a day of short presentations (about 10 minutes each). There will be several presentations throughout the day. To see the schedule and decide which ones are of interest to you, please see this entry from The Aquarium. ### [I've made the plunge](/2008/i-ve-made-the-plunge/) I may have made a mistake, but I’ve joined 2007 and hopped on twitter. You can follow me here, or view my latest updates in the sidebar. ### [Making Your GlassFish v3 Prelude Administration Console Plugin Pluggable](/2008/making-your-glassfish-v3-prelude-administration-console-plugin-pluggable/) Making Your GlassFish v3 Prelude Administration Console Plugin Pluggable In my last article, I talked about writing plugins for the GlassFish v3 Prelude Administration Console, which showed the various integration types supported out-of-the box by the console, but what if a plugin developer would like to allow <i>other</i> plugins to extend it just like the console itself does. In this short article, we’ll show how to do exactly that. As we saw in the last article, the GlassFish v3 Prelude Administration Console offers a wide range of integration types, but it is also possible to create your own types, should you wish to allow other plugins to interact/integrate with your own plugin, and doing so is very simple. All that is required is the selection of an integration type identifier, which must be unique across the system. By convention, your integration types should be a Java package-like name followed by a colon and a specific integration point name (as we saw in the integration type table above in the other article). For example, let’s say you’re writing a plugin for you company’s fantastic GlassFish extension, Winnie. In your plugin, your ConsoleProvider class in in com.foo.winnie.admin, and you’d like to be able allow other plugins to add tabs to main Winnie config page. Your integration type, then, would be com.foo.winnie.admin:tab. When the Winne plugin authors define the intregation point, they would specify that as the type, and your tab’s id as the parentId. Now we have a new integration type defined, but how does one consume the integration points that are of this new type? To include any integration points defined for a given type, the GlassFish v3 Prelude Administration Console provides a few JSFTemplating Handlers (for more information on what a handler is, please see the previous article and/or the JSFTemplating documentation). To include all integration points for a given type, your markup might look like this: <sun:propertySheet> <sun:propertySheetSection id="propSheetSection"> <!afterCreate getClientId(component="$this\{component}" clientId=>$attribute\{sheetId}); /> </sun:propertySheetSection> <event> <!afterCreate getUIComponent(clientId="#\{sheetId}" component=>$attribute\{component}) includeIntegrations(type: "org.glassfish.admingui:resources" root="#\{component}"); /> </event> </sun:propertySheet> In some cases, you may want only one integration point, with the deciding factor being the priority (see below). The GlassFish v3 Prelude Administration Console does for its :masthead integration type used in the theming support. Such a use might look like this: <sun:form id="propertyForm"> <!afterCreate getClientId(component="$this\{component}" clientId=>$attribute\{formId}) getUIComponent(clientId="#\{formId}" component=>$attribute\{component}) includeFirstIntegrationPoint(type: "org.glassfish.admingui:masthead" root="#\{component}"); /> </sun:form> That’s all there is to it. With this code in place in <i>your</i> plugin and the integration type published where others can find it, your plugin can be easily extended by anyone. The possibilities in extending GlassFish v3 Prelude Administration Console — as well as its extensions — are limited only by our imagination. ### [Not So Late Breaking News](/2008/not-so-late-breaking-news/) Not So Late Breaking News I’ve been meaning to say something about this for while, now, but I have been a bit busy, and was finally beaten to the punch by Alexis Moussine-Pouchkine over at The Aquarium. Before I go any further, go read Alexis' article, paying particular attention to the "real #1 winner" link. Go ahead. I’ll wait…​ image::https://glassfish.dev.java.net/public/image/glassfish_logo_large.gif Pretty exciting, eh? It was, in fact, quite an honor. I was contacted by a friend at Sun, Ken Paulsen, with whom I’ve done a good deal of work in the past (this, for example). He had an opening on his team, the GlassFish Administration Console team, and was wondering if I might be interested in filling it. The chance to work for Sun on GlassFish (from home, to boot!), was just too good of an opportunity to pass up, so my history of work with JavaServer Faces and GlassFish-related open source technologies (code, support, bug reports, etc) translates itself into a full-time gig. If that’s not incentive to get involved, I don’t know what is. :) At any rate, I’ve been on staff for about three months now, working hard with everyone else on the team getting the GlassFish v3 Prelude release ready to launch, which we’ll do Thursday, November 6. I’ll have an article here (and at my new Sun blog, most of whose contents will likely be cross-posted here) on the launch date. Speaking of which, I need to finish that…​ :) ### [The Means Stultify the End](/2008/the-means-stultify-the-end/) The Means Stultify the End From time to time, someone, trying to cut through all the hype and spin, will attempt some sort of statistical analysis to determine which web framework is "winning." The results are almost always disappointing, and not because I don’t agree with the outcome, but because the methodology is so flawed. The most recent attempt I’ve discovered, noble as it is, is no different. If you read the post, you’ll notice the page author is basing his efforts on data from Google Trends, which, I guess, is a fair starting place. The problem, though, as was pointed out in the comments, is that his search criteria is flawed, particularly with regard to JSF, a technology near and dear to my heart. :) He uses "myfaces+icefaces" as the discriminator for JSF-related queries. The flaw there, of course, is that MyFaces is only one implementation of JSF, not everyone searches for "myfaces," and ICEfaces is a component library, not an implementation, and is a keyword not used in all JSF queries. Commendably taking a cue from a commenter, the author then links to an "improved" http://www.google.com/insights/search/#cat=&q=struts%202%2Cmyfaces%20%2B%20mojarra%2Cspring%20mvc%2Cjboss%20seam&geo=&date: &clp=&cmpt=q[query], but this one is actually worse. In this attempt, his JSF-related query used "myfaces+mojarra" which will capture the number of times someone queried for both major JSF implementations at the same, a scenario I dare say is not even slightly common. One of the issues with trying to quantify searches for JSF-related data, is that, if you’re not careful, you’ll get some data that’s not even slightly related. I understand why authors write these kinds of posts. I was even asked the question this post tries to answer at JSFOne. Since there’s no reliable way to get usage information for open source projects, we have no hard numbers to work with, so we’re left using Google statistics to try to make an educated guess. More often than not, though, the results fall far short of mark. Now on the issue of "tell me which framework is 'winning' or 'better' so I know which one to use," while I have an opinion, depends on a whole slew of issues, which is a topic for a different post someday. Perhaps. :) ### [JSFOne: Day Two](/2008/jsfone-day-two/) JSFOne: Day Two Day two is over, as I sit here on the morning of the third, despite my best intentions. It was a long day for me, but a good one, overall. Despite my two talks scheduled for that afternoon, I took the time to attend one of the JSFOne sessions presented by Ted Goddard of ICEsoft on "Ajax Push/ICEFaces." Ajax Push is the term ICEsoft prefers for what others call Comet (Ajax…​Comet…​ get it? : ) or Reverse Ajax. It’s a technology that has interested me for quite a while, so I figured this was a good chance to learn from an expert, and I was completely blown away with how easy it is with ICEfaces. I was expecting to have to add a lot of mark up to the template to use Ajax Push, and maybe a lot of plumbing on the server as well, but I was wrong. The template remains completely unchanged — it has no idea that Ajax Push is being used. In fact, Ted suggested that we write our app as Web 1.0 app, and THEN add the push features. It sounded crazy until I saw the changes on the server side: two lines of code. I don’t have the code handy, but you basically subscribe a session to a group (I believe that’s the term they use) with one line of code, and then, anywhere you want to notify interested clients of an update, you use another line of code. That’s it. It’s basically a very simple subscribe/notify mechanism. Very impressive. The Infragistics guys are here as well. Someday, I’ll have to play with both of those frameworks and see if I can cook up a compare and contrast of some of the major frameworks. We’ll see if that ever happens ; ). After lunch, I gave my first presentation of the day, "JSF 2-Style Component Development in a 1.2 World." This is the talk I gave at the Oklahoma City JUG, and it went much better the second time around. The attendance was pretty good, with lots of good discussion. I changed the presentation a bit, based on the feedback from the first go 'round, and spent more time in the code than on the slides, using a print out of the slides as my outline. I think it flowed better and seemed to be well appreciated by the audience. After that, I attended Kito Mann’s presentation on Shale Test, a JSF testing framework from the Apache Shale group. Having attended Stan’s BOF on JSFUnit the night before, I wanted to see what Shale Test offered. Kito seems to like it a lot, so there must be something there. Overall, it seems like a pretty nice tool. While it does seem to support in-container testing, all we looked at was out-of-container, JUnit-style tests, which I tend to lean toward. Stan made a good point in his BOF, though, that out-of-container testing isn’t often as complete as in-container, as any Servlet Filters, etc. that the app may have aren’t every applied. Of course, that approach to testing, as Stan quickly notes, blurs the line between unit and integration testing. That debate aside, both Shale Test and JSFUnit offer very functional ways to test JSF apps, though, to be honest, I’m inclined toward JSFUnit, for what that’s worth. In the last slot of the day was my presentation on JSFTemplating, which was also well attended and received. From a presentation perspective, I felt it flowed pretty well (especially since that was the first time I’ve given that talk) with no major hiccups (or minor, from what I can remember : ). The audience seemed really engaged, asking a lot of good questions. I was initially afraid it wouldn’t fill the whole time slot, but we actually went the full 90 minutes. With all of my presentations done, I headed to dinner, where I got to have a fun chat with a native Virginian, a Bostonian, and a German. All nice, sharp guys, which made for good conversation. After dinner was the JSFOne/Rich Web Experience 2008 Party. I don’t drink, so that part didn’t appeal to me much, but I made the mistake of heading back to my room to drop off my backpack, at which point I got comfortable and wasn’t able to force myself to get back out. :) I spent the rest of the evening, then, watching the hotel’s TV system trip and fall and finally basically quit working altogether. With no wifi in the hotel room, that made for an interesting evening. Day 3 will be a short one, and I will be heading to the airport before things are done, so I won’t have much to say. In fact, I’m typing this as sessions are going on, so I won’t have much to report. This, then, will likely be my last post from/about the conference. One quick note about Day 3, though. I got to meet David Chandler, a fellow JSF enthusiast and JSFOne speaker, and a fellow Believer, and we had a very good discussion over breakfast, which was an unexpected, but very welcome surprise. He has a neat project going on, which I may discuss in a more appropriate forum at some point (if you’re interested in what that is or where that might be discussed, feel free to email me : ). ### [JSFOne: Day One](/2008/jsfone-day-one/) JSFOne: Day One I’m actually writing this on day 2, but I was up late working and didn’t get a chance last night, so, without further delay, here are my thoughts on JSFOne day #1. This conference is a little different for me, as I’m speaking at this one. My first day, then, was technically Wednesday night. I finally arrived at the hotel and promptly ran into Chris Schalk, who was chatting with Matthias Wessendorf, so I joined them for some non-shop talk, mostly, which was a nice change. Ed Burns arrived a bit later and joined the conversation, which ran later into the night than we four speakers should have been up. :) The actual first day of the conference was a little odd for me, as I only went to one session, which was mine. The rest of my day was spent working on GlassFish bugs and a little bit on my presentation. The meals, which were excellent, as is usual at a NFJS event, punctuated my bug squashing, giving me a good reason to take a break. Other than being my first time to speak at a conference, another first occurred for me on day 1: my first podcast interview. Kito is interviewing, presumably, all of the speakers for jsfcentral.com. It was a fun experience, and I can only hope I don’t sound like a blathering idiot. :) I won’t steal Kito’s thunder by telling what was asked and answered, but I will say this: he asked me what the difference was between Mojarra and MyFaces, which caught me off guard. I think I was Fair and Balanced in my response — I certainly tried to be — but we’ll have to wait and see how it turned out. I really hope it didn’t come across like I was bashing MyFaces in anyway. I do think Mojarra is the better implementation,but I have a clear bias. The MyFaces guys (and there are at least three here: Matthias, Martin, and Cagatay) are all very, very sharp and they’ve done a great job on MyFaces, so if I said something derogatory about them, it’s simply because I was caught off guard a little bit (which is my fault, but I’ll move on. :) My talk time came around, so I shuffled off to my room. I wasn’t sure what kind of attendance to expect, as "Hacking Mojarra" is a bit lower level than most people seem to enjoy working, but attendance, at four, exceeded my fear, which was zero. :) Ed Burns attended the talk and was very helpful in filling in some of the holes in my knowledge of things. Despite my best efforts, I haven’t been able to learn it all, but, having been around since the beginning, Ed was much closer to that than I. :) After dinner, I attended the expert panel discussion, which was a lot of fun. The panel was open to all speakers, but I declined to take the stage, as JSF was well represented on the stage already with Daniel Hinojosa, Dan Allen, Jeremy Grelle, Stan Silvert, Keith Donald, Ed Burns, Martin Marinschek, and Kito Mann on the stage. There was a lot of really good questions and discussion amongst both the experts and the audience. Kito had actually had to call an end to it so that we could move to the BOFs. One interesting comment came from the panel, though. We were discussing the advantages of having multiple implementations, which is something I and others find to be a good thing, mostly. Stan Silvert noted, though, something like, "At some point, one implementation has to win, and I think we’re pretty close to that point now." He didn’t specify which implementation he thought was winning, but, based on what JBoss ships, I have a pretty good idea what the meant. I can’t guess how close to the truth he is, but I thought the statement was quite interesting. I attended Stan’s BOF on JSFUnit, a JSF testing framework I’ve been watching for some time now. The BOF gave me a chance to see an expert with the tool discuss and demo it, which helped a lot in clearing up some of my questions. I went in intrigued by it, and left really impressed. When I get back from the trip (and get passed the GlassFish hard code freeze Tuesday), I’m going to spend some time really learning this tool. My night ended in the hotel lobby as I worked until almost 1:00am trying to finish up some of my open issues. I can’t work from the hotel room, as the conference wifi isn’t available there, and the wifi in the room costs. Since I can go up one flight of stairs and get it for free, that’s what I did. And I squashed a pretty big issue, so it was well worth it. The first day of the conference was, I think, a great success. I felt pretty good about how my talk went (the evals, though, will give a much better and less biased picture, though ;) and the mood and excitement of the attendees was very encouraging. There are a LOT of people using JSF in a myriad of industries and in some very large, complex applications, and having a good time doing it. Furthermore, David Geary noted that his JSF training and consulting business has really been going crazy over the last year, so it looks like things are really going well for JSF. Tomorrow brings day 2, and my two other presentations. More on that this evening. ### [JSFOne Looms!](/2008/jsfone-looms/) JSFOne Looms! JSFOne is just a week and a half away, so if you haven’t done so yet, buy those tickets! The Java Posse recently plugged the show in the Quick News section in what I think might be the greatest 34 seconds in Java Posse history. Listen for yourself. ;) http://www.macromedia.com/go/getflashplayer[Get the Flash Player] to see this player. var so = new SWFObject('https://media.dreamhost.com/mediaplayer.swf','mpl','320','20','8'); so.addParam('allowscriptaccess','always'); so.addParam('allowfullscreen','false'); so.addVariable('height','20'); so.addVariable('width','320'); so.addVariable('file','JSFOne%20on%20the%20Java%20Posse.mp3'); so.write('player'); At any rate, in preparation for my presentations at the conference, I volunteered to give one of my presentations, JSF 2-style Component Development in a JSF 1.2 World, to the Oklahoma City JUG. The only word that comes to mind is, "educational." The presentation did not start off well, as I broke what I consider to be THE cardinal rule for presentations: never, ever require network access unless you have to, and if you have to, rethink your presentation. :) The components I intended to demo were still pulling their CSS and Javascript from Yahoo’s CDN because I hadn’t taken the time to correct that, as I had done on the rest of the Scales components. Instead of demoing something else, I tried to fix that mistake prior to the start of the session, which was another mistake. I should have picked something else to demo, but panic kicked in a bit and skewed my judgment. When I felt I finally had that part under control, I turned to the main reason I showed up early, which was to verify that I could successfully connect to and use the projection system. When I did that, things unraveled further. As is often the case, in my experience, when hooking up a laptop to a projector, my machines resolution was lowered to match that of the projector. Normally, this wouldn’t be much of a problem, but, for reasons I can’t explain, I was using OpenOffice.org 2.4 on my Mac Book Pro, which requires X11 to run. When the resolution changed, things in OO.org went crazy. The right and bottom sides of the slides wouldn’t fit on the screen, and the program decided to rearrange the items on the slide to fit in the viewable area. Unable to correct that, I ended going back to the slide editing screen and manually selecting the slide to show from the list on the left, and showing the edit view for the slide show. Once I got those two issues in hand, more or less, I think the presentation went fairly well, but I certainly learned (or relearned some important things): I will never break the cardinal rule again, and I’ll not use OpenOffice.org 2.x on a Mac ever again. :P It’s probably unfair to blame OO.org for that failure, but its dependence on X11 (which is fixed in OO.org 3.0, currently in beta) caused me much grief that day, and NeoOffice provides a Mac-native port of OO.org that works MUCH better. After the lunch session was over, I fixed my network issue and downloaded NeoOffice, verifying that both issues were indeed resolved in the room on the hardware I would be using that night, but then no one showed for the evening session, so I got no chance at redemption. :) As frustrating as the session was for me (and I’m sure the audience), it was a helpful tune up for JSFOne. The feedback I received, which was much kinder than I expected, was extremely helpful as well. Given the time I’ve had since that session and what I learned from it, I think all three of my sessions will be much smoother come September. Speaking of that, my slides are due soon, so I had better finish those up. I hope to see some of you at the conference. Be sure to come up and say hi. :) ### [Maven and Annotations: Not as Easy as It Should Be](/2008/maven-and-annotations-not-as-easy-as-it-should-be/) Maven and Annotations: Not as Easy as It Should Be Over the past year or so, I’ve been slowly migrating — somewhat accidentally — to Maven. I had even begun migrating the build environment for Scales from Ant to Maven, but hit a huge roadblock: annotation processing. Scales depends heavily on compile-time annotation processing, and the only thing I could find on the web was other people with the same problem. As I was working on some of my JSFOne examples, I really wanted to use Maven, as the NetBeans support is a lot cleaner with Maven versus an externally maintained Ant build file, so I set to with renewed purpose. Finally, I seem to have found the right query string, as I appear to have solved my problem. The solution? Ant. One of the vaunted features of Maven is the ability to embed Ant scripts in your POM file. My first thought when I ran into the problem above was exploiting that capability, but those attempts were thwarted by one of Maven’s biggest weaknesses: poor documentation. As I noted, though, I finally found a web page that had something close to what I needed that I was able to work out the rest. Since my JSFOne examples have the same compilation requirements as does Scales, I was able to pull the annotation processing tasks from the Scales build, giving me this: <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <executions> <execution> <id>process_component_annotations</id> <phase>generate-sources</phase> <configuration> <tasks> <property name="target.dir" value="target/classes/META-INF"/> <mkdir dir="$\{target.dir}" /> <apt srcdir="src/main/java" preprocessdir="generate" destdir="$\{target.dir}" includes="**/*.java" compile="false" debug="true" factory="com.sun.faces.mirror.FacesAnnotationProcessorFactory" source="1.5" target="1.5"> <option name="generate.runtime" value="" /> <option name="namespace.uri" value="http://steeplesoft.com/jsfone/jsf2comps" /> <option name="namespace.prefix" value="jsfone" /> <option name="taglibdoc" value="src/main/conf/tag-descriptions.xml"/> <option name="localize" value="" /> <classpath> <path refid="maven.compile.classpath" /> </classpath> </apt> <move file="$\{target.dir}/taglib.xml" tofile="$\{target.dir}/jsf2comps.tld"/> <move file="$\{target.dir}/facelets.taglib.xml" tofile="$\{target.dir}/jsf2comps.taglib.xml"/> </tasks> <sourceRoot>generate</sourceRoot> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> <version>1.7.0</version> </dependency> </dependencies> </plugin> It’s not really pretty, but we are talking about a Maven POM. ;) As I’m sure you’ve surmised by now, I’m not a Maven expert, but here is my understanding of things. We’re telling Maven to run these tasks when the generate-sources phase is run (if you can find documentation on what the Maven lifecycle is, I’d love to see it). The tasks run are, I think, pretty self-explanatory (their purpose is outside the scope of this post either way ; ). Note, though, that we can run as many arbitrary Ant tasks as we want. One feature that I like a lot is the sourceRoot entry. With that line, we’re telling Maven to add the generate directory to the build path. Since the annotation processor creates the source for JSP Tag files, we need to compile that class, and this takes care of that for us. One remaining problem was that this creates some directories and files that Maven doesn’t delete when the clean goal is run. To fix that, we add this XML snippet to the plugin description above: <execution> <id>clean_generated</id> <phase>clean</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <delete dir="generate" /> </tasks> </configuration> </execution> With that, we can now issue a mvn clean and get rid of the generate directory that apt creates. Snazzy. Maven experts will look at this and doubtless see many ways to improve the code, and some will likely suggest the Maven apt plugin from Tobago. What this represents, though, is a working solution in spite of Maven, ugly as it may be. Of course, I’m certainly open to suggestions and advice, but what I have is working, so I’m not going to lose much sleep over it. Hopefully, this will help someone else. Better yet, maybe the Maven developers will release a meaningful update to Maven that fixes problems like this. :) ### [Quercus on GlassFish via the Update Center](/2008/quercus-on-glassfish-via-the-update-center/) Quercus on GlassFish via the Update Center Jim Driscoll wrote a really helpful blog entry regarding the GlassFish Update Center module he wrote for Mojarra. After reading that, I decided to revisit Quercus on GlassFish. Using Jim’s incredibly detailed entry, as well as looking at the code in the Mojarra 2.0 SVN repo, I was able to get an Update Center module working that installs and configures Quercus for you, so now all you have to do to get WordPress running, for example, is install this module, and extract WordPress into your document. Easy! For those interested, the Update Center url is http://uc.steeplesoft.com/quercus.xml. To set this up, you’ll need to start the Update Center ($GF_HOME/updatecenter/bin/updatetool.*), switch to the Preferences tab, click Add, and fill out the form. Once that’s done, switch to the "Available Software" tab, click the "Check for Updates" button in the upper right corner, and wait for the process to finish. You should now see Quercus available under the "Web Technologies" section. For those interested, the source code is in my Mercurial repository here. Due to some issues in GlassFish v2, automatic uninstallation is a bit complicated. The module supports it, but you have to get your hands dirty to make it work. Jim has details on his blog. If you use this, please let me know how it works out for you. :) ### [Mojarra Scales 1.0 RC2 is out](/2008/mojarra-scales-1-0-rc2-is-out/) Mojarra Scales 1.0 RC2 is out I have just uploaded RC2 for Mojarra Scales 1.0, a JSF component set born of the Mojarra Sandbox. This release features a number of bug fixes and a handful of new enhancements. When updating, make sure you grab the latest JSFTemplating snapshot from either its download page or Maven, as there are some bug fixes and features there that Scales needs. You can download the last jar here. Changes in 1.0 RC2 In no particular order: <ul> * A bug was fixed in JSFTemplating regarding ':' encoding in URLs. This will affect sc:download if it is used inside a NamingContainer (such as h:form or h:dataTable). If you use the component in this manner, you will need to grab a JSFTemplating build from June 9 or later. * Added code to try to automatically determine the mime type if one is not provided. For this to work, a filename must be given. If both properties are null, the default is text/plain. * Fixed a method="download" bug affecting IE. * Added null pointer checks needed for when verifyObjects is set to true (issue #15) * Added build-time support for a GlassFish Update Center module * Upgraded to YUI 2.5.2 * Added missing / in templates/multiFileUpload.xhtml (issue #16) * Fixed some build issues regarding @Override caused by Java 6 vs Java 5 differences * Added support for f:param to sc:download. For each f:param found with a name/value pair, that pair will be added to the URL generated. This will help in situations in which the component is in a table and you need to pass some sort of identifier to the managed bean to load the data associated with the current row, for example. * Added f:param to the demo under the "Default url variable" example * Localization now supported on sc:dateSelector. Currently, the only two locales supported are en and de. New localizations can be added as need (I only speak English, so they’ll have to be contributed), but projects should be able to create com.sun.mojarra.scales.MessageResources_xx_yy.properties, and set the locale attribute on the component to "xx_yy" to get immediate use of the new locale. This method has not been tested yet, but works in my head. :) * It appears that YUI 2.5.2 doesn’t like a null axis on the charts, so the default value now is "''" (i.e., an empty pair of single quotes). Odd, but it seems to fix the cases where there is no Axis defined. Ideally, that parameter wouldn’t even be used if there is no value, but doing that will take a bit more work than I have time for at the moment, so this work around will have to suffice. End users shouldn’t notice either way. If you have any more (or new) issues, please be sure to raise them on the users list (or, better yet, in the Scales issue tracker) to make sure they are addressed. Hopefully, the next release will be 1.0. A big thanks to everyone for the feedback! ### [GlassFish, PHP and WordPress](/2008/glassfish-php-and-wordpress/) GlassFish, PHP and WordPress With all the hype around JRuby, Jython, Scala, Groovy, etc., an oft-overlooked dynamic language with JVM support is PHP. Thanks to the hard work of the folks at Caucho Technology, the Quercus project offers a pure Java implementation of the PHP language, sporting support for a lot of the major PHP-based applications. In this entry, we’ll look at how to configure GlassFish to provide easy PHP support, and then look at installing WordPress, the popular blogging software (which runs this site) on GlassFish. Installing the library The first step, of course, is to download Quercus. As of this writing, the current version is 3.1.6 and can be downloaded here. The typical installation method is to wrap your PHP application inside the war, but that’s always felt a little odd to me. While that works, we’re going to setup GlassFish to process a PHP file from any application. To do that, let’s open up the Quercus war file, and look in WEB-INF/lib, where you will find 3 jar files. Now you have a choice. If you want to make PHP support available to all domains, place these three jars (quercus.jar, resin-util.jar, and script-10.jar) in the lib/ directory in your GlassFish installation root. If you only want to add support to one domain, copy the jars to the lib/ directory in your domain directory (e.g., $GF_HOME/domains/domain1/lib/). Enabling PHP support With the jars installed, we’re ready to modify the default web configuration. This is done by modifying config/default-web.xml in each domain directory you would like to affect. I have not seen a way to change this globally, so you have to do this to each domain. If someone out there knows how, though, I’m all ears. At any rate, in default-web.xml, add these servlet and servlet-mapping entries: <servlet> <servlet-name>Quercus Servlet</servlet-name> <servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class> <init-param> <param-name>ini-file</param-name> <param-value>WEB-INF/php.ini</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Quercus Servlet</servlet-name> <url-pattern>*.php</url-pattern> </servlet-mapping> If you’d like, you can also add index.php to the welcome file list: <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>index.php</welcome-file> </welcome-file-list> Installing WordPress For our purposes, we’re going to make WordPress available at http://localhost:8080/wordpress, so we create the directory $GF_HOME/domains/domain1/docroot/wordpress. Next, we extract the WordPress archive here. Pointing our browser at http://localhost:8080/wordpress/, we see the typical WordPress installation screens. The first screen tells us that WordPress can’t find the configuration file, and offers us a link to create one. Click on that, then click on the "Let’s go!" link on the next page (feel free to read the page, of course ;). On the form that is presented, fill out the requested information and click submit. We are now ready to begin the installation, so click the "Run the install," answer two more questions, and click "Install WordPress." After a few seconds, you should see the "Success!" page. Make a note of the password, and click "Log In." Voila! You’re done! You now have WordPress installed and are ready to start blogging! Since we’ve done a directory installation, adding themes and plugins should be as straightforward as any run-of-the-mill PHP hosting setup. If anyone else tries this, I’d love to hear how the support for third party extensions is! ### [Where will you be the first weekend in September?](/2008/where-will-you-be-the-first-weekend-in-september/) Where will you be the first weekend in September? For those of you that like to hear me speak (and, yes, I’m looking at you, Mom!) I will be at JSFOne, a conference brought to you by the No Fluff Just Stuff team and dedicated to the JSF ecosystem. "JSFOne," you say? That’s what I said when I ran into Kito Mann at JavaOne. He mentioned that he and Jay Zimmerman (the driving force behind NFJS) were putting together the conference and asked if I would be interested in speaking, which, of course, I was. I’m also quite flattered to be listed among these speakers. The site hasn’t gone live yet, but, let me tell you, the movers and shakers are on this speaker list. It’s not every big name in JSF (I can name a couple more off the top of my head), but it’s close. It should be a great conference (to quote the Tiki birds, if I weren’t in the show, I’d be in the audience too!), and it will run concurrently with The Rich Web Experience East, so there should be some nice cross-breeding with the Ajax/RIA worlds. At any rate, as things stand now (which may be subject to change), I’ll be giving three presentations. You can get information on these and the other great sessions on the JSFOne web site, but here are the details on mine: JSFTemplating: The Other ViewHandler Just about everyone is familiar with Facelets — and with good reason — but did you know there’s another major alternative? JSFTemplating is a ViewHandler implementation that has been around for years — actually predating Facelets a bit — that offers some very compelling features, such as pluggable template formats and event handlers. It’s even (mostly) Facelets-compatible, giving the user the best of both worlds. If you’d like to take a look at part of the technology that powers, for example, the Admin Console in the GlassFish application server, this presentation is for you! JSF 2-style Component Development in a JSF 1.2 World One of the improvements coming in JSF 2 is the vast simplification of component development, but JSF 2 is months away, and you want that functionality NOW, so what’s an impatient developer to do? Enter JSFTemplating and JSF Extensions. Using these two libraries, it is possible to use an approach very similar to what JSF 2 will offer, but can be done using JSF 1.2. In this presentation, we’ll peek under the hood of Mojarra Scales, a component set that uses this approach, and see what it has to offer. Hacking Mojarra: A Guided Tour Have you ever wanted to work on the industry-leading JSF 1.2 implementation, but didn’t know where to start? Or, have you ever been curious what the implementation looks like behind the scenes? In this presentation, we’ll take a look at the build environment, tools, and processes that Mojarra has in place, giving you just about everything you need to sit down and fix your favorite bug, or, perhaps, cook up the next great enhancement. If you’re using JSF, this conference will definitely worth your time. If nothing else, you’ll get to meet the brightest minds in JSF. And me. Hope to see you there! :) ### [JSF 2.0 Early Access Review Available](/2008/jsf-2-0-early-access-review-available/) JSF 2.0 Early Access Review Available The JSF 2.0 Expert Group (operating under the auspices of JSR 314) has released Early Draft Review 1 of the upcoming revision of the spec. We are soliciting feedback, of course, and the window of opportunity for that runs through July 2. If you want to have some input on the direction of the specification, now is the time to speak up. :) The major changes in this draft release are baked in Ajax support, and what we’ve termed "EZComp," which is better described as composite components. Composite components, which touches on a change to finalized in a later release, namely, the inclusion of Facelets, allows a component developer to create a new component by piecing together several others in a template file. This functionality is very similar, as best as I can tell as I’ve never used them, to Facelets' component support, where a snippet of markup is specified in a file and can then be treated as an actual component. Unlike the Facelets version, though, these composite components are "real" components in that they are backed by a UIComponent. If you were at JavaOne, this is what Ed demoed in this presentation (with Roger demonstrating the Ajax support). There’s still much work to be done before September when we are schedule to deliver the Proposed Final Draft, but this is a pretty good start. If you have any interest at all, please review the spec and give us feedback. We really do want your input, as our goal is to improve upon the JSF experience and solve as many of the real world pain points as we can. If your favorite pain point isn’t being addressed, you owe it to yourself to speak up! :) ### [Mojarra Scales 1.0 Release Candidate 1](/2008/mojarra-scales-1-0-release-candidate-1/) Today, I released the first release candidate for Mojarra Scales, the JSF component library I helped create. Rather than repeat myself, I’ll just paste the email announcement here: I am pleased to announce the first release candidate of Mojarra Scales 1.0, a new JSF component set. Mojarra Scales started out as the Sandbox for the JSF RI (now known as Mojarra) and was recently promoted to its own java.net project. The component set includes a tab view, several menu controls, JavaScript charts, a multi-file upload control, the first (as far as we can tell) free JSF rich text editor control, as well as several other visual controls. Additionally, Scales offers a simple, easy to use pretty URL component, allowing JSF applications to offer search engine-friendly "deep links." The home page for Mojarra Scales is at https://scales.dev.java.net, and the RC bits, including a demo application, which shows the components used in JSP, JSFTemplating and Facelets pages, can be found at http://tinyurl.com/3u4doe The demo application can also be viewed online at http://jsftemplating.org/mojarra-scales-demo. The jars will be available via Maven as soon as we get some technical issues worked out. As this is a release candidate, there are more than likely going to be issues. If any are are found, or if you would like to file requests for enhancements, please see the Scales issue tracker: https://scales.dev.java.net/issues/. The Scales architecture, based on JSFTemplating, makes it extremely easy to add new components, so if there’s something missing that you’d like to see, please drop us a note, or, better yet get involved and submit a patch! Real time support is often available during US business hours in #jsftemplating and ##jsf on irc.freenode.net. Ask for jdlee. Feedback, patches, etc. are, of course, very much welcome. :) ### [JavaOne 2008: Day 4](/2008/javaone-2008-day-4/) JavaOne 2008: Day 4 Like every other day at JavaOne, Friday started with a general session, this one led by James Gosling. Unlike other days, though, today would be a short one. I was a bit late to session, so I missed what Schwartz, Green, and Melissinos were doing on stage with Gosling, but there was a large piece of artwork handed over. Who knows. Well, apparently over 1,000 people, if I had to guess, do know, but I don’t. :) The session was better attended than I expected, being Friday and all. The room was dark, but it was half full, if not three quarters full. Gosling spent his time highlighting interesting Java technologies, some of which we’ve seen all week, such as the Sentilla devices and the LiveScribe Pulse Smartpen. I won’t go into details (for that, see Joe’s post on The Server Side), but this thing is extremely cool. The demo that really wowed me was Tor Norbye’s demo of NetBeans 6.1’s JavaScript support. He demonstrated how the enhancements that went into making NetBeans 6 a great Ruby IDE had been adapted to make NetBeans a great JavaScript IDE, offering things like code completion and error highlighting. Tor also showed how NetBeans will inform you when a function you’re about to call is not compatible with certain browsers. The coolest part of the whole demo, though, was the debugger. I think most serious web developers know about Firebug, but this debugger, which is a Firefox plugin (with support for other, more monopolistic and less functional browsers coming soon) allows the developer to set a breakpoint in NetBeans, hit the page in Firefox, then have the breakpoint tripped in the IDE, allowing for things like inspection of local variables, etc. In some ways, it seems very much like Firebug’s debugger, but the integration with the IDE, allowing for live editing of the code (if I recall correctly), is extremely cool. Gosling also spent some time on the jMonkeyEngine, which is an engine to make writing games in Java easier. It allows the game designer to "focus on making great games" according to Chris Melissinos. I’m not much into writing games, but I have to admit that it was an impressive piece of work. It looked very professional. What surprised me is the <strike>foolishness</strike> bravery of the presenters, as they were demoing a game based on the engine by playing against people in the UK which meant that they were depending on the Moscone internet link. Luckily, it was pretty flawless. Gosling also showed, with the help of Ken Russell and Sven Gothel, a JOGL application running on a phone, using an Nvidia APX 2500 processor. It was a very slick demo. The audio was a bit choppy — they were pegging the CPU, which they admitted they needed to fix — but it’s a good sign that mobile Java is making good strides as well. I didn’t get to see everything Gosling showed, as I had to step out and head to the All Java Web Tier EG meeting. We had JSF, Servlet and Portlet people all in the same room, discussing some overlapping functionality and where it all went. I may cover the details in another post, but I will say this about the meeting: it was quite a collection of some REALLY smart people: Ed, Roger, Hani, Greg Wilkins, and a host of others. For all the gritching some people have about the JCP, it was impressive and reassuring to see some of the sharpest minds in the industry discussing — and sometimes arguing over — the best way to extend the various specs. It’s clear that it’s not an ivory tower approach, as the needs/demands of the various user communities were clearly presented, and very forcefully defended. So that’s it for JavaOne 2008. It was a great week, if not very tiring, and often like drinking from a fire hose. From fairly early mornings to (usually) very late nights, the conference will keep you going, constantly throwing information at you. Even at the roughly 3 bazillion parties, meant to entertain, technology was never far from the minds and mouths of the attendees. JavaOne is certainly something every serious Java developer should experience. And, as silly as this may sound, the rah rah hype of the marketing side worked: I’m genuinely more excited about being a Java developer than I was. After being exposed to all of the great things going on in the non-web areas of Java, my list of things to learn and experiment with has gone from hard to manage to nearly impossible. And that’s fine by me. :) ### [JavaOne 2008: Day 3](/2008/javaone-2008-day-3/) JavaOne 2008: Day 3 My day started today with the Intel general session. I went in with low expectations for some reason, but came away pretty pleased. The speaker, Douglas Fisher, Vice President, Software and Solutions Group and General Manager, Systems Software Division of Intel Corporation, talked about how software drives innovation in hardware, which makes possible more interesting things in hardware, which in turn drives more innovation in hardware, and the cycle repeats. Years ago, an Intel exec whose name escapes me described this as the software spiral. He then brought a Sun exec (Jeet Kaul, if I recall correctly) onto the stage to discuss performance gains in the JVM, presumably in the virtualization space. He shared how from January 2007 to JavaOne 2007, they made a 20% gain in performance, so they set their goal for JavaOne 2008 at 60%. They announced today a 68% gain, with the demo peaking at 74%, on the exact same hardware and software that was used last year. The only difference was the JVM. Very cool. Fisher then went on to speak about the mobile space for a bit, talking about Intel’s Atom processor, which is TINY. He had 1,000 Atom processors in a vial like one might find in a science lab. Amazing. He then showed a video for moblin.org, which highlighted where Intel sees things going with mobile devices, and there were some very cool smoke and mirrors demos in the videos. If any of those products ever make it to market, we’re going to see some very, very cool things in terms of personalized, context-aware mobile devices. My first session of the day compared the Eclipse RCP and the NetBeans Platform. I’m not currently doing any desktop work, but I have considered getting back into that. It sounds like a fun challenge, and one completely different from what I normally work with. The session was really good. It was a great, even-handed comparison between the two, complete with the to-be-expected assessment that the best framework depends on your needs. Personally, should I start a project like that, I’ll probably use NetBeans, as I prefer a pure Swing approach to Eclipse’s SWT approach, and, to be honest, Eclipse annoys me a bit. : ) Next up, after a long break, was Migrating (Large) Applications to OSGi. I don’t know what I expected, really, but that wasn’t it. Not that it was bad, mind you. They gave a brief overview of what OSGi is and what it offers, then gave some pretty sound, concrete tips on migrating large systems, such as migrating piece by piece, for example. They also couldn’t stress enough that custom ClassLoaders are bad. Don’t do it. :P I’m not sure what I was looking for, but I enjoyed the session nonetheless. The close of my day in terms of sessions as Ed Burns and Roger Kitain’s talk on JSF 2. As an Expert Group member, I know (or should know ; ) everything that might be in the talk, but I still wanted the recap. I wish they had gone into more detail on the annotations side of things, as I think that’s pretty exciting in terms of productivity, though it likely would have devolved into one slide after another of "here’s another annotation!" so they probably made a wise choice. Ed did show off the composite component support currently in the draft spec. That support, coupled with Ryan’s Groovy work, made for a very cool demo. Given the short time allotted, they did a fine job. I hope it got everyone in the room as excited as I am about the upcoming spec. Here are some pictures from that session: " Before I left, I got my picture taken with Duke: image::meandduke.jpg and took some pictures of the Moscone Center on my way out: image:southlobby1.jpg image:southlobby2.jpg image:southlobby3.jpg image:southlobby4.jpg ### [JavaOne 2008: Day 2](/2008/javaone-2008-day-2/) JavaOne 2008: Day 2 Day 2 of JavaOne is effectively over. As I sit here typing, I have one more event, the hands-on-lab Plug Into GlassFish™ V3 With JavaServer™ Faces and jMaki in about an hour, which should be really good. It’s basically a lab showing how to do what Jerome demoed yesterday afternoon in the general session when he added a feature to the GlassFish admin console. The day has been pretty good. I skipped the Oracle general session this morning, but I was told that they announced that they are releasing Eclipse plug-ins that offer some of JDev’s functionality with regard to the Oracle ESB. While that doesn’t help us NetBeans users, it is is good news for Eclipse users, as now they won’t be forced to use JDev if they have to talk to the Oracle ESB. Another announcement I somehow missed is Sun’s announcement of a partnership with Liferay, which is really good news, I think. In a former life, I used Liferay briefly. While I didn’t get the chance to become really proficient with the system, I really liked it. I think I might take a look at that as a solution for the OKC JUG (assuming I can solve the Java hosting issue). Here are more details on the announcement, if you’re interested. A funny note: In the Web Beans talk today, Gavin was lamenting the lack of a real, full-featured event system in JSF, something which Web Beans hopes to fix and that will be fixed in JSF 2. Someone in the crowd piped up, "What about JMS?" Gavin responded, "'What about JMS?' Are you serious?" <!--pull-→Gavin responded, "'What about JMS?' Are you serious?"<!--/pull-→ then went on to lambaste the idea. He was right: JMS is totally inappropriate for what he was discussing, but I really feel sorry for the guy that suggested it. Apparently, no one warned him of Gavin’s proclivity for blunt, brutally honest responses. One that strikes me as really phenomenal about Sun is their willingness to mingle with the unwashed masses (and I admit: we can be a scary lot :). As I was leaving the pavilion today, James Gosling was there talking to someone, when another conference attendee asked him if she could have her picture taken with him. He affably replied, "Sure!" and posed for the camera. A few moments later, he strolled through the same crowded hall as everyone else, completely unassuming. He gets high marks from me for that (for what little worth those marks are worth ;). My only real complaint so far with the conference is that the network is awful. It’s almost useless. What makes it worse is that this is a problem that recurs every year. It’s well known and oft joked about, even by Sun execs (see Rich Green’s comments in Tuesday’s general session). It seems to me, though, that Sun has no one to blame but themselves. If the network is the Moscone Center’s, then Sun needs to push them to beef it up for the 15,000 constantly connected geeks that they know are coming. If it’s Sun’s network, then they’re really on the hook for the pain we go through, not to mention the poor speakers who foolishly depend on internet access for their demos. The network is more than the computer; Sun needs more tubes in here. Time to chug down the rest of this Diet Pepsi (it was either that or Diet Mt. Dew) and head to my lab. ### [JavaOne 2008: Day 1](/2008/javaone-2008-day-1/) JavaOne 2008: Day 1 Good morning. It’s time for my JavaOne 2008 Day 1 report (though it’s actually the morning of the 2nd day :). Thanks to the graciousness of Sun Microsystems, I’m here on the Java Blogger program, giving me really amazing access and privileges. All I have to do is blog about my experience, which I would have done anyway, so over the next few days, I’ll be filing "reports" on what I’ve seen and heard. So, with that introduction out of the way, let’s recap day 1. The day started off early. I grabbed breakfast in the press room then hopped in the Press/Analyst room for the kick off keynote. As I stood there, I realized I was standing behind a couple of friends of mine, Joesph Ottinger of The Server Side, and Eugene Ciurana of LeapFrog (and Tesla), so I introduced myself, as we’ve never met in real life. Once the doors opened, we filed in and found our seats, and got to watch a dance troupe gyrating on stage. They weren’t bad (they were actually pretty good, I guess some would say), but not my thing, really. At one point, the dancers took a break so James Gosling could come up and do his usual shirt sling shot. " Finally, the keynote began and Rich Green the stage. His speech was a pretty typical rah rah speech, in which he paraded various vendors with Java-based products on stage, such as Ian Freed of Amazon with the Amazon Kindle, and Rikko Sakaguchi of Sony Ericsson with…​a phone whose model number I can’t remember, but which I want to check out nonetheless. There was also a fairly disastrous JavaFX demo by Nandini Ramani. The demo crashed three times on her, though we learned from Josh Marinacci that the demo had a race condition which they fixed later. Embarrassing for Nandini, I’m sure, but it didn’t dent my enthusiasm for the platform. Speaking of JavaFX, it appears that like JavaOne 2007, this is the year of media, powered by JavaFX. There were a plethora of JavaFX-based demos, either showing audio, a game, or metrics taken from sensors placed around the Moscone Center, JavaFX was displayed proudly. A couple of interesting things to note were JavaFX running on Android, and the JavaFX SDK due in beta this summer (for which you can sign up at javafx.com). The Android demo was interesting. It’s my understanding the the Android SDK takes your Java code and compiles to run on the Dalvik VM, so it’s not Java bytecode at run-time. I’m curious how they got JavaFX to run, then: did they compile the run-time to run on Android, or, as Jonathan Schwartz commented cryptically, do they have the JVM running on Dalvik. Or maybe I’m missing something. :) The Neil Young announcement, to be honest, was a bit of a let down. Yes, the project is cool, and yes the man’s a legend, but I sure was hoping for some great new technology announcement. :) One you get past JavaFX, one of the biggest themes, it seems to me, has been GlassFish v3. They’re really pushing that hard, which makes sense, I think, as it is really, really cool technology. Roberto Chinnici discussed the future of Java EE, highlighting some of the features of the upcoming spec, then brought out Jerome Dochez, the architect behind GlassFish. Jerome then demoed v3, discussing it’s relatively new OSGi foundation, and then showed how, for example, the EJB container can be added to GlassFish at run-time, no server restart needed. In the words of Rich Green, "very cool stuff." Jerome also demoed the work that Ken Paulsen and his team have done in making the Admin Console pluggable, which has some interesting OEM possibilities. Arun Gupta and Tor Norbye then showed off the scripting language support in GlassFish with a networked, two-player Tic Tac Toe game, finishing with Tor running the game "Global Thermonuclear War." When the game’s map showed nuclear explosions all over the US, Tor shouted, "Oh no! What have I done?!" Priceless. Danny Coward, the Chief Architect for Java SE, then discussed where SE is and where it’s heading. There were two big announcements in his presentation. The first was the the Java Module System will now interoperate with OSGi, hopefully putting to rest, finally, the long and contentious feud between the camps. The second, which I found more exciting, was the announcement of a baked-in video codec in SE. It’s based on a codec from On2, so I don’t know what kind of market penetration it will get, but it is a single codec that content creators can depend on being there on all modern Java-capable devices, from your desktop to your cell phone, so it should do well. Time will tell. Also demoed were changes to the applet plugin. It boots faster, an applet crash won’t take out your browser, and the applet can now be detached from the page and run separately. Close the applet, and it reattaches to the web page. Detach the applet and close the browser, and you’re given the option of installing the application on your local machine. If you do so, you no longer need a browser to run the app. Really, really cool. As I sit here sipping this Kool-Aid, I think JavaFX and this new applet plugin will make applets viable again. I’m certainly anxious to play around with the technology. The pavilion floor is, of course, packed with vendors pitching their wares and handing out free stuff. I’ve gotten more t-shirts in one day than I did all last year, and that includes attending two tech conferences. My 4-year old son loves the screaming flying monkey from AT&T. :) Time to run to a session (BTW, Cay Horstmann is three chairs to my left. Celebrity sightings are fun! :) I’ll either do mini posts during the day or one big one tonight. We’ll see. Sorry for any typos and bad grammar here. I’m typing on the run, so to speak, so I haven’t had time to proof read and edit. We’ll see if I come back and do that. Once more unto the breach, dear friends, once more! ### [JavaOne on Your Google Calendar](/2008/javaone-on-your-google-calendar/) JavaOne on Your Google Calendar Next week, I’ll be off to JavaOne. With everything that’s going on, I thought it would be nice to have my JavaOne schedule on my Google Calendar, which I could then sync with my phone. Sadly, it wasn’t as easy as I thought it would be (though I certainly could be the failure in the process :). After I imported my schedule into Outlook (used only — and grudgingly — as iTunes is broken in that it only supports Outlook) and then synced that with my Google Calendar, all of the event start times were adjusted for the time zone differences. Importing by CSV resulted in cryptic messages about my calendar not being available, so I did what any good geek would do: I wrote my own solution, creatively named J1Sync. The program itself is really rather simple. Not counting all the imports, it’s currently less than 100 lines of code. In a nutshell, it reads its configuration from a properties file, connects to the specified Google Calendar, removes any entries it added (by looking for a special string appended to the description), then adds the events from an input file. The input file is a CSV file downloaded from the JavaOne Schedule Builder application. Execution is simple, as it takes one optional parameter, the path to the properties file, defaulting to j12008cal.csv in the current working directory: java -cp dist/j1sync.jar;lib/gdata-calendar-1.0.jar;\ lib/gdata-client-1.0.jar;lib/gdata-core-1.0.jar;\ lib/xercesImpl-2.8.1.jar \ com.steeplesoft.j1sync.J1Sync And that’s all there is to it. It’s really not very exciting code, but I’ve found it to be pretty useful. Since it removes anything it added, I can freely change my schedule as I see fit, then safely download the CSV and rerun the process with no duplicated calendar entries. If I have time, I’d like to change it so that it can log on to the Schedule Builder and grab the CSV itself, removing the manual download step. That it would make a cron job, for example, much simpler. For those interested, the source code repository can be found in the Steeplesoft Mercurial repository. I don’t have a binary download yet, but I’ll post a comment here when I do for those that don’t care to build from source. If anyone tries it out, let me know how it works for you. I’d be curious to know if my roughly one hour effort is of use to anyone else. ### [Mojarra Gets Groovy](/2008/mojarra-gets-groovy/) Today, Ryan Lubke committed code to the Mojarra tree that will allow a JSF developer to prototype and/or develop just about every JSF artifact using Groovy. When deployed to the server in development mode, the Groovy file can be changed on disk, and the changes will be picked up automatically, allowing one to avoid the compile/package/deploy cycle that can make Java web development so tedious. Once the artifact is "done," the Groovy source can be copied to a Java source file and compiled (or the build process can compile the .groovy files to .class files) for production deployment. This could be a really nice feature for component development, for example. For more details, including a sample NetBeans project, visit Ryan’s entry. All around, a very, very cool enhancement. Great work, Ryan! ### [Reintroducing the JSFTemplating FileStreamer](/2008/reintroducing-the-jsftemplating-filestreamer/) In a blog entry last year, Ken Paulsen gave a short introduction to the FileStreamer utility in JSFTemplating. Since Scales is now using JSFTemplating to make the component authoring process easier, I have been able to use this facility, allowing me to deprecate some custom code. In the process of making the migration, I’ve made changes to JSFTemplating that will be of benefit to all. In this entry, I’d like to highlight those changes, and show you how you, too, can use this great facility.// more Prior to my changes, JSFTemplating offered two ways to use the FileStreamer. One way is as a Servlet. This approach is intended for non-JSF users, though JSF users can certainly use it as well — many other frameworks have "resource servlets" as well. Another method is a ViewHandler-based approached, the approach Ken uses in his blog entry, which can only be used if the JSFTemplating ViewHandler is in play. Since I want to avoid as much external configuration as possible, and I don’t want to dictate a JSFTemplating-only approach to JSF app authoring (not that there’s anything wrong with that), I needed another method, so I created a PhaseListener-based approach: FileStreamerPhaseListener. Using a PhaseListener, we are able to process the request from inside the JSF lifecycle, giving us access to application state, etc. For my purposes (namely, modifying the FileDownload component to use the FileStreamer), that is very important. The FileDownload component currently works by stuffing a reference to itself in the HttpSession, which is then retrieved when the resource request is made, a process made difficult, though not impossible in a Servlet-based approach. While the PhaseListener solves how to handle the incoming request, it doesn’t solve the problem of getting the data from the component. This is where FileStreamer really shines. As Ken notes in his blog, FileStreamer supports the idea of a ContentSource, which is a class that handles getting the content of a source (if you can imagine that) from an arbitrary location. His examples show getting the resource from the file-system as well as a remote server, all through the same API. Leveraging that capability, I added to Scales the FileDownloadContentSource: public class FileDownloadContentSource implements ContentSource { public final static String CONTENT_SOURCE_ID = "fileDownloadCs"; public String getId() { return CONTENT_SOURCE_ID; } public InputStream getInputStream(Context context) throws IOException { InputStream in = (InputStream) context.getAttribute("inputStream"); if (in != null) { return in; } String componentId = (String) context.getAttribute(Context.FILE_PATH); FacesContext fc = FacesContext.getCurrentInstance(); FileDownload comp = (FileDownload) fc.getExternalContext() .getSessionMap().get("HtmlDownload-" + componentId); if (comp != null) { Object value = comp.getData(); if (value != null) { String mimeType = comp.getMimeType(); context.setAttribute(Context.CONTENT_TYPE, mimeType); if (FileDownload.METHOD_DOWNLOAD.equals(comp.getMethod())) { context.setAttribute(Context.CONTENT_DISPOSITION, comp.getMethod()); } else { context.setAttribute(Context.CONTENT_DISPOSITION, "inline"); } byte[] data = null; if (value instanceof byte[]) { in = new ByteArrayInputStream ((byte[]) value); } else if (value instanceof ByteArrayOutputStream) { in = new ByteArrayInputStream (((ByteArrayOutputStream) value) .toByteArray()); // EEEK! } else if (value instanceof InputStream) { in = (InputStream)value; } else { throw new FacesException( "HtmlDownload: an unsupported data type was found: " + value.getClass().getName()); } } } context.setAttribute("inputStream", in); return in; } public void cleanUp(Context context) { InputStream is = (InputStream) context.getAttribute("inputStream"); // Close the InputStream if (is != null) { try { is.close(); } catch (Exception ex) { // Ignore... } } context.removeAttribute("inputStream"); } public long getLastModified(Context context) { return -1; // We don't/can't know so make it redownload every time } } The really interesting part is in getInputStream(). We query the request for the component ID, then look it up in the session. If it is found, we then query the data returned to determine its type, then return an InputStream which the PhaseListener will use to stream the data to the client. I really like this ContentSource approach. It’s very simple and elegant, and, as you can see, very easy to implement. We still have two problems remaining, though: how do I tell JSFTemplating about this new ContentSource, and how do I generate a URL to access the data? In Ken’s example, he used an init-param in web.xml to register his ContentSource`s. Again, I wasn’t too comfortable with that, as it requires more external configuration. I want people to be able to drop this component on a page and not have to worry about configuration (though there’s still the `PhaseListener registration, which I’m working on). After some discussion with Ken, I developed, with much help from him, a mechanism by which JSFTemplating will register ContentSources based on a properties file. This file, META-INF/jsftempalting/fileStreamer.properties, looks something like this: contentSources=com.sun.mojarra.scales.util.FileDownloadContentSource The FileStreamer constructor finds any of these files that might be in any JAR in the web application’s lib directory (WEB-INF/lib) and registers the ContentSource`s specified in the comma-delimited list (i.e., `contentSources=org.example.contentSources.ExampleContentSource, org.example.contentSources.ProxyContentSource). For the performance sensitive, this happens only once during a web app’s lifecycle, as the FileStreamer reference is a singleton. At any rate, for the curious, here’s how the files are found, a new public and static method on FileUtil called getJarResource() that can be used by any application: public static List<Tuple> getJarResources(FacesContext facesContext, String resourcePath, String... searchPaths) throws IOException { if (searchPaths == null) { // Use default jar search path... searchPaths = DEFAULT_SEARCH_PATH; } List<Tuple> entries = new ArrayList<Tuple>(); ExternalContext ec = facesContext.getExternalContext(); for (String searchPath : searchPaths) { Set<String> paths = ec.getResourcePaths(searchPath); for (String path : paths) { if ("jar".equalsIgnoreCase(path.substring(path.length() - 3))) { JarFile jarFile = new JarFile(new File(ec.getResource(path).getFile())); JarEntry jarEntry = jarFile.getJarEntry(resourcePath); if (jarEntry != null) { entries.add(new Tuple(jarFile, jarEntry)); } } } } return entries; } The return from this method is tuple containing the JarFile and JarEntry for the properties file, which FileStreamer then loops through and processes. The only remaining issue, then, is URL creation. The new FileStreamerPhaseListener has a utility method to handle that for us: public static String createResourceUrl(FacesContext context, String contentSourceId, String path) If contentSourceId is null, the default ContentSource is used, which is JSFTemplating’s ResourceContentSource. In Scales' case, though, we want to use our custom ContentSource, so our call to this method looks like this (from FileDownloadRenderer): protected String generateUri(FacesContext context, FileDownload comp) { return FileStreamerPhaseListener.createResourceUrl(context, FileDownloadContentSource.CONTENT_SOURCE_ID, comp.getClientId(context)); } That results in a URL like this: /mojarra-scales-demo-facelets/jsft_resource.jsf?contentSourceId=fileDownloadCs&filename=j_id5 The browser can request that URL, and the FileStreamerPhaseListener will recognize that it should process it, determine and acquire the ContentSource, then query that for the data, setting the mime type, etc., as it streams the data to the client. I am also now using this exact approach, though with the default ContentSource, to serve up from the Scales jar file the Javascript and CSS needed for the components, demonstrating clearly, I think, the power and flexibility of this great facility. ### [Web Profile Wackiness](/2008/web-profile-wackiness/) Web Profile Wackiness In a recent blog post, Java EE 6 (JSR 316) specification co-lead Roberto Chinnici discussed the two leading proposals for the web profile in the upcoming Java EE 6 specification (For more information about profiles, one can start with this article on TheServerSide.) The part that caught me by surprise and confuses me greatly is why the inclusion of JavaServer Faces in the web profile would be controversial. Having spoken with an expert group member, who I will not out :), the argument comes down to this: "We shouldn’t force a broken technology, that is not the clear winner on people." I think that’s a very interesting statement, in that it precludes doing just about anything in the spec. Java EE is a huge specification. It encompasses a vast array of technologies, including JSF. One of those technologies, for example, is the Java Persistence API, of which, I’ll admit, I’m pretty fond. It seems counter-intuitive that it would exclude the standard web application framework. It is, though, not without its faults, and definitely not without its own detractors. There are many very vocal Hibernate fans (not to mention JDO fans) that question why we need JPA. Their contention is that Hibernate is better, so why not just use that? Whether or not they have a point isn’t really relevant here, but their contention is: If JPA is not superior, and it’s clearly not the leading persistence API, why force that on someone via the specification? In fact, Java itself is not the clear winner when it comes to development platforms, so should there be any spec at all? It’s no secret that JSF is not perfect — that’s why the JSF 2 EG exists and is doing what we’re doing. I think, though, the question of whether or not JSF belongs in the web profile has already been answered back in the Java EE 5 specification. The spec listed JSF as the standard<sup>1</sup> web application framework. Since EE 5 took that stance, it seems to me to be the logical thing to put that library under the web profile umbrella. The question of its brokenness is completely separate. If it truly is broken, and there is a raft of people who would disagree, then the question of its inclusion the specification should be revisited. If it is decided that it stays in the spec, then it belongs in the web profile. If it is decided to remove it from the spec, then that takes care of the profile question. Furthermore, JSF’s inclusion in the profile in no way forces the framework on anyone. I write and deploy applications to GlassFish all the time, and it includes a messaging framework, but I don’t feel compelled to use it. It also includes JSP, which just about everyone in the JSF world feels is broken<sup>2</sup>, and I’m not forced to use it. As with any complex development and deployment environment, there will be things one does not need, so one simply chooses not to use it. The question before the EE, though, is what kind of environment can a web developer expect when he sits down in front of a web profile compliant application server, and it seems counter-intuitive that it would exclude the standard web application framework. One last point, and I’ll quit rambling. It has been rightly pointed out that option A is bascially Tomcat. If that’s all the web profile offers and I have to track down JSF, EL, Java Mail and a host of other libraries, why should I bother with the container, even if it is web profile compliant. I can just install Tomcat, and get a simpler server. To omit the technologies in option B will completely neuter the profile and help absolutely no one. Except the Tomcat team. :) 1 Standard in the sense that it’s in the EE spec, not in the everyone-is-using-it sense of the word. Though they should be. :) 2 With JSF 2, in fact, all the cool new features will only be available in the Facelets-like page description language we’re working into the spec. ### [A ValueChangeListener Question and Answer](/2008/a-valuechangelistener-question-and-answer/) A ValueChangeListener Question and Answer At the lunch session of the OKC JUG today, a question was asked about the difference between the valueChangeListener attribute and <f:valueChangeListener/>. That is, <h:selectOneMenu id="optionMenu" value="#\{optionBean.selectedOption}" valueChangeListener="#\{optionBean.optionChanged}" onchange="submit()"> <f:selectItems value="#\{optionBean.optionList}" /> </h:selectOneMenu> and <h:selectOneMenu id="optionMenu" value="#\{optionBean.selectedOption}" onchange="submit()"> <f:selectItems value="#\{optionBean.optionList}" /> <f:valueChangeListener type: "com.mycompany.MyValueChangeListenerImpl" /> </h:selectOneMenu> The question was, which is "better?" There was also a question if the latter form automatically handled the JS on the parent component. I will now attempt to answer those questions. :) The former form takes a MethodExpression (#\{optionBean.optionChanged}) that points to a method that satisfies the following method signature: public void valueChangeListener(ValueChangeEvent e); The latter form points to a class that implements the ValueChangeListener interface: public class MyValueChangeListener implements ValueChangeListener { void processValueChange(ValueChangeEvent event) throws AbortProcessingException { //... } } You can also use "binding" with the component: <f:valueChangeListener type: "com.mycompany.MyValueChangeListenerImpl" binding="#\{optionBean.valueChangeListener}"/> In OptionBean, you would have a method like this: public ValueChangeListener getValueChangeListener() { return new MyValueChangeListener(); } If the binding returns null, and the type is specified, then a ValueChangeListener of the specified type is created and set on the binding (i.e., setValueChangeListener(ValueChangeListener vcl) would be called). If the binding is non-null, though, the type is ignored. Note that both methods require that the user manually add the JS to the component. I can think of a couple of reasons why this is done, though they may not be the official reasons. While it could be done (maybe), care would have to be taken to determine into which event to hook. Some form elements might take onchange, while others take onblur. In the event of <h:inputText>, for example, does the user want to fire this onchange or onblur? Most likely onblur, but should the framework assume that and cause problems for the user? Probably not. Another reason, which is, to me, more significant, is that JSF doesn’t know when the listener should fire. Should it fire as soon as the field is left? What if there are several VCLs that the user wants to fire at the same time? Or perhaps the VCL is there to change server state when the user submits the form rather than changing UI state. There’s no way to tell for sure, so the onus for controlling the timing of the event falls on the page author, and rightly so, I think. There’s a lot there, so I help it helps more than confuses. If it DOES confuse, feel free to ask for clarification. ### [Dependency Management with Ant and Ivy](/2008/dependency-management-with-ant-and-ivy/) Dependency Management with Ant and Ivy One of my long-standing complaints with Ant is that project dependency management is non-existent in the core Ant distribution. Many will quickly point to the Maven Ant tasks, but I’ve never been really fond of them for one reason or another. The other advice I often get is to use Ivy, but even after several attempts, I had never gotten Ivy to work. With the recent release of 2.0 beta 1, though, I thought I’d try again, and I’m glad I did. Not only have I gotten it to work for me, but I was also able to successfully configure custom resolvers. Below is what I had to do to migrate the Mojarra Scales dependency management to Ivy. Using Ivy requires, at least in the way I’m using it, two new files, ivy.xml, which defines my dependencies, and ivysettings.xml, which configures my custom resolvers. The usage from my Ant build file is actually pretty simple, so we’ll start there: <target name="-download-ivy" unless="skip.download"> <!-- download Ivy from web site so that it can be used even without any special installation --> <echo message="installing ivy..."/> <get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/$\{ivy.install.version}/ivy-$\{ivy.install.version}.jar" dest="$\{ivy.jar.file}" usetimestamp="true"/> </target> <target name="-install-ivy" depends="-download-ivy" description="--> install ivy"> <path id="ivy.lib.path"> <fileset dir="$\{lib.build.dir}" includes="*.jar"/> </path> <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path"/> </target> <target name="update" depends="prepare,-install-ivy" description="Download project dependencies"> <!-- edited for brevity --> <ivy:settings file="ivysettings.xml" /> <ivy:retrieve pattern="lib/[conf]/[artifact]-[revision].[ext]" /> <!-- edited for brevity --> </target> You will also need to define these properties somewhere: ivy.install.version=2.0.0-beta1 ivy.jar.file=$\{lib.build.dir}/ivy.jar But what’s going on here? The -download-ivy target, simply downloads the Ivy jar and installs it in the target directory, lib/build in Scales' case. Next, -install-ivy tells Ant how to find the Ivy tasks. Finally, in the update target, we tell Ivy where to find the settings (which we’ll look at in a moment), and then we tell Ivy to download the dependencies. But what’s that pattern all about? This, I think, is a pretty interesting aspect of Ivy. Unlike Maven (and the related Ant tasks), the files aren’t just downloaded into a local repo and left, exposed to the build system through some sort of path or fileset reference. Ivy does download and cache the artifacts, but it also copies those to a directory in one’s project (at least, that’s how I have it set up ;). The pattern tells Ivy to copy the files a directory named after the configuration (more on that in a moment) under the lib/ directory, using an artifact-version.ext file name structure. It is then up to me to create a classpath or fileset reference from those files, and I think I like it that way. So, what’s this "configuration" I mentioned? For that, let’s turn our eyes to ivy.xml. The ivy.xml for Scales looks like this at the moment: <ivy-module version="1.0"> <info organisation="org" module="standalone" revision="working"/> <configurations defaultconfmapping="runtime->*"> <conf name="build"/> <conf name="javascript"/> <conf name="applet" /> <conf name="compile" extends="applet" /> <conf name="test" extends="compile"/> </configurations> <dependencies> <dependency org="com.sun.wts.tools.mri" name="maven-repository-importer" rev="1.2" conf="build->*>"/> <dependency org="commons-httpclient" name="commons-httpclient" rev="3.1" conf="applet->*"/> <dependency org="commons-fileupload" name="commons-fileupload" rev="1.1.1" conf="applet->*"/> <dependency org="commons-codec" name="commons-codec" rev="1.3" conf="applet->*"/> <dependency org="commons-io" name="commons-io" rev="1.2" conf="applet->*"/> <dependency org="commons-logging" name="commons-logging" rev="1.1" conf="compile->*"/> <dependency org="commons-lang" name="commons-lang" rev="2.3" conf="compile->*"/> <dependency org="commons-collections" name="commons-collections" rev="3.1" conf="compile->*"/> <dependency org="com.sun.facelets" name="jsf-facelets" rev="1.1.14" conf="compile->*"/> <dependency org="com.sun.jsftemplating" name="jsftemplating" rev="1.2-SNAPSHOT" conf="compile->*"/> <dependency org="com.sun.jsftemplating" name="jsftemplating-dynafaces-0.1" rev="1.2-SNAPSHOT" conf="compile->*"/> <dependency org="javax.faces" name="jsf-api" rev="1.2_07" conf="compile->*"/> <dependency org="javax.servlet.jsp" name="jsp-api" rev="2.1" conf="compile->*"/> <dependency org="javax.el" name="el-api" rev="1.0" conf="compile->*"/> <dependency org="taglibrarydoc" name="tlddoc" rev="1.3" conf="compile->*"/> <dependency org="velocity" name="velocity" rev="1.4" conf="compile->*"/> <dependency org="findbugs" name="findbugs" rev="1.0.0" conf="test->*"/> <dependency org="findbugs" name="findbugs-ant" rev="1.0.0" conf="test->*"/> <dependency org="yui" name="yui" rev="2.4.1" conf="javascript->*"/> </dependencies> </ivy-module> Let’s take that one section at a time. The first element we see is info, and I’ll be honest here: I’m really not sure what that’s for at the moment. I think it may be related to publishing (or installing, in Maven parlance) project-specific artifacts to a repository somewhere, but don’t quote me on that. The next section is where we define "configurations," which seem to be roughly analagous to Maven’s scope’s, but completely configurable and arbitrary. I have defined five configurations: build: Jars need only for the build environment javascript: This is an unusual one, but I use this only for the YUI files (currently) to make extracting the files easier later in the build process applet: Jars which need to be bundled for use with the applet compile: Jars needed only for compilation, API classes, for example test: Jars needed for testing Take note of the extends attribute. It works just like you probably think it does: since compile extends applet, it will get all of the artifacts defined for it, as well as those defined for applet. Given how Ivy (is configured to) handle dependencies, that means you’ll get two copies of some of those artifacts, but I’m OK with that. Next in the file is the list of dependencies, which is pretty straightforward. The org maps to Maven’s groupId, the name maps to artifactId, rev maps to version, and conf maps to scope in Maven terms. Please don’t ask what that odd "→*" is there for, as I don’t understand that fully yet. All I know is that it won’t work without it. :) Next up is ivysettings.xml: <ivysettings> <settings defaultResolver="chained"/> <property name="java.net.maven.pattern" value="[organisation]/jars/[module]-[revision].[ext]"/> <resolvers> <chain name="chained" returnFirst="true"> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="java-net-maven1" root="http://download.java.net/maven/1" pattern="$\{java.net.maven.pattern}" m2compatible="false"/> <ibiblio name="java-net-maven2" root="http://download.java.net/maven/2/" m2compatible="true"/> <url name="sourceforge"> <artifact pattern="http://easynews.dl.sourceforge.net/sourceforge/[organization]/[module]_[revision].zip" /> <artifact pattern="http://easynews.dl.sourceforge.net/sourceforge/[organization]/[module]-[revision].zip" /> </url> </chain> </resolvers> </ivysettings> One of the great things about Ivy 2 is that is configured to look at Maven repos by default. For Scales, though, I need some artifacts from the java.net Maven repository. To enable that, I have to define a custom resolver, which we see in the resolvers/chain elements. The chain resolver instructs Ivy to try one resolver after another to find the current artifact, with the returnFirst attribute telling Ivy to bail out as soon as a resolver that locates the artifact. Inside the chain, I instruct Ivy to use the ibiblio repository first. I then configure both the Maven 1 and Maven 2 java.net repositories. To do that, I configure additional instances of the ibilio resolver, but I change the root URL for the repository. In the case of the Maven 1 repository, I describe the pattern needed to find the artifact, as well as telling the resolver that the repository is not Maven 2 compatible. Finally, I create a URL repository, called "sourceforge," which I will use to resolve my YUI dependency. With all of that in place, I can issue an ant update from the command line, and sit back and watch Ivy checking the configured repositories for my dependencies. It may seem like a lot to configure for dependencies, but Ivy is certainly better than the homegrown dependency management schemes I’ve seen (and devised), and is certainly less intrusive than migrating wholesale to Maven. While I <i>am</i> coming around on Maven 2, this will be a great tool for those projects that I can’t (or won’t) migrate. ### [Announcing Mojarra Scales](/2008/announcing-mojarra-scales/) Some of you may be wondering what the status is on the RI Sandbox. With the announcement of Project Mojarra, we can finally take the wraps off of Mojarra Scales, the promotion of the RI/Mojarra Sandbox to its own project. There are a few differences between the Sandbox of Scales to note, such as package names, namespace, etc. There has also been a fair amount of refactoring inside the library to simplify the components somewhat (more on that later). To migrate from the RI Sandbox to Mojarra Scales, you will need to do the following: Remove jsf-ri-sandbox-0.9.jar Add mojarra-scales.jar. (I’m working on getting this added to the java.net maven repository as well). Add the (new) JSFTemplating dependencies from here and here. Change your references to the RI Sandbox URL. JSP: <%@ taglib uri="http://java.sun.com/mojarra/scales" prefix="sc" %> Facelets: xmlns:sc="http://java.sun.com/mojarra/scales" Add the static resource PhaseListener: <lifecycle> <phase-listener> com.sun.mojarra.scales.util.StaticResourcePhaseListener </phase-listener> </lifecycle> That should be all there is too it (though if I’ve missed a step, please let me know). ### [JSFTemplating and Woodstock: Component Authoring Made Easy](/2008/jsftemplating-and-woodstock-component-authoring-made-easy/) JSFTemplating and Woodstock: Component Authoring Made Easy In my last post, I alluded to some refactoring done inside the Sandbox / Scales library to simplify the components' code. If you are interested in learning more about what was done, and how you can apply the same techniques to your own JSF components, please see this article, written by Ken Paulsen and myself, with editing help from Rick Palkovic, which shows how one can use JSFTemplating and some (currently "private") annotations from the Woodstock project to greatly simplify JSF component authoring. I think it’s a very interesting and helpful technique, which, by the way, resembles what JSF 2 will likely offer when we finally ship it later this year. Oh, yeah. Happy New Year’s! :) ### [Announcing Project Mojarra](/2007/announcing-project-mojarra/) Announcing Project Mojarra It is with a pretty high degree of excitement that we, the <strike>JSF RI</strike> Mojarra development team, announce Project Mojarra. While the project itself is not new (it’s the same, high quality and stable JSF implementation we’re all familiar with ;), the announcement of the new moniker brings to an end a lengthy, and sometimes frustrating, process of deciding on a name that can pass legal muster. For more details on the name change, see this entry by Ryan Lubke. ### [OC4J Seam Archetype Update](/2007/oc4j-seam-archetype-update/) OC4J Seam Archetype Update Well, that wasn’t hard. I think I have the redeploy issue fixed, and a shared library was the trick. It appeared that the redeployment issue was due to some odd class loading issue, so I decided to try a shared library. To do that, I create the directory in j2ee/home/shared-lib/hibernate/3.2 and put these jars there: antlr-2.7.6.jar asm-1.5.3.jar asm-attrs-1.5.3.jar cglib-2.1_3.jar commons-collections-3.2.jar commons-logging-1.1.jar dom4j-1.6.1-jboss.jar hibernate-3.2.4.sp1.jar hibernate-annotations-3.3.0.ga.jar hibernate-commons-annotations-3.0.0.ga.jar hibernate-entitymanager-3.3.1.ga.jar hsqldb-1.8.0.7.jar javassist-3.3.ga.jar jboss-archive-browsing-5.0.0alpha-200607201-119.jar jta-1.0.1B.jar log4j-1.2.14.jar To be candid, I’m not 100% sure that all of these classes belong in a Hibernate library, but it works and I’m afraid to breathe on it. :) To describe the shared library to OC4J, I added the following XML to j2ee/home/config/server.xml: <shared-library name="hibernate" version="3.2" library-compatible="true"> <code-source path="../shared-lib/hibernate/3.2/"/> </shared-library> And that’s it. I created the project and immediately built and deployed, verified that the application worked, then repeatedly redeployed and tested the app without failure. That’s not to say that the archetype is complete or perfect in any way, but it’s Good Enough for Now. :) Any fixes/enhancements/etc. are, of course, very welcome. ### [A Seam+JPA/Hibernate on OC4J Maven 2 Archetype](/2007/a-seam-jpa-hibernate-on-oc4j-maven-2-archetype/) A Seam+JPA/Hibernate on OC4J Maven 2 Archetype As a follow-up to my entry on getting a Seam and JPA/Hibernate application running on OC4J, I now have an alpha release of a Maven 2 archetype available for use and testing, with heavy emphasis on testing. Using the archetype is pretty simple (assuming you know how to use Maven 2 archetypes in general): mvn archetype:create -DarchetypeGroupId=com.steeplesoft.maven.archetypes -DarchetypeArtifactId=seam-jpa-oc4j -DarchetypeVersion=1.0-alpha -DremoteRepositories=http://repo.steeplesoft.com/maven2 -DgroupId=com.foo -DartifactId=myApp -Dversion=1.0 What this gets you is a multi-module project, such as what was described in the aforementioned article, with (hopefully) working examples of a JPA entity bean, a HSQL-based PersistenceUnit, and a simple JSF (Facelets), all wired together via Seam. Chances are good that you’ll want to change the package name and structure to match your project and organization’s needs, but, if you’re like me, having these examples to copy and paste will help when creating a new project. :) This is by no means perfect. Given my newness to Maven, the archetype itself could probably use some help, <strike>but there’s something more serious to consider at the moment involving OC4J. If you create the project as described above, deploy the resulting EAR file and hit the web context, you should see that the application works fine. If you try to redeploy the application, you’ll see an error message like this in the web console (formatted for readability)</strike>(this is been fixed): Operation failed with error: java.lang.IllegalStateException: ClassLoader "myapp.web.myapp-web-1.0:0.0.0" (from in /oc4j/j2ee/home/applications/myapp/myapp-web-1.0/): This loader has been closed and should not be in use. The server console will show something like this: oracle.oc4j.admin.internal.DeployerException: java.lang.IllegalStateException: ClassLoader "myapp.web.myapp-web-1.0:0.0.0" (from <web-module> in /oc4j/j2ee/home/applications/myapp/myapp-web-1.0/): This loader has been closed and should not be in use. at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:258) at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:120) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:59) at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:48) at org.jboss.seam.persistence.EntityManagerFactory.createEntityManagerFactory(EntityManagerFactory.java:81) at org.jboss.seam.persistence.EntityManagerFactory.startup(EntityManagerFactory.java:50) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.jboss.seam.util.Reflections.invoke(Reflections.java:21) at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:125) at org.jboss.seam.Component.callComponentMethod(Component.java:2095) at org.jboss.seam.Component.callCreateMethod(Component.java:2010) at org.jboss.seam.Component.newInstance(Component.java:1981) at org.jboss.seam.contexts.Contexts.startup(Contexts.java:304) at org.jboss.seam.contexts.Contexts.startup(Contexts.java:278) at org.jboss.seam.contexts.ServletLifecycle.endInitialization(ServletLifecycle.java:95) at org.jboss.seam.init.Initialization.init(Initialization.java:554) at org.jboss.seam.servlet.SeamListener.contextInitialized(SeamListener.java:34) at com.evermind.server.http.HttpApplication.initDynamic(HttpApplication.java:1130) at com.evermind.server.http.HttpApplication.<init>(HttpApplication.java:738) at com.evermind.server.ApplicationStateRunning.getHttpApplication(ApplicationStateRunning.java:414) at com.evermind.server.Application.getHttpApplication(Application.java:545) at com.evermind.server.http.HttpSite$HttpApplicationRunTimeReference.createHttpApplicationFromReference(HttpSite.java:1990) at com.evermind.server.http.HttpSite$HttpApplicationRunTimeReference.<init>(HttpSite.java:1909) at com.evermind.server.http.HttpSite.addHttpApplication(HttpSite.java:1606) at oracle.oc4j.admin.internal.WebApplicationBinder.bindWebApp(WebApplicationBinder.java:238) at oracle.oc4j.admin.internal.WebApplicationBinder.bindWebApp(WebApplicationBinder.java:99) at oracle.oc4j.admin.internal.ApplicationDeployer.bindWebApp(ApplicationDeployer.java:547) at oracle.oc4j.admin.internal.ApplicationDeployer.doDeploy(ApplicationDeployer.java:202) at oracle.oc4j.admin.internal.DeployerBase.execute(DeployerBase.java:93) at oracle.oc4j.admin.jmx.server.mbeans.deploy.OC4JDeployerRunnable.doRun(OC4JDeployerRunnable.java:52) at oracle.oc4j.admin.jmx.server.mbeans.deploy.DeployerRunnable.run(DeployerRunnable.java:81) at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:298) at java.lang.Thread.run(Thread.java:595) The only way I’ve found to fix that is to restart the app server, which is, of course, extremely ugly. Making this work on OC4J has been extremely trying, and this is just one more example of the pain I’ve put myself through. Since the contract dictates this container, though, I have little choice. :) At any rate, I’m going to try to work around this by creating one or more shared libraries on the app server and see what that gets me. I’ll report back what I find. In the meantime, you can find the archetype in my (new) Maven repo (when the DNS finally propagates), or in its (experimental) Mercurial repository. ### [Seam and JPA/Hibernate on OC4J 10.1.3](/2007/seam-and-jpa-hibernate-on-oc4j-10-1-3/) Seam and JPA/Hibernate on OC4J 10.1.3 On a recent project, the architecture we settled on included JavaServer Faces (no surprise, there, I guess:), JBoss Seam and JPA. The production environment is Oracle’s OC4J, so the stack we chose has to deploy (easily) to that container. While I did get it working, it wasn’t easy, nor was it easily reproducible. Now that the pressures of deadlines have passed, I took the time to track down what exactly needs to be done to make the application deploy and run on OC4J. In retrospect, it doesn’t look that hard, but, knowing the pain I went through to make it work, I thought I’d share what you need to know if you’re in a similar situation. Quick Links Parent POM EJB POM Web App POM Ear POM JPA Configuration OC4J Application File While I was at it, I thought I’d reconstruct my build environment using Maven 2. Doing so will eventually allow me to create an archetype with which I can bootstrap new projects. With that in mind, I created a multi-module Maven project with an "EJB" module, a web module, and an EAR module. The "EJB" module isn’t a "real" EJB module, in that it doesn’t have any EJBs in right. The business/service layer classes it does have use Seam annotations to expose the functionality to the web tier. The web module contains the web-related Faces-managed beans (think backing beans), and the ear module simply packages everything in an EE5-compliant ear file for deployment. Here are the Maven POM files: [[parent"]] /pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft</groupId> <artifactId>refImpl</artifactId> <packaging>pom</packaging> <version>1.0</version> <name>refImpl</name> <url>http://maven.apache.org</url> <repositories> <repository> <id>java.net</id> <url>http://download.java.net/maven/1</url> <layout>legacy</layout> </repository> <repository> <id>jboss-snapshot</id> <name>The JBoss maven repo</name> <url>http://snapshots.jboss.org/maven2</url> </repository> </repositories> <parent> <groupId>org.jboss.seam</groupId> <artifactId>parent</artifactId> <version>2.0.0.CR2</version> </parent> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> </dependencies> <modules> <module>ejb</module> <module>web</module> <module>ear</module> </modules> <build> <defaultGoal>package</defaultGoal> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project> ejb/pom.xml: <project> <parent> <groupId>com.steeplesoft</groupId> <artifactId>refImpl</artifactId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft.refImpl</groupId> <artifactId>ejb</artifactId> <name>ejb</name> <version>1.0</version> <packaging>ejb</packaging> <url>http://maven.apache.org</url> <build> <finalName>myproj-ejb</finalName> </build> <dependencies> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>1.2_05</version> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> <version>1.2_05</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam</artifactId> <exclusions> <exclusion> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> </exclusion> <exclusion> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-el</artifactId> <exclusions> <exclusion> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.3.1.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.0.GA</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search</artifactId> <version>3.0.0.GA</version> <scope>runtime</scope> <exclusions> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>jboss</groupId> <artifactId>jboss-archive-browsing</artifactId> <version>5.0.0alpha-200607201-119</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> <scope>compile</scope> </dependency> </dependencies> </project> web/pom.xml: <project> <parent> <groupId>com.steeplesoft</groupId> <artifactId>refImpl</artifactId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft.refImpl</groupId> <artifactId>web</artifactId> <name>web</name> <version>1.0</version> <packaging>war</packaging> <url>http://maven.apache.org</url> <build> <finalName>myproj-web</finalName> </build> <dependencies> <dependency> <groupId>com.steeplesoft.refImpl</groupId> <artifactId>ejb</artifactId> <version>1.0</version> <type>ejb</type> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>jsr250-api</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>postgresql</groupId> <artifactId>postgresql</artifactId> <version>8.2-504.jdbc3</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam</artifactId> <exclusions> <exclusion> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> </exclusion> <exclusion> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-el</artifactId> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam-ui</artifactId> </dependency> <dependency> <groupId>org.richfaces.framework</groupId> <artifactId>richfaces-impl</artifactId> <version>3.1.1-GA</version> </dependency> <dependency> <groupId>org.richfaces.framework</groupId> <artifactId>richfaces-api</artifactId> <version>3.1.1-GA</version> </dependency> <dependency> <groupId>org.richfaces.ui</groupId> <artifactId>richfaces-ui</artifactId> <version>3.1.1-GA</version> </dependency> <dependency> <groupId>com.sun.faces</groupId> <artifactId>sandbox</artifactId> <version>0.9</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>3.0.0.GA</version> <scope>runtime</scope> <exclusions> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>javax.xml.ws</groupId> <artifactId>jaxws-api</artifactId> <version>2.1</version> <scope>runtime</scope> </dependency> <dependency> <groupId>com.sun.facelets</groupId> <artifactId>jsf-facelets</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>1.2_05</version> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> <version>1.2_05</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2</version> <scope>compile</scope> </dependency> <dependency> <groupId>commons-digester</groupId> <artifactId>commons-digester</artifactId> <version>1.6</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1-jboss</version> <scope>compile</scope> </dependency> <dependency> <groupId>el-impl</groupId> <artifactId>el-impl</artifactId> <version>1.0</version> </dependency> </dependencies> </project> ear/pom.xml: <project> <parent> <groupId>com.steeplesoft</groupId> <artifactId>refImpl</artifactId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.steeplesoft.refImpl</groupId> <artifactId>ear</artifactId> <name>ear</name> <version>1.0</version> <packaging>ear</packaging> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>com.steeplesoft.refImpl</groupId> <artifactId>web</artifactId> <version>1.0</version> <scope>runtime</scope> <type>war</type> </dependency> </dependencies> <build> <finalName>myproj</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-ear-plugin</artifactId> <configuration> <modules> <webModule> <groupId>com.steeplesoft.refImpl</groupId> <artifactId>web</artifactId> <contextRoot>myproj</contextRoot> </webModule> </modules> <resourceDir></resourceDir> </configuration> </plugin> </plugins> </build> </project> It should be noted that this is my first real project with Maven. There are likely things done in these POMs that don’t make sense. Feel free to correct me, but please be kind. :) Note that I’m using Hibernate, and not Toplink Essentials, even though I’m deploying to an Oracle application server. I tried to use TLE — I really did — but I just couldn’t get it work reliably. Hibernate did, so it won. Probably the biggest issue was figuring out what Seam and Hibernate need. I started with seam-gen and create a <i>really</i> basic Seam app. I ripped out all of the "extraneous" things, like security, drools, persistence, etc., and deployed the app to GlassFish to make sure it worked. Once I got it working there, I deployed to OC4J, looked to see which class was missing, and added it to the POM. Lather. Rinse. Repeat. The persistence configuration is pretty basic, but I did have to make one change (that I’m not sure I like) to make DB access not blow up: <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="em"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <non-jta-data-source>jdbc/SeamTest</non-jta-data-source> <!-- ... --> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.OC4JTransactionManagerLookup"/> </properties> </persistence-unit> </persistence> There is one extra configuration step you will need if you are planning on using the JSF 1.2 reference implementation (which the Seam developers recommend, and I wholeheartedly do as well ;). Oracle ships its own XML parser — an artifact that, I’m guessing, predates the inclusion of such a library in the JDK. Ordinarily, this likely would not be a problem, except that, starting with 1.2_05, the JSF RI depends on JAXP 1.3; OC4J supports only JAXP 1.2. Since I’m dpeloying to a JDK 5 environment, I don’t need to bundle the library with my app, but I do need to tell OC4J not to use its own parser. This is done with orion-application.xml, which I placed in ear/src/main/application/META-INF: <orion-application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/orion-application-10_0.xsd" deployment-version="10.1.3.1.0" default-data-source="jdbc/OracleDS" component-classification="external" schema-major-version="10" schema-minor-version="0" > <imported-shared-libraries> <remove-inherited name="oracle.toplink"/> <remove-inherited name="oracle.persistence"/> <remove-inherited name="oracle.xml"/> <remove-inherited name="oracle.xml.security"/> </imported-shared-libraries> </orion-application> This file tells OC4J not to import into my application its Toplink, persistence, XML, and XML security libraries. The other three libraries may not need to be listed, but they were added at one point in my experimentation and do not appear to be hurting anything, so I have left them in. Debu Panda shows how to use Hibernate as a pluggable EJB3 JPA provider by configuring Hibernate as a shared library and importing that library into your application via orion-application.xml, but I’m not a real big fan of that approach, as it requires a change to the server, and it has been my experience that administrators are loathe to do things like that. Using the POMs and dependencies above, Hibernate is bundled with the application and works as the JPA provider without server alterations, so that’s a much more palatable approach in my books. Debu’s way <i>does</i> work, though, if you prefer that. If you choose to go that route, make sure you mark the Hibernate library in your POM as being provided: <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.3.1.GA</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.0.GA</version> <scope>provided</scope> </dependency> That should be all there is to it (assuming I did not forget to copy something). If you have any issues with any of this, or, perhaps, some cleanups that can be made, I’d certainly love to hear your feedback. Enjoy! ### [Rich Web Experience, Day 3](/2007/rich-web-experience-day-3/) Rich Web Experience, Day 3 The third and final day of the Rich Web Experience has come and gone. Today’s schedule is a bit lighter, with two morning sessions, a keynote at lunch, and workshops in the afternoon, leaving us finished (and done with the conference : ) just before dinner. To be honest, I was a bit distracted this morning, as the Sooners were busy shellacking Miami. Though I couldn’t watch it on TV, I did have cbsportsline.com open so I could see live stats. Despite the distraction, though, I really enjoyed Nicholas Zakas' talk on "Enterprise JavaScript Error Handling." He started off by telling us that the only difference between enterprise JavaScript error handling and JavaScript error handling is that you can’t give a talk on JavaScript error handling. :) After the bad joke, he showed some pretty novel ways of handling errors, and even getting those errors logged to the same place the server errors are by using an img tag. He is a very eloquent and entertaining speaker, and, for me at least, very effective. Next up, I sat in on Joe Walker’s talk on DWR. Since I’ve used DWR quite a bit, there was a fair amount of review, but Joe’s section on Reverse Ajax was new to me, and really, really cool. Joe’s passion and acumen certainly shone not only in this session, but in his participation on the expert panel. After lunch and a keynote by Eric Miller, it was off to a performance workshop with a couple of people from the Yahoo! Exceptional Performance team. Steve Souders and Tenni Theurer discussed various ways to increase web site performance (including pipelining, using sprites, and locating CSS and JS imports strategically), the YSlow Firebug plugin, and then walked through the rules that YSlow helps a page author enforce. As much as I enjoyed the conference, I’d have to say I’m glad it’s over. The NFJS team crammed so much into this weekend that I don’t think I could have taken much more. Apparently, even though my wife wonders some times, I actually do have a threshold for that kind of thing, and the RWE got dangerously close to finding it. It was a great conference, though, and I highly recommend it. Next year, they’re going to try to do one "on each coast" with the plans being one in San Jose again, and the other, tentatively, in Atlanta. It’s definitely worth the money, and I’m not just saying that because I won an iPhone. :) ### [Rich Web Experience, Day 2](/2007/rich-web-experience-day-2/) Rich Web Experience, Day 2 Day two of RWE turned out to be as good as the first. I started the day with two back-to-back talks on the Google Web Toolkit given by David Geary. Just as entertaining and informative as his JSF talks from yesterday. He describes GWT as (roughly) "the coolest piece of software I have ever seen" and it is pretty cool. I’m still not sold on it, though, largely for the same reason I don’t like some other Java web frameworks: I don’t think Java code is the best way to express a UI; I much prefer a domain specific language for that. Having said that, though, what GWT is offers is cool enough that I might just have to play with it some. The keynote at lunch was given by Jesse James Garrett, discussing "Beyond Ajax." What I took away from it is the call to look beyond Ajax and really think through the problem at hand. Ajax treats a symptom in user interfaces. He encouraged us to look beyond band-aids (my word, not his) like Ajax and really figure out how to solve the user’s problems. He pointed to the iPod as an example: it has fewer features and was more expensive than the competition, but it works the way users want/need it to, so it dominates the market. Really good keynote. I spent the afternoon in a couple of less practical (for me) sessions, JavaFX and the Yahoo! User Interface. I’ve used both, though the latter more than the former, so the talks, it turns out, weren’t of much value to me. I knew that might be the case, but I wanted to see if I might pick up something new on either technology. I didn’t, but that’s OK. They were both pretty good talks, and I enjoyed myself. :) The expert panel after dinner was good, though depressing, spending a great deal of time on how awful web security is, and how almost hopeless the situation is with regard to fixing. It’s not completely without hope, the experts noted, but pretty close. I got to eat dinner with Chris Schalk, formerly of Oracle and now with Google and author of my current favorite JSF book (you should all go out and buy two copies. No, I don’t get a commission, but that’s not for lack of trying :). We got to get caught up on what he’s been doing, and talked a bit about what he’d like to see Google do in terms of its developer community. There should be some interesting things coming out of Google soon. For the record, I asked about the rumored GPhone, and got the "I can neither confirm nor deny" response. Google must train all their people on that. :P Speaking of the GPhone…​ To cap the night off, during the prize raffle section, I didn’t happen to win the 24" iMac, but I got the next best thing there: an 8GB iPhone! The timing works out really well, as I really wanted one, and my other phone happened to have died Tuesday of this week. To use it, I have to switch to AT&T, but I’ve been wanting to ditch my current carrier anyway, so this is a great excuse. ### [Rich Web Experience, Day 1](/2007/rich-web-experience-day-1/) Rich Web Experience, Day 1 Today, I’m attending No Fluff Just Stuff's "The Rich Web Experience" conference in San Jose. Having had a great experience with NFJS’s Greater Oklahoma Software Symposium, I have high expectations for this conference, and, so far, I’ve not been disappointed. After breakfast and an expert panel discussion, I headed off for the sessions. While they were all good today, a couple stand out. The first was the jMaki presentation from Greg Murray and Ludovic Champenois. These two guys (along with others like Arun Gupta and Carla Mott) have put together a REALLY impressive package. Perhaps the coolest thing about jMaki is that it works in languages other than Java, such as PHP and Ruby. Greg and Ludo demonstrated a number of the features of the framework, including have one toolkit’s component (a Dojo tree) control the state of another toolkit’s component (a YUI tabview), all made possible by the normalization of the object model the widgets accept via the jMaki wrappers. Extremely cool stuff and worth your attention. The other session I’d like to mention is David Geary’s presentation "Ajaxian Faces." David is a VERY funny speaker, and his presentation was every much as good as his book, Core JSF. He obviously knows his stuff and conveys it in a clear, informative and very enjoyable manner. If you get a chance to hear him speak, do yourself a favor and take it. Apart from the sessions, at the risk of sounding like a fan-boy, my favorite part was getting to meet some of the Sun folks with whom I’ve interacted over the web over the past couple years, such as the aforementioned Arun Gupta and Carla Mott. I also got to meet Greg Murray and Ludovic Champenois of jMaki fame (among other things). They are all very sharp and very cool people. It was fun to finally get to put a face to the names. To cap off the night, I had coffee with my primary Sun contact, Ryan Lubke, the JSF RI maintainer. It was a fun time chatting about football, JSF and other unrelated things, and drinking caffeinated beverages late in the evening. :P As much as I know you’d like to hear the story, I told him I wouldn’t tell anyone about his sub-optimal navigation skills, so please don’t ask. :) Tomorrow, I have a couple of GWT talks (with David Geary) and a JavaFX session, as well as a key note from Jesse James Garrett, the coiner of the term "Ajax." Should be a good day. ### [JUGs Offer More Than Free Pizza](/2007/jugs-offer-more-than-free-pizza/) JUGs Offer More Than Free Pizza As regular readers likely know, I am currently serving as the president of the Oklahoma City Java Users Group. One of the things we’ve really been focusing on is getting the word out about our JUG, hoping to increase not only attendance, but the size of our speaker pool as well. Since we’ve really started pushing this effort, I’ve done a fair amount of thinking about JUGs in general and have come to reinforce an idea I’ve long held: good JUGs are more than just a once-a-month meeting. They offer several very practical benefits to both Employees and Employers. Employees Employees are, ostensibly, the primary focus of a JUG. As such, the JUG’s value is more clearly and easily seen here. Exposure to new technologies The most obvious purpose of a JUG is to give its members introductions to, or small tutorials on new technologies, methodologies, etc. One of the problems, if one can call it that, with working full time is that, in many cases, it leaves little time for research and experimentation. In the hurry to finish a product, we are often left little choice but to use what we know, so staus quo carries the day. In some situations, we are granted (or simply make) the time to evaluate a new technology, but, oftentimes, tight deadlines or even strict corporate policies make that unworkable. Once or twice a month, though, an employee can sit down in a JUG session and learn about the latest in the field. The value in this is that it costs the employee only a an hour or two of his time, and he gets to reap the benefits of all the time the speaker put in to preparing the talk. This allows a developer to avoid a lot of the initial learning curve of the technology, methodology, etc. and come up to speed quickly on the topic at hand. Armed with this basic knowledge, the developer can go back to work the next day and begin his own experimentation, able to avoid many of the pain points in learning a new tool. While the pressures mentioned above still apply, it’s possible (at least more so than before) that the situation has been ameliorated enough to allow a little time for research. Expansion of professional networks One of the hottest trends on the internet right now is that of social networking. This fad for pre-teens to 20-somethings has made its way into the professional world. Networking sites like http://www.linkedin.com/ exist to fill the desire to connect with fellow professionals, but developers need not look further than their local JUG for this same type of networking. The attendance numbers for the Oklahoma City JUG vary from month to month, as do the actual attendees, but there is a pretty solid core of consistent attendees. That means that each month, a developer has the opportunity to meet, in real life, many fellow developers living in the same city, putting a face and personality to the name that a web site just can’t offer. The JUG also offers the opportunity to talk to people in one’s ever expanding network, trading ideas, techniques, problems, etc. While there is certainly value to sites like LinkedIn, actually being able to look someone in the eye and have a conversation about work is hard to beat. Exposure to potential employers This is perhaps a bit more subtle: developers aren’t the only ones who attend the talks. We regularly see managers as well as recruiters attending our sessions. While there are several reasons they would be attending (managers want/need the exposure to new technologies as well, and recruiters tell us they learn about these new technologies in order to help them recruit more effectively), one of the most important for developers, especially those looking for a job, is that, in attending, those making hiring decisions get an easy and free introduction to the developers in the area. In fact, it was my presentation in the fall of 2006 that caught my current employer’s eye, as I was told up front when we first started talking about the opportunity Objectstream to offer. Had I not become active in the JUG, it’s quite possible that I would have missed that opportunity. Enhance your reputation Closely tied to the last boon, JUG involvement can do wonders for enhancing one’s reputation among peers. Having a reputation as solid coder, developer, analyst, researcher, etc. is extremely important in getting and keeping employment, as witnessed by the referrals for which employers ask. Active participation in the JUG, whether as a vocal attendee or, better yet, presenter gives the opportunity to showcase one’s skill sets. Likewise, and I think more importantly, it allows one to work as part of a team in a public way, offering assistance to those in attendance that may not understand the topic as well. The aforementioned managers and recruiters take great interest in those who can clearly and effectively elucidate a topic, and the JUG provides a great forum for that. Employers Individual employees aren’t the only ones who can gain from JUG attendance and participation. Area employers stand to gain much from a visible presence in the local JUG. Free (or at least cheap) exposure for one’s company One of the things that I like to do after each month’s meetings is to look at the sign in sheets to see who all came, and for whom they work. I am constantly surprised by that list. Hardly a month goes by that I don’t learn of yet another Java shop in town. The big shops are generally easy to spot, but, for the smaller or newer shops, it’s often a bit more difficult to become known in the community, which makes finding job candidates more difficult. If they don’t know about your shop, how do they know if you’re hiring? By becoming involved in the local JUG, an employer has a very inexpensive marketing vehicle. Handled properly (technical types are often adverse to heavy-handed sales pitches), it’s a win-win for an employer. Find potential employees The exposure of employees to employers mentioned above works both ways: by attending the JUG, an employer gets the chance to test drive, so to speak, an employee: How solid is the candidate, technically? How clearly can he/she communicate what he knows? Is he/she comfortable speaking to large groups? Is he/she willing to help others? How patient is he/she with those less skilled? And so on. A more relaxed environment like the JUG can be (and often is, in my experience) a much better forum for evaluating a potential candidate, and it can be had for free (or really cheaply if one chooses to be a JUG sponsor). Facilitate a more knowledgeable community The primary goal of the JUG, I would think, is the first point above: exposing local developers to new technologies, etc. While this is primarily focused on the developer, an employer has much to gain from this as well. Via the JUG, current employees, as we’ve discussed, get the opportunity for self-improvement, which can only help their employers. As one in leadership positions, I’ve always been encouraged to see fellow developers take the initiative to expand their sphere of knowledge. It’s gratifying to watch developers becoming increasingly confident and self-sufficient through such endeavors, and such growth can only make them better developers. The employer also stands to gain by having a better informed/educated community when it comes to hiring. In addition to getting to learn about a potential candidate, an employer, actively sponsoring and participating in the JUG, can help develop potential candidates for very little cost, so, when a position opens up, the area candidates will be better prepared to fill that position. In the final analysis, there’s little down side to a users group. Assuming one can sacrifice a little time for it, there’s much to gain, from the social aspects to professional development, and even personal gratification for those that really like public speaking, a users group offers a unique opportunity. Are you taking full advantage of your local JUG. If not, why? ### [Thank you, Sun](/2007/thank-you-sun/) Thank you, Sun I’m a bit hesitant to post this as I’m afraid that it may come across as self-congratulatory, which is not my intent at all, but I think Sun deserves an "atta-boy." Recently, Sun sought to reward various contributors who they felt have been a boon to GlassFish. On two different occasions, I have been blessed to be recipient of Sun’s largess. At JavaOne 2007, which I was unable to attend, I was selected as one of the (first?) GlassFish Champions, and awarded an engraved iPod Nano (which I’m enjoying now :). Most recently, I was selected as the winner of GlassFish’s Fish for a TV competition. I’m extremely flattered by both honors, and I can’t thank Sun enough for wanting to reward its community members (and me in particular). I think it speaks volumes about Sun’s seriousness about Open Source. At any rate, I don’t want to dwell too much on me on this blog, but I felt that Sun deserved the press. By the way, here’s a picture of the TV, which we are enjoying immensely. :) ### [Another RI Sandbox Progress Report](/2007/another-ri-sandbox-progress-report/) Another RI Sandbox Progress Report With some help from Ryan Lubke, a number of issues have been fixed in the RI Sandbox, including: * "Standard" Attribute Support * Update various CSS files * Make the tabs default to something prettier and several minor fixes here and there. Having done that, I’ve bumped the version (which I have been awful at maintain thus the jump from 0.1 to the seemingly arbitrary 0.7) to 0.8, leaving us with this road map. 0.9 Custom icons in the TreeView (587) Slider component (590) 1.0 Fix HtmlEditor 404s (594) Possible DataTable component (591) Post 1.0 Lazy loading the tree (588) Animations (585) MyFaces support (564 - I may just make these all 1.2-only since MyFaces 1.2 finally appears to be close) If you have any comments, questions, suggestions, etc., please let me know here or in the issue https://javaserverfaces.dev.java.net/issues/enter_bug.cgi?issue_type: DEFECT&subcomponent=sandbox[tracker]. ### [Comparing the GlassFish and OC4J Admin Consoles](/2007/comparing-the-glassfish-and-oc4j-admin-consoles/) Comparing the GlassFish and OC4J Admin Consoles As I’ve noted previously, a recent job change has required that I become familiar with Oracle’s application server, Oracle Containers for Java, or OC4J. I recently set aside time to set up my OC4J environment to test a prototype I have been working on and have running under GlassFish. After getting the server installed and logging on to the administration console, I was struck by how nice it was. I’ve long held that one of the many strengths GlassFish has over its open source competition is a vastly superior administration console. Presented now with a commercial application server with the might of a company like Oracle behind it, how well does GlassFish stand up1? In this entry, I’d like to take a look at that question. Since a Java EE container is a complicated piece of software, an exhaustive comparison of any two such containers is an overwhelming task. In the interest of brevity, we’ll take a look at just a couple of areas2, and wrap things up with some general observations. When I first log on to each of the consoles, it’s apparent that the two were designed with different emphases. In OC4J’s console, the front page seems to have chosen server health to highlight, showing some general information (including status, server start time, and version) and a chart of response and load (showing both request processing time in seconds and requests per second). The navigation for OC4J is achieved via a horizontal navigation bar that is shown above and below that page’s main content. The GlassFish console, on the other hand, seems to have chosen ease of use, presenting the user with shortcuts to commonly performed functions, including deployment, monitoring, "other tasks" and support/help. Navigation is handled by a frame on the left presenting the user with a tree view of tasks. Application deployment in the two containers is affected by the navigation choices. In OC4J, the administrator clicks on the Applications link in the horizontal menu and is presented with a table listing the deployed resources (applications, modules, and standalone resource adapters). Deploying an application is done by clicking on the deploy button, and following the wizard. Archive selection: Application attributes entry: Deployment settings: Results: For GlassFish, the administrator has a host of choices in the navigation tree: Enterprise Applications, Web Applications, EJB Modules, etc. Unlike OC4J, though, there does not appear to be a way to see all the deployed modules regardless of type. One has to click on each type on the left to see items of that type. Selecting one presents the user with a screen like this: Deployment in GlassFish is a bit simpler, as all steps are on one page, and there is no concept of a deployment plan (for better or for worse): On this screen, the administrator selects the deployment type, selects the archive, sets the application name and context root, etc., then clicks deploy and the job is done. Once deployed, monitoring the application becomes quite important. Here the differences in the two application servers are pretty marked. As I’ve already noted, the OC4J administrator gets some basic metrics up front, whereas the GlassFish administrator has to dig a little bit to find similar information. The OC4J console also has, I think a slight edge in its first page under Performance: OC4J also offers a couple of interesting reports that I have yet to find under GlassFish (which doesn’t mean they don’t exist, of course, but, if they’re there, they’re certainly not as easy to find): Top Servlets and Top JSPs: While these are two pretty interesting reports, from what I can tell, that’s all there is unless one uses a JMX console. GlassFish, on the other hand, gives the administrator almost too much information it can seem. The Runtime tab under Monitoring gives the administrator a detailed looked at several areas of the runtime environment, including JVM (up time and heap size), class loading system (total loaded class count, unloaded class count, and loaded class count), memory (initial non-heap size, max non-heap size, initial heap size, max heap size, etc), and many more. Like OC4J’s Top Servlet report, OC4J may offer this information, but it was non-obvious to me where to find it in the interface. With GlassFish, it’s all out in the open. The Applications tab lets the administrator select an application and a component and get detailed information: The resources tab is a bit of a mixed bag. While OC4J has the upper hand in clarity and conciseness, GlassFish wins in terms of completeness. With connection pool metrics like max connections allowed, number allocated, high water mark, etc., GlassFish gives the administrator a wealth of information about what is happening on his server. My only complaint, which I’ve shared with the administration console team, is the page needs a more concise summary of what’s going on. Something like OC4J’s summary would be great. Other than that, this is a great resource that has helped me more than once track down leaked connections. Both application servers allow the administrator to see a list of the currently running transactions: OC4J goes a step further though, giving a nice performance overview of historical JTA information: In general, I feel more comfortable with the GlassFish administration console, though that’s probably due, at least in part, to my higher degree of familiarity. Having said that, though, the OC4J console is really quite nice and has some features that the GlassFish administration console team would be wise to take a look at it. As I’ve noted, it’s quite possible that the "deficiencies" I’ve found in the GlassFish console aren’t really deficiencies at all, at least not in the way I thought they were. It’s quite possible I just don’t know where to look (the same goes for OC4J, for that matter). If that’s the case though, the console team might consider making those items easier to find. One thing that OC4J does that I wish GlassFish would do is really pretty simple, but it sure is nice: server restarts. GlassFish allows an administrator to stop the server instance, but he must then restart it via the host operating system: batch file, shell script, Serivce Control Manager, etc. OC4J’s console has a restart button — click that, wait just a few moments, then log back in. Nice and simple, and you never have to leave your browser. In the end, though, I’m quite happy with the GlassFish console. I’ve been using it for over a year now, and it has only gotten better and faster. While I realize there are many, many more factors to consider in picking an application server, ease of administration is a pretty important one (at least for me), and I think GlassFish does extremely well against all competitors, even one from the world’s largest software company. 1 I am aware that Sun is very active and generous in its support of GlassFish, but it still seems to carry the stigma that open source sometimes does in certain circles. 2 The current production release of OC4J is 10.1.3.2, with a preview release for 11g available. The preview, however does not currently ship with a GUI administration console, so this comparison will be using 10g. ### [RI Sandbox Update: A Blogging Hat Trick](/2007/ri-sandbox-update-a-blogging-hat-trick/) RI Sandbox Update: A Blogging Hat Trick For my record setting, third blog in a single day, I thought I’d make a quick update on the state of the RI Sandbox components. Just a couple of days ago, a former coworker started asking questions about my download component, which made me realize that I should probably find some time to do some work on them. As a general rule, they’re all fairly usable, with some gotchas here and there, as Brent was discovering. Given my desire to see a 1.0 release, it’s time to address those issues. I recently added a more generic Pretty URL PhaseListener, based on an approach I discussed last year. As I added that, I made a mental note that that would be the last thing I added to the library before 1.0. There are still some YUI widgets I’d like to see supported, but, in the interest of putting (an admittedly somewhat arbitrary) bow on things, I’m going to try to hold myself to that. What I need to do then, is take a hard look at what’s left on the components and make a list of to do items, thing such as complete support for the "standard" JSF attributes, and perhaps less purple in the default styles. :) I also need to make sure that I’m comfortable with the balance I’ve tried to strike between usability and flexibility. The YUI widgets offer a myriad of options, and the examples show numerous ways of using the widgets, but trying to offer all of those in one neat package via these components is probably not the best approach. So there you have it. It’s a bit of a vague long term plan, but, in the short term, I’ve bumped up the version to 0.7, which I hope to increment more frequently as I feel it’s appropriate, and plan to tackle Brent’s download issue. If you have questions or issues, please comment here, email me, or file an issue on the https://javaserverfaces.dev.java.net/issues/enter_bug.cgi?issue_type: DEFECT&subcomponent=sandbox[tracker]. ### [A Quick Administrative Note](/2007/a-quick-administrative-note/) A Quick Administrative Note I recently made a change that I should probably note here: In mid-May, I left my employer of the past 2+ years, IEC, to join Objectstream as a Software Architect, and for whom I will be working at the FAA’s Mike Monroney Aernoautical Center here in Oklahoma City. While I’m very excited about this opportunity (and have enjoyed the past few weeks), it was not an easy decision to leave IEC, as it’s a really great place to work. IEC (and my boss, Mitch, in particular) gave me a degree of freedom in terms of technology that I’ve not had anywhere else. I was able to try a lot of bleeding edge technologies and do some really neat stuff with some really sharp people. Much of what you may have read here came from my experiences at IEC. With Objectstream, I will have the opportunity to architect and build very large, complex systems, well beyond the scope and size of most of what I’ve done thus far in my career, so it will be a good growth vehicle for me. A side effect of this change is that the types of things I’ll blog about will change a bit, as the FAA is an Oracle and RUP shop. While I won’t be leaving the JSF and GlassFish worlds, one can certainly expect my new environs to show up here. Though it was not an easy decision, as Peter Brady once sang, "when it’s time to change, don’t fight the tide." :) ### [JSFTemplating: Announcing beta support for Facelets templates](/2007/jsftemplating-announcing-beta-support-for-facelets-templates/) JSFTemplating: Announcing beta support for Facelets templates The JSFTemplating team is proud to announce that a new, Facelets-compatible format has been added to JSFTemplating and has reached the beta stage. Not all of the Facelets components are currently supported; those that are currently supported are ui:component, ui:decorate, ui:include, ui:define, and ui:remove, with the addition of a new ui:event, which brings the power of JSFTemplating’s events to this new Facelets format. In addition other JSFTemplating features are also available to Facelets pages, such as "pageSession" (i.e. #\{pageSession.variable}) and ability to reference relative information like $this{componentId}. Please remember that this is beta software, but should be stable enough to support the basic Facelets functionality (note that we do not yet have support for Facelets tag handlers, etc). Should you find a bug in this new format, please file an issue against it on the issue https://jsftemplating.dev.java.net/issues/enter_bug.cgi?issue_type: DEFECT&subcomponent=Facelets+Format[tracker]. If you would like to see a demo of the functionality, we have deployed an application that shows the exact same templates as processed by Facelets itself as well as JSFTemplating, thus showing how well the implementations match up. As the implementation matures, this application will be updated to show the current state. If you have questions or comments, please join the discussion on the dev mailing list. You might also be able to catch one of the developers on irc.freenode.net in #jsftemplating. ### [Virtual Hosting using Apache and GlassFish](/2007/virtual-hosting-using-apache-and-glassfish/) Virtual Hosting using Apache and GlassFish While many have found GlassFish to be a great choice for an internal application server, there are others that would like to push it a bit further, and use it in an ASP/ISP envrionment. Jan Luehe discussed GlassFish’s virtual hosting features in a recent blog entry. What I’d like to do in this entry is take the information that Jan presented, and walk through setting up a few different virtual hosting environments. Terms to Know Before we go too far, we need to make sure we’re all using various terms in the same manner. To summarize Shreedhar Ganapathy’s excellent discussion, a domain in GlassFish terms is an "administrative area." It should not be confused with DNS domains. A domain will have one or more servers defined. These servers correlate, roughly, with a ServerName in Apache’s httpd.conf (and, like a ServerName can have `ServerAlias`es, a server can be given aliases). For the sake of this discussion, we will not give any attention to clustering or load balancing. Before a vhost environment can be set up, one must ask: Do the vhosts need to be completely separated from each other? That is to say, will the production environment need to be configured in such a way that an administrator for one group of servers can not touch another group of servers? If you intended to have one administrator admin all servers, you can probably get by with one domain. However, if you need to allow a user to administer his servers without having access to another user’s servers, then you will need to create additional domains. We’ll start with the simple case, and look at multiple servers in one domain. One Domain, Multiple Servers We’ll start by configuring GlassFish. We’ll use two vhosts, vh1 and vh2. To add a virtual server from the admin console, go to Configuration→HTTP Service→Virtual Servers: Click add, and fill out the form: I’ve chosen to use http-listener-1 only, as I only care about http://vh1:8080/ being available. Repeat the process for server vh2. For those that prefer the command line, the server can be created with this command: asadmin create-virtual-server --user admin --hosts vh1 --httplisteners http-listener-1 vh1 asadmin create-virtual-server --user admin --hosts vh2 --httplisteners http-listener-1 vh2 While there are a myriad of options regarding port usage, I like to have Apache handle requests on port 80, and forward requests for my vhosts to the appropriate server behind it, so let’s take a look at that configuration: <VirtualHost *:80> ServerName vh1 ProxyPass / http://vh1:8080/ ProxyPassReverse / http://vh1:8080/ </VirtualHost> <VirtualHost *:80> ServerName vh2 ProxyPass / http://vh2:8080/ ProxyPassReverse / http://vh2:8080/ </VirtualHost> With that, your virtual hosts should be ready. To test that things are working correctly, let’s deploy two applications (which, I’m afraid, you’ll have to supply :) ). Command line users can do: asadmin deploy --virtualservers vh1 AppA.ear asadmin deploy --virtualservers vh2 AppB.ear With these apps deployed, http://vh1/AppA should get your app, while http://vh2/AppA should get a 404, and vice versa. If you deploy a third app and do not specify a virtual server: asadmin deploy AppC.ear then http://vh1/AppC and http://vh2/AppC will both work. Here are some rules to keep in mind: If, when deploying an application, a virtual server is not specified, then the app is available to all servers in that domain. If an application is deployed to one or more specific virtual servers, then it will not be available to any virtual servers not in that list. Likewise, if an application is deployed to one or more specific virtual servers, then it will not be available to be used as the <strong>Default Web Module</strong> for any virtual servers not in that list. Multiple Domains, Multiple Servers If you need to segregate administrative control amongst users, such as in an ASP/ISP environment, then you will need multiple domains. When you setup the server, the default domain, domain1, is created for you. Since a domain is an administrative area, one can not use the admin console to create another domain, and must use the asadmin command line tool. A session might look something like this: $ asadmin create-domain --portbase 5000 --profile developer mydomain Please enter the admin user name>admin Please enter the admin password> Please enter the admin password again> Please enter the master password [Enter to accept the default]:> Please enter the master password again [Enter to accept the default]:> Using port 5048 for Admin. Using port 5080 for HTTP Instance. Using port 5076 for JMS. Using port 5037 for IIOP. Using port 5081 for HTTP_SSL. Using port 5038 for IIOP_SSL. Using port 5039 for IIOP_MUTUALAUTH. Using port 5086 for JMX_ADMIN. Domain being created with profile:developer, as specified on command line or environment. Security Store used should be: JKS Domain mydomain created. The documentation has this to say about domains: A domain, in addition to being an administrative boundary, is also a fully compliant Java EE Server. This means that you can can deploy your Java EE Applications to the domain and run them when the domain is started. A domain provides all the necessary environment and services that are essential to run the applications. That being so, each domain will have its own set of ports. Note the use of the portbase option above. That instructs asadmin to start allocating ports starting at 5000 according to this pattern: * Admin port: portbase + 48, HTTP * Listener port: portbase ` + 80 * IIOP listener port: `portbase + 37 * JMX port: portbase + 86 We specified the developer profile, as we do not need clustering, high availability, etc., for our purposes here, but please note that option if you do indeed need those capabilities. With our domain created and start (asadmin start-domain mydomain), we can now begin creating virtual servers and deploying applications in the same manner we did above. Note that, for those using Apache as the front end, the virtual host configuration will need to be adjusted accordingly: <VirtualHost *:80> ServerName vh3 ProxyPass / http://vh3:5080/ ProxyPassReverse / http://vh3:5080/ </VirtualHost> <VirtualHost *:80> ServerName vh4 ProxyPass / http://vh4:5080/ ProxyPassReverse / http://vh4:5080/ </VirtualHost> and that your admin console is listening at http://localhost:5048/. Conclusion That should get you going! There are some details that have been glossed over (such as memory usage), but you should now have in your hands a step-by-step guide on creating, configuring, and maintaining virtual servers using GlassFish. If you have any questions, comments, corrections, etc., please feel free to leave a comment. ### [TinyMCE Support in the Sandbox](/2007/tinymce-support-in-the-sandbox/) TinyMCE Support in the Sandbox I have just committed preliminary support for the TinyMCE JavaScript HTML editor. There are parts that still don’t work correctly, but it’s a good start. This example markup: <h3>Normal editor</h3> <risb:htmlEditor rows="10" cols="85" value="#\{testBean.editorValue}"/> <h3>Simplified editor</h3> <risb:htmlEditor rows="10" cols="85" value="#\{testBean.editorValue}" themeStyle="simplified"/> <h3>Full editor</h3> <risb:htmlEditor rows="10" cols="85" value="#\{testBean.editorValue}" themeStyle="full"/> gets you this: Hopefully, I’ll get full support for the editor, but I can’t make promises on how quickly that will happen, this being mostly a lunchtime project. If you’d like to influence the direction this component goes, now’s the time to speak up! :) ### [JSFTemplating Meets Facelets](/2007/jsftemplating-meets-facelets/) JSFTemplating Meets Facelets I could be wrong, but I think it’s safe to say that most people don’t know about JSFTemplating, which is a pity, as it’s a pretty nice alternate ViewHandler implementation from Ken Paulsen, GlassFish admin console architect. One of the coolest features, I think, is its introduction of templating events (e.g., one can attach a beforeEncode event to a component on a page and have a handler method fire before that component is encoded). The first comment I hear, though, is usually something about template syntax, and it does seem a bit foreign with things like <!if $attribute{in} & ! (#{in} = abc) > and <span class="code">#include /header.inc</span>. That’s where I come in. Ken and I got to talking about the project, and, given my experience with Facelets and my involvement with the JSF RI (not to mention my apparent inability to say no :), he asked me if I would be interested in writing a Facelets-compatible format for JSFTemplating, which is another really cool feature of the library: the "formats" are pluggable. That is to say, when you write a web page in a given format, the format handler (technically, a LayoutDefinitionManager) translates the page into a LayoutElement tree, which the core of JSFTemplating then processes to create the UIComponent tree that JSF needs to see. The technical challenge intrigued me, so I agreed to take it on, giving me another lunch time project. :P The short-term goals of the effort are to create a format that is functionally equivalent to the templating in Facelets. That is to say, we intend to duplicate the functionality of the ui:* "components" in Facelets, while adding support for the event model that JSFTemplating provides. Once that’s done, I’d like to take a look at some of the more advanced features exposed via the taglib.xml, but we’re taking Dr. Leo Marvin’s advice and taking baby steps. :) For those interested in tracking the progress, the source code is available in the JSFTemplating CVS tree, which you’ll be able to see once java.net finishes its massive upgrades. ;) ### [Unit Testing EJBs](/2007/unit-testing-ejbs/) Unit Testing EJBs As we’ve done more and more EJB development, we’ve had to think pretty hard about how to unit test our beans. We’ve tried a couple of different approaches (including not testing, which I don’t recommend ;), but weren’t ever just real comfortable with the results. I’m pretty happy with the method we’re using now, and it’s so simple, I’m a bit embarrassed that we didn’t think of it earlier. One of our earliest attempts used JBoss' embeddable container, which we eventually discarded for a couple of reasons. It was really heavy in terms of configuration and startup time, and, as hard as I’m sure the JBoss team is working on AS 5 in terms of EE 5 compliance, the embeddable container is still using an old version of the spec, which meant we had to change the way we handled resource look ups, which we didn’t like. We’ve also tried using mock objects, but, for the most part, we found that to be overkill. What we ended up with is pretty light and simple. To make things work, we had to change the way we setup our EJBs. Since the beginning our EE 5 development, we’ve been using field injection: @EJB(mappedName="ejb/MyEjb") private MyEjbInterface myEjb; which we have changed to using property injection: private MyEjbInterface myEjb; @EJB(mappedName="ejb/MyEjb") public void setMyEjb(MyEjb myEjb) { this.myEjb = myEjb; } Our general approach has been to avoid making changes to production code for the purpose of testing, but, after talking things over with a friend from our local JUG, I felt the change was not only appropriate, but a good general philosophy change. What Rod explained to me is that, by using property injection, we make our beans reusable across integration technologies. If, for example, we ever wanted to use this class with Guice or Spring, we’d be out of luck using field injection, as they don’t support that. They do, though, support property injection, so using that makes sense in terms of portability. With that change made, our unit tests became a lot easier to write. Our applications are all multi-tiered, with JSF handling the view, and service and DAO layers that are either Faces-managed or container-managed and Session Beans, depending on the need for remote access. For the purposes of our discussion here, we’ll start with the data layer. Let’s say we have this simple DAO: @Stateful public class UserDaoImpl implements UserDao { private EntityManager entityManager; @PersistenceContext(unitName="myapp") public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } public User addUser(String userName, String emailAddress) { User user = new User(userName, emailAddress); entityManager.persist(user); return user; } } This is a very simple DAO, and there is a lot intentionally left out, but it demonstrates a simple DAO using JPA. So how do we test that? How do we create the EntityManager, for example? Here’s how the unit test might look using JUnit 4 and DBUnit: public class UserDaoImplTest { private static UserDaoImpl dao = new UserDaoImpl(); private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("myapp-test"); private static EntityManager entityManager; @BeforeClass public static void classSetup() { try { entityManager = (EntityManager) emf.createEntityManager(); DbUnitHelper.initDatabase(entityManager, "doc/sql/myapp.sql"); dao.setEntityManager(entityManager); } catch (Exception e) { throw new RuntimeException (e); } } @AfterClass public static void classTearDown() { try { DbUnitHelper.closeConnection(); } catch (SQLException e) { e.printStackTrace(); } } @Before public void setUp() throws DatabaseUnitException, SQLException, Exception { DbUnitHelper.loadData("/dataset.xml"); } @Test public void addUser() { DbUnitHelper.startTransaction(entityManager); User user = dao.addUser("Jim Halpert", "jim@dundermiffflin.com"); Assert.assertNotNull(user); DbUnitHelper.rollbackTransaction(entityManager); } } The unit test starts by declaring some static resources: the DAO implementation, an EntityManagerFactory, and an EntityManager. In the @BeforeClass, we ask the EMF for the EntityManager, then pass that to a DBUnit helper class, then set the EM on the DAO (you should see now where the property injection comes in handy). The @Before method simply loads our test data before each test. One could just as easily have each unit test rollback at the end, but we chose to reload our small test dataset before each run. The unit test itself is fairly straightforward, except that we are explicitly handling transactions to mimic the container-managed transaction handling we get for free in production. The persistence context is defined like this: <?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="myapp-test" transaction-type: "RESOURCE_LOCAL"> <class>com.steeplesoft.myapp.model.beans.User</class> <exclude-unlisted-classes/> <properties> <property name="toplink.jdbc.driver" value="org.postgresql.Driver"/> <property name="toplink.jdbc.url" value="jdbc:postgresql://localhost/myapp"/> <property name="toplink.jdbc.user" value="myapp"/> <property name="toplink.jdbc.password" value="myapp"/> <property name="toplink.logging.level" value="FINE"/> </properties> </persistence-unit> </persistence> Here is the code for the DBUnitHelper class. Note that this is still experimental, but I’ve used it on three projects now with good success, but it does abuse the JPA API by talking to the TopLink objects directly, so it is definitely not portable. You have been warned. :) Testing our service is fairly similar, needing just a bit more setup: public class MyAppServiceImplTest { private static MyAppServiceImpl service = new MyAppServiceImpl(); private static UserDaoImpl dao = new UserDaoImpl(); private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("myapp-test"); private static EntityManager entityManager; @BeforeClass public static void classSetup() { try { entityManager = (EntityManager) emf.createEntityManager(); DbUnitHelper.initDatabase(entityManager, "doc/sql/myapp.sql"); dao.setEntityManager(entityManager); service.setUserDao(dao); } catch (Exception e) { throw new RuntimeException (e); } } @AfterClass public static void classTearDown() { try { DbUnitHelper.closeConnection(); } catch (SQLException e) { e.printStackTrace(); } } @Before public void setUp() throws DatabaseUnitException, SQLException, Exception { DbUnitHelper.loadData("/dataset.xml"); } @Test public void addUser() { DbUnitHelper.startTransaction(entityManager); User user = service.addUser("Jim Halpert", "jim@dundermiffflin.com"); Assert.assertNotNull(user); DbUnitHelper.rollbackTransaction(entityManager); } } This test is very similar to the DAO test, including transaction management, but we call the service instead of the DAO. I also chose to create a "real" instance of the DAO as opposed to mocking one up, since the resource was local to the project. That makes the test more of an integration test in some ways, but we’re OK with that. For external resources, we’re tempted to use mock objects, but another sharp OKC JUG regular, Dave Nicolette, suggests that that might be overkill. Anything we might inject we will have an interface for, so he suggests just writing a stubbed implementation of the interface and injecting that, making our "stub" behave the way our test expects, which would allow us to focus on testing the client and not the "remote" object. That’s an interesting approach. I have not been able to test that yet, but I certainly will when the need arises. That about sums it up. All that’s left to test is the JSF layer, for which we don’t have a solution with which I’m all that comfortable. Once we nail something down, I’ll be sure to write it up here. :) So, how is everyone else testing EJBs? Comments, suggestions, corrections, etc. are, of course, welcome! ### [GlassFish Success Stories](/2007/glassfish-success-stories/) GlassFish Success Stories Jamey Wood and Shreedhar Ganapathy of GlassFish fame asked me some time ago if I would be interested in filling out a questionnaire describing my company's use of GlassFish. I finally got the questionnaire completed and turned back in, allowing Jamey and Shreedhar to finish up the article, which is now posted here. We’ve been using GlassFish in production since, if I recall correctly, March of last year, well before Java EE 5 went "final." We’ve been very happy with it, so this piece was a nice way of giving back to a community of developers and users that have helped us a lot over the past year. ### [Site Outage](/2007/site-outage/) Site Outage Some of you may have noticed an extended outage of this site for most of last week. It appears that my provider was having NFS issues which, to my knowledge, are ongoing. They told me they were watching my server hoping it would stabilize, all the while all I wanted was a functional site. I finally got them to move me to another server, and things appear to be back to normal. So, dear reader, I apologize for any inconvenience that might have caused either of you. :) Believe me, no one was more irritated than I. :) ### [Using the Woodstock Sortable Table](/2007/using-the-woodstock-sortable-table/) Using the Woodstock Sortable Table At long last, the Woodstock component set is finally here. At IEC, we have been anxiously awaiting its release for quite some time now, as we’ve been hoping to make use of the sortable data table component it offers, which we have now done. Having done it, allow me to show off the component a bit, as well as explain what I had to do make things work. It’s not hard, necessarily, just different enough to give one pause at first glance. Table of Contents Setting up your environment The Table Displaying Data Sorting Data Filtering Data What It Looks Like Closing Setting up your environment The first thing you will need to do, obviously, is add the required jars to your project: dataprovider.jar dojo-0.4.1-ajax.jar jsf-extensions-common-0.1.jar jsf-extensions-dynamic-faces-0.1.jar json.jar prototype-1.5.0.jar webui-jsf-suntheme.jar webui-jsf.jar To make things look pretty (and who doesn’t), you will also need to configure the Woodstock theme servlet: <servlet> <servlet-name>ThemeServlet</servlet-name> <servlet-class>com.sun.webui.theme.ThemeServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>ThemeServlet</servlet-name> <url-pattern>/theme/*</url-pattern> </servlet-mapping> With that done, you will need to declare the Woodstock namespace on your page: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:risb="http://java.sun.com/jsf/ri/sandbox" xmlns:w="http://www.sun.com/webui/webuijsf"> Of course, XML being what it is, xmlns:w="http://www.sun.com/webui/webuijsf" will have to be repeated on each page that uses a Woodstock component. I should also note that, while I was using "webuijsf" as the Woodstock examples suggested, I have started using "w" as it’s much smaller (and have updated this entry to reflect that). Having done that, you will now need to change your Facelets template/template client (or JSP header include, etc), changing <head> to <w:head>. This is necessary, as this is how the various JavaScript and CSS files required by Woodstock are included. <w:head> <w:link url="/style.css"/> </w:head> Alternately, you can use the themeLinks component: <head> <w:themeLinks /> </head> The Table We’re now ready to put a table on the page. Here’s a snippet from the application in which I’ve implemented the table: <w:table id="table" clearSortButton="true" sortPanelToggleButton="true" title: "Pending Units" filterText="#\{ewl.group.filter.filterText}" " deselectMultipleButton="true" selectMultipleButton="false"> <f:facet name="actionsTop"> <f:subview id="actionsTop"> <h:selectOneMenu id="selectedEngineer" value="#\{ewl.selectedEngineer}"> <risb:selectItems value="#\{ewl.engineers}" itemValue="#\{item.name}" itemLabel="#\{item.name}" /> </h:selectOneMenu> <w:button id="assignEngineerAction" text="Assign Engineer" action="#\{ewl.assignEngineer}" /> <w:image icon="TABLE_ACTIONS_SEPARATOR" /> <w:button text="Refresh" action="#\{ewl.refresh}" /> </f:subview> </f:facet> <f:facet name="filter"> <w:dropDown submitForm="true" id="filter" action="#\{ewl.group.filter.applyBasicFilter}" items="#\{ewl.group.filter.filterOptions}" onChange="if (filterMenuChanged(this) == false) return false" selected="#\{ewl.group.filter.basicFilter}" /> </f:facet> <f:facet name="filterPanel"> <f:subview id="filterPanel"> <h:inputHidden id="customFilter" value="#\{ewl.group.filter.customFilter}" /> <w:markup tag="div"> Show only units for the engineer: <h:selectOneMenu id="engineerFilter"> <risb:selectItems value="#\{ewl.engineers}" itemValue="#\{item.name}" itemLabel="#\{item.name}" /> </h:selectOneMenu> <w:button action="#\{ewl.group.filter.applyCustomFilter}" onClick="applyCustomFilter('engineerFilter');" mini="true" text="OK"> <f:setPropertyActionListener value="assignedTo" target="#\{ewl.group.filter.customFilterField}" /> </w:button> </w:markup> <!-- snip! --> </f:subview> </f:facet> <w:tableRowGroup id="pendingRowGroup" sourceData="#\{ewl.group.provider}" sourceVar="unit" selected="#\{ewl.group.select.selectedState}" binding="#\{ewl.group.tableRowGroup}"> <w:tableColumn align="center" selectId="selectReferenceId"> <w:checkbox id="selectReferenceId" selected="#\{ewl.group.select.selected}" selectedValue="#\{ewl.group.select.selectedValue}" onClick="setTimeout('clicked()', 0);" /> </w:tableColumn> <w:tableColumn alignKey="assignedTo" headerText="Assigned To" sort="assignedTo"> <w:staticText text="#\{unit.value.assignedTo}" /> </w:tableColumn> <!-- snip! --> </w:tableRowGroup> </w:table> At first glance, that’s quite overwhelming, and I’ll be the first to admit that I don’t understand everything that’s going on there, but I’ll try convey what I do understand. :) For good or bad, this sample does both sorting and filtering. The properties on <w:table> should be fairly self-explanatory. The actionsTop facet allows me to insert arbitrary markup into the area by that name in the table header. In this example, it is through this area that I’m able to perform various actions against the selected rows in the table: assign an engineer or refresh the table (i.e., clear any filters and reload the data the database). Displaying Data Finally, we come to the heart of the table, the tableRowGroup. This is the point at which I had to smile and nod, and just do what I was told. The TLD docs have this to say of this component: The tableRowGroup component is used to define attributes for XHTML elements, which are used to display rows of data. You can specify multiple w:tableRowGroup tags to create groups of rows. Each group is visually separate from the other groups, but all rows of the table can be sorted and filtered at once, within their respective groups. Note that we bind this component to a property on the managed bean. This is where things get really…​interesting. If you were to look at the example source code or the TLD docs for the table, you would find a number of helper classes, such as Group, Filter, and Select. If you are like me, your first inclination is to skip using these classes, hoping to simplify things a bit. Don’t. In fact, I took these classes and tweaked them a bit to make them more generally usable and bundled them in a utility library that we can use. If you’d like to use these classes, the complete source can be downloaded here. You can browse the source to see what all Group does, but one of its most important functions is to create the TableDataProvider the component will need. The easiest way I have found, which you will see in the class, is to wrap a List of my model objects in an ObjectListDataProvider: public Group(String sourceVar, Object[] array) { this(sourceVar); provider = new ObjectArrayDataProvider(array); } // Construct an instance using given List. public Group(String sourceVar, List list) { this(sourceVar); provider = new ObjectListDataProvider(list); } Now that we’ve bound the data to the tableRowGroup, we need to display the data on the page. In the example above, I have two columns: one has a checkbox for selecting a row, and the other shows the assigned engineer. Again, this is somewhat of a black box for me, but as best as I can make out, the "select" column has a selection ID that will be used by the table’s JavaScript to manage selected rows. Note the the value of the `selectId matches the id of the checkbox component. The checkbox itself has few properties to note. The first is the selected and selectedValue attributes, which are bound to methods on the Select object (owned by the Group object) that determine whether or not a given row has been selected. The third property is the onClick (note the case) property. The JavaScript referenced here is used to update the table to reflect the selected of the row associated with the checkbox (From the TLD Docs: "The JavaScript setTimeout function is used to ensure checkboxes are selected immediately, instead of waiting for the JavaScript function to complete."): var tableId = "pendingUnits:table"; function clicked () { document.getElementById(tableId).initAllRows(); } Sorting Data The next column in the table is a sortable column. While most of the markup here is straightforward, note the alignKey and sort properties. These columns indicate the field on which to sort when the user selects that column. I am uncertain as to whether or not they have to be the same, but I’ve always seen them that way, so that’s the pattern I’ve followed. It is also probably important to point out how data is retrieved from the DataProvider. In the staticText component, you’ll see the value is set to #\{unit.value.assignedTo}. The variable unit is the sourceVar defined in the table setup, and value is a method on the DataProvider that returns (in our case) the object for the given row. Filtering Data Filtering is also enabled on our table. The filter facet is where I am able to specify the filters I’d like to be able to apply to the table. Due to a JavaScript issue I have yet to track down (which may or may not be related to my nascent Facelets support), my implementation here is a bit different from the Woodstock examples. Here is the source for filterMenuChanged: function filterMenuChanged(cb) { if (cb.value == "_customFilter") { var ret = document.getElementById(tableId).filterMenuChanged(); return ret; } else if (cb.value == "FILTER_SHOW_ALL") { window.location.href=window.location.href; } } It basically checks for the special option element Woodstock adds to determine if a custom filter is being requested (which causes the filter panel to be displayed), or if the "show all" option was selected, which will clear the filter. Note that this JavaScript is not optimal and has changed a fair amount as my understanding of the component has grown, and will likely do so again. Ideally, I’ll solve the JavaScript error that prompted this so that this can go away. The next item of interest is the filterPanel facet, which is display when the user selects the "Custom Filter" option. The markup here pretty simple, in that all I have are a number of custom filters (though I’ve shown only one) that are nothing more than a label, an appropriate UIInput component, and a button. The only thing really noteworthy is the JavaScript used to apply the filter. Via EL, we’re taking the value entered or selected by the user, and setting that on a property on the Filter class (which I added to the Sun-provided class to make things more reusable). Since every field on the form will get set on the managed bean referenced via its EL, we can’t have them all pointing at the same property. To solve this problem, I use some simple JavaScript to copy the value in which I’m interested to a hidden field, which is the only one assigned to the desired property. I also use a <f:setPropertyActionListener> to set which field should be filtered: <w:button action="#\{ewl.group.filter.applyCustomFilter}" mini="true" text="OK" onClick="applyCustomFilter('timePending');"> <f:setPropertyActionListener value="timePendingClass" target="#\{ewl.group.filter.customFilterField}"/> </w:button> The source for applyCustomFilter is function applyCustomFilter(source) { document.getElementById('pendingUnits:table:filterPanel:customFilter').value = document.getElementById('pendingUnits:table:filterPanel:' + source).value; } When the form submits, the appropriate properties on the Filter object are set, and the filters are applied to the DataProvider: public void applyCustomFilter() { basicFilter = Table.CUSTOM_FILTER_APPLIED; // Set filter menu option. filterText = "Custom - " + customFilter; // Filter rows that do not match custom filter. CompareFilterCriteria criteria = new CompareFilterCriteria( group.getProvider().getFieldKey(customFilterField), customFilter); // Note: TableRowGroup ensures pagination is reset per UI guidelines. group.getTableRowGroup().setFilterCriteria(new FilterCriteria[] \{criteria}); } What It Looks Like Here is a screen shot from the application from which this table was taken. It shows the rows sorted by the "Assigned To" field, a row is selected, and the custom filter panel is displayed: Closing And that’s "all" there is to it. I’ve worked with (and on) a fair number of JSF components, but this is likely the coolest with which I’ve had personal experience. The "coolness" comes at a cost, though, in that the component can be difficult to grasp at first. Hopefully, this "little" will flatten the learning curve just a little bit. And while you’re playing with the table, be sure to check out some of the other Woodstock components. They did a great job. As a side note, many thanks to Ken Paulsen (of JSFTemplating and GlassFish admin console fame) for answering all of my questions, regardless of how silly they seemed. My employer, IEC (namely, my boss Mitch, and not just because he reads this ;) ) deserves many thanks as well for giving me the time to add Facelets support, without which we couldn’t be using Woodstock. ### [Sandbox Demo and Nightlies Available](/2007/sandbox-demo-and-nightlies-available/) Sandbox Demo and Nightlies Available Thanks to the generosity of Ryan Lubke, Ed Burns and the javaserver.org folks, the Sandbox demo application, which can be found in the Sandbox source tree, is now available online. There are a couple of known issues with it, but it should give you a good sense of the current state of the components. We also have nightly snapshots of the sandbox source, binaries and demo available on the RI website. If you find any issues, please file an issue on the <a href="https://javaserverfaces.dev.java.net/issues/enter_bug.cgi?subcomponent=sandbox&version=current">tracker</a>. ### [JSF RI Sandbox FileDownload Component Changes](/2007/jsf-ri-sandbox-filedownload-component-changes/) JSF RI Sandbox FileDownload Component Changes Today I checked in a couple of changes to the RI Sandbox file download component that will make the component more flexible, and, therefore, more usable. Before these changes, the only way the component could be used was with one of two "methods:" "inline" (e.g., a PDF embedded in the page), or "download" (which was a link with a text anchor). While this worked, it was pretty limiting. What if the page author wants the link to be a picture, or if he wants the file download to start from on onChange even handler? Before today, that wasn’t possible. Today, though, I committed support for child components, as well as support for creating an EL variable that can be used by any child components as they please. With the first change, something like is now possible: <risb:download method="download" mimeType="application/pdf" fileName="HelloWorld.pdf" data="#\{testBean.pdf}"> <h:graphicImage alt="Download" url="/download.jpg"/> </risb:download> which will render an anchor, using the the download.jpg image as its content, that will deliver the HelloWorld PDF to the client when clicked. (In theory, anything can be used inside <risb:download />, though I’ve only tested with text and images.) But what if you want a dynamically generated image to be displayed? With the second change, this is now possible: <risb:download mimeType="image/jpg" fileName="image.jpg" data="#\{testBean.image}"> <h:graphicImage url="#\{downloadUrl}" width="250px" /> </risb:download> This simple example will render an image on the page, pulling the contents of the image from TestBean.getImage, and should the user try to save the image, the filename defaults to "image.jpg." If you don’t like the variable name downloadUrl or if it would clobber one already set, you can specify the name of the variable with the urlVar attribute: <risb:download mimeType="image/jpg" fileName="image.jpg" urlVar="foo" data="#\{testBean.image}"> <h:graphicImage url="#\{foo}" width="250px" /> </risb:download> Fancy. At IEC, we’re pretty excited about these changes. We’re using both the download and multi-file upload components in a couple of different high profile projects, which means that they’re stable enough for production, and they also get a good deal of real world scrutiny, resulting in changes like these above. These changes can be picked up from the RI CVS HEAD branch. Thoughts? Complaints? Suggestions? ### [Merry Christmas!](/2006/merry-christmas/) Merry Christmas! My general rule is that I avoid too much personal stuff here. I have other venues for those interested in that kind of thing, but it would be remiss of me if I did not take the time to wish a merry Christmas to those that read this blog. I truly hope your Christmas season was (and continues to be) a happy one, spent with family and friends. More importantly than that, though, I sincerely hope each of you will take a good, honest look at the historical reason for Christmas. Beyond the gifts and meals and parties, Christmas celebrates the birth of a Child, Jesus of Nazareth, the Savior of the world. My hope and prayer is that you will find, if you have not already, the Light of Christ, as I did so many years ago. Thanks for indulging me this personal note, and here’s hoping for a great and exciting 2007! ### [Why CakePHP?](/2006/why-cakephp/) Why CakePHP? A reader recently asked me why I chose CakePHP over other frameworks, such as Prado, so I thought I’d answer that question briefly. What drew me to CakePHP was the "simplicity." I say that cautiously, as there is a bit of a curve, but there’s very little configuration (i.e., no xml). At the time, all the config files in Prado kinda scared me off. I liked how CakePHP automatically picked up my controllers, models, etc based on the file/class names and locations. I liked the ActiveRecord approach to the models. In fact, it was the ORM part of CakePHP that really sold me, as I was looking for a good Hibernate-esque tool for PHP. When I stumbled across CakePHP, I found that and a really good MVC framework, so I bit. At any rate, as time passed, I began looking at Prado again, as I read somewhere a description that made it sound as if Prado were fairly similar to JSF in terms of development (page templates, application lifecycles, etc), and I decided that I deal with a bit of XML on the Java side, so why not on the PHP side. I started writing a small budget app for my wife and I (why we don’t just download one I can’t really say : ) in Prado and was enjoying, but the documentation was pretty poor (still is) for the latest/beta version. That’s what I get for using a beta, but it had features the stable version didn’t, and I was trying to avoid having to relearn the framework. I was also unable to get much help on the mailing lists, so, in the end, it was taking too long so I started over in CakePHP, with which I’m very comfortable, and got it done in no time. I like Prado and would like to play with it some more as time permits, but the docs are going to have to get better. The API docs were great, but the "here’s how you actually use this stuff" type of documentation was not very helpful at all. :| ### [Yahoo! UI and JSF Update](/2006/yahoo-ui-and-jsf-update/) Yahoo! UI and JSF Update I’ve had several people ask for an update on where things stand with my YUI components and their JSF component wrappers, so I figure I should take the time to answer that question. In terms of the state of the components, I currently have (admittedly basic) support for three components: Calendar, Menu and TreeView. Of the three, the Calendar seems to be the most "complete" in terms of how I intend to use it, i.e., as a pop-up, one-up calendar. I’d like to add support for two-ups, as well as an always-showing form. I have not had the need to use it in such ways, so those have remained on the to do list, but they’re certainly there. The Menu component seems to work fairly well, but it has some issues with submenus and mouseovers. If you try to mouse over to the submenu, it disappears as soon as the mouse leaves the parent menu’s area. I have not yet had a chance to track that down. The TreeView component, which just became functional about an hour ago, is fairly basic, but, again, "working." :) On the Java side, I have defined a TreeNode class, and extended that to make TextNode, MenuNode, and HtmlNode, to match the corresponding Javascript classes. One only needs to create a TreeNode object and add any children to it, then set that on the JSF component tag via the (currently) model attribute. It’s pretty basic, but, given its age, I’ve not had a chance to press it hard and see where it needs improvement. The big question has been, "Where can I get it?" Until recently, I didn’t have a good answer for that, but that is no longer the case. I’ve made the decision to move these components, as well as my upload and download components into the Sandbox recently opened in the source tree for the JSF reference implementation. Once the components have had a chance to bake a bit and get some more exposure and critique, they will be moved to a component library in the RI we’re tentatively calling LionFish, in keeping with the theme started with the GlassFish project. Currently, the only component available in the tree (which you can get by checking out the RI source code) is the TreeView wrapper, YuiTree. I will begin migrating the rest of the source over during the Christmas holidays. That’s about it. If you have any other questions, feel free to email me, or, preferably, comment here. I’ll post again when all the source is available. ### [Download and Multi-file Upload JSF Components](/2006/download-and-multi-file-upload-jsf-components/) Download and Multi-file Upload JSF Components At work, we have run into two issues several times: 1) We haves app that create PDFs, and we need our JSF apps to send that to the user, and 2) we need to be able to upload multiple files to one of our JSF apps. The solutions we’ve used have been less than exciting. For the first problem, we’d make the backing bean that coordinates the PDF creation (calling the service layer, basically) session-scoped, then have a hidden iframe on the result page whose source is a JSP that pulls the bean out the session (via Java code!) and sends the PDF to the browser in such a way that forces the user to save the file. For the upload issue, we’ve been using JUpload, which works fine, but, since it lives outside the JSF lifecycle, we have to do some interesting things to make it work. Luckily, my boss gave me time to create better solutions, resulting in the components <fl:download/> and <fl:multiFileUpload/>. File Downloads This component is really rather simple. Currently, it has these options: data mimeType fileName method text iframe height width A few of these attributes need a little explanation: The data attribute is an EL expression that resolves to the content of the file to be downloaded. This data can be returned as a byte[], InputStream, or a ByteArrayOutputStream. The mime type needs to be specified as there is no easy way of determining the correct type short of guessing based on the file extension, adding a third party dependency, or writing a bunch of painful code myself. None of those are very appealing. The method is how the file is to be rendered: 'inline' (i.e., embedded in the page), or 'download' (i.e., force a Save As dialog). text is the text of the link tag for the download method. iframe is a boolean determining whether to use an iframe when embedding the file. Usage is pretty simple: <fl:download method="download" mimeType="application/pdf" data="#\{testBean.pdf}" fileName="test.pdf" text="Get PDF"/> <fl:download method="inline" mimeType="application/pdf" data="#\{testBean.pdf}" width="500px" height="250px" /> which renders to this: Multi-file Uploads The second component is a bit trickier. Since HTML won’t allow more than one file selected per file input element, another method must be employed. Following JUpload’s lead, I implemented this part of the component in an applet. The applet allows the user to select a number of files and, when he’s ready, to submit them all in one batch. This component is a bit more complex, so we’ll spend more time on it, and we’ll start with the component parameters: type - The manner in which to render the applet: 'full' or 'button' (see below for details) fileHolder - The object into which uploaded files will be placed destinationUrl - The URL to which to navigate after an upload (see below) fileFilter - A string listing the extensions to allow, as well as a filter description (i.e., "Image Files|jpg,png,gif") maxFileSize - The maximum size per file in bytes startDir - The directory in which to start looking for files buttonText - The text on the button if type is set to 'button' height - The height of the rendered applet width - The width of the rendered applet Some of those attributes needs some explaining: The fileHolder is an object that implements the com.iecokc.faces.components.upload.multifile.FileHolder interface defined by the component. This class will be fetched by the component via the ValueExpression given in the tag. As each file is uploaded, FileHolder.addFile() is called, storing the file, in effect, in the backing bean (as it has a reference to the same object). The component provides an implementation of this interface, FileHolderImpl, which simply takes the InputStream for the file, and stores it in a Map, indexed by filename. It is possible to write an implementation of the interface that reads each file in and writes it to a database, JCR repository, etc., depending on your application’s needs. Once all of the files have been processed, the component retrieves the destinationUrl, which, if a ValueExpression is used, gives the backing bean the chance to analyze the set of uploaded files and pick an appropriate destination URL based on application-specific needs. UNC paths are acceptable. Care must be taken when using the startDir attribute, as file systems paths are far from portable. For in-house applications, such as the one for which this component was developed, one can probably safely use this parameter. In the extension part of the fileFilter string, only the extensions are need: no masks, periods, etc.</ul> Here are a couple of sample usages. Full Mode: <fl:multiFileUpload maxFileSize="10240" fileHolder="#\{testBean.fileHolder}" destinationUrl="#\{testBean.destination}" width="750px" height="250px" type: "full" fileFilter="Images|jpg,png,gif"/> which renders like this: Button Mode: <fl:multiFileUpload maxFileSize="10240" fileHolder="#\{testBean.fileHolder}" destinationUrl="#\{testBean.destination}" width="175px" height="25px" type: "button" buttonText="Custom Text!"/> which renders like this: What’s Next? These components are extremely young (I "finished" the download component Monday and the upload component today), so the APIs and implementation need some more scrutiny by someone other than the guy who wrote them. That means, of course, that things may change, but I hope it won’t be anything major. Personally, they seem to solve effectively the problem which spawned them, so I see nothing that needs changing, but others likely will, so we’ll have to wait and see how all of that shakes out. Enough already? Where can I get them? That’s a very good question. As I noted, these were components developed for my company, but my boss has graciously given me permission to release them (in fact, he approached me about it). That leaves the question then, of exactly where/to whom to release them. I am currently in the middle of discussions on where these and my YUI components will live. They’ll either be rolled in to the newly opened JSF RI sandbox, or added to Ed Burns' JSF-extensions project, and I’m having trouble deciding. I’ll make a post here when a decision has been reached. ### [Using Acegi Security With JSF](/2006/using-acegi-security-with-jsf/) Using Acegi Security With JSF A question that often comes up in when looking through JSF <a target="blank" href="http://forum.java.sun.com/forum.jspa?forumID=427&start=0">forums</a> or idling on IRC is, "How do I secure my JSF app?" to which, of course, there are a myriad of options. At <a target="blank" href="http://www.iec-okc.com">IEC</a>, we use <a target="blank" href="http://www.acegisecurity.org/">Acegi Security</a>. That answers only part of the "how," though, as Acegi is not the easiest thing to learn. In this blog entry, I’ll detail how we have Acegi implemented at IEC. While it’s not perfect, it works well for us, and should be enough to get someone moving in the right direction. The first step, of course, is to download Acegi, and integrate with the web application. Once the jars have been installed in WEB-INF/lib, web.xml needs to be edited: <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext-acegi.xml,</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> org.acegisecurity.ui.session.HttpSessionEventPublisher </listener-class> </listener> <filter> <filter-name>Acegi Filter Chain Proxy</filter-name> <filter-class> org.acegisecurity.util.FilterToBeanProxy </filter-class> <init-param> <param-name>targetClass</param-name> <param-value> org.acegisecurity.util.FilterChainProxy </param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi Filter Chain Proxy</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> </filter-mapping> That’s the easy part. The Acegi configuration, applicationContext-acegi.xml in this example, is where the difficulty comes in: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <!-- ******************************************************************* --> <!-- Acegi Security Config --> <!-- ******************************************************************* --> <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,contextHolderAwareRequestFilter,anonymousProcessingFilter,switchUserProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor </value> </property> </bean> <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <property name="providers"> <list> <ref bean="daoAuthenticationProvider" /> <ref local="anonymousAuthenticationProvider" /> <ref local="rememberMeAuthenticationProvider"/> </list> </property> </bean> <bean id="daoAuthenticationProvider" class="class="org.acegisecurity.providers.dao.DaoAuthenticationProvider""> <property name="userDetailsService"> <ref local="memoryAuthenticationDao" /> </property> </bean> <bean id="memoryAuthenticationDao" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"> <property name="userMap"> <value> user1=ROLE_FOO, ROLE_ADMIN </value> </property> </bean> <bean id="loggerListener" class="org.acegisecurity.event.authentication.LoggerListener" /> <bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"> <property name="authenticationManager"><ref local="authenticationManager"/></property> <property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property> </bean> <bean id="basicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"> <property name="realmName"><value>Contacts Realm</value></property> </bean> <bean id="anonymousProcessingFilter" class="org.acegisecurity.providers.anonymous.AnonymousProcessingFilter"> <property name="key"> <value>foobar</value> </property> <property name="userAttribute"> <value>anonymousUser,ROLE_ANONYMOUS</value> </property> </bean> <bean id="anonymousAuthenticationProvider" class="org.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider"> <property name="key"><value>foobar</value></property> </bean> <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter"> </bean> <bean id="contextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" /> <bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"> <property name="authenticationManager"><ref local="authenticationManager"/></property> <property name="rememberMeServices"><ref local="rememberMeServices"/></property> </bean> <bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"> <property name="userDetailsService"><ref local="memoryAuthenticationDao"/></property> <property name="key"><value>springRocks</value></property> </bean> <bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"> <property name="key"><value>springRocks</value></property> </bean> <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property> </bean> <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> <property name="authenticationManager"><ref bean="authenticationManager" /></property> <property name="defaultTargetUrl"><value>/index.jsf</value></property> <property name="alwaysUseDefaultTargetUrl"><value>false</value></property> <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property> <property name="authenticationFailureUrl"><value>/login.jsp?login_error=1</value></property> <property name="rememberMeServices"><ref local="rememberMeServices"/></property> </bean> <bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <property name="loginFormUrl"><value>/login.jsp</value></property> <property name="forceHttps"><value>false</value></property> </bean> <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"> <property name="allowIfAllAbstainDecisions"><value>false</value></property> <property name="decisionVoters"> <list> <ref bean="roleVoter" /> </list> </property> </bean> <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> <property name="authenticationManager"> <ref bean="authenticationManager" /> </property> <property name="accessDecisionManager"> <ref local="httpRequestAccessDecisionManager" /> </property> <property name="objectDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /foo*=ROLE_FOO </value> </property> </bean> <bean id="switchUserProcessingFilter" class="org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter"> <property name="userDetailsService" ref="memoryAuthenticationDao" /> <property name="switchUserUrl"><value>/j_acegi_switch_user</value></property> <property name="exitUserUrl"><value>/j_acegi_exit_user</value></property> <property name="targetUrl"><value>/</value></property> </bean> <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter" /> </beans> I’m not Acegi expert, and I make no claims to understand what all is going on here, but I have included the whole config file as I found it difficult (at the time, at least) to find a complete example that uses the Acegi 1.x package and class names. I must also note that I’ve done my best to back out IEC-specific changes, so there may still remain same changes that need to be made to get this to work in a "clean" environment (read as: this should work, but it may not. If you have to make changes, please let me know and I’ll fix my example). Once Acegi is setup and configured, we can start protecting resources. The configuration above protects all URIs that start with /foo, but it is also sometimes desirable to protect only certain parts of a page. Acegi ships with some JSP tags that make that possible, but these work outside the JSF lifecycle. To solve that problem, Cagatay Civici has written some JSF tags that do live inside that cycle. Here’s an example from an app we have in poroduction. In this particular snippet, if the user has the correct permissions, we allow him to approve a request or resubmit the order: <acegijsf:authorize ifAllGranted="ROLE_OrderManager] <h:form id="requestForm" rendered="#\{dwmoForm.isRequest == true}" style="display: inline"> <input type: "button" value="Approve Request" onclick="return approveRequest();" /> </h:form> <h:commandButton id="resubmitButton" type: "button" value="Resubmit Order" onclick="return resubmitOrder();" style="display: inline; margin: 0px; padding: 0px;"/> </acegijsf:authorize> And that’s all there is to it. Once you get it setup, it’s really not too difficult to work with. I have seen some balk at using Acegi, given its dependence on Spring, but, while it’s true that you must have Spring in your classpath for Acegi to work, by no means does that require that the application itself be Spring-based. In fact, we’re using this very approach in an application that uses no Spring at all, but, rather, some EJB3 session beans (and Ajax on the front end). So, if you can live with the extra few jars to solve the dependencies of Acegi, it plays well JSF, even in a non-Spring app. What are your thoughts? Do you see ways to improve this approach, or do you have a better one altogether? I’d love to hear your feedback. ### [Review: Building Ajax JSF Components](/2006/review-building-ajax-jsf-components/) Review: Building Ajax JSF Components If you’re doing web development, you have likely at least heard of Ajax, and, if you’re not currently using it, you’ve likely investigated its possible use. One of the tricky aspects of working with a technology like Ajax is integrating it with various frameworks. JavaServer Faces, now a standard part of the Java EE stack, is no different. For both a page and component author, the integration issue can be a big question. Luckily for those of us in the JSF world, that question has been addressed by Chris Schalk and Ed Burns, in their new book JavaServer Faces: The Complete Reference. While the book is a comprehensive look at the entirety of the JSF framework, one particular chapter, Building AJAX JSF Components, should be of interest to anyone working with Ajax, especially component authors. The chapter begins by making the grandiose claim that "JSF and AJAX are a perfect match." The authors then attempt to back up their claim by showing how JSF’s lifecycle phase management helps implement components that use AJAX very cleanly, especially from the component users' perspective. After a brief introduction to how AJAX works, the authors implement an employee directory search page using hand-written AJAX code and a servlet (no JSF involved at all). This component, in a fashion similar to the myriad of autocomplete components available, allows the user to type in the name of the desired employee and see, as he types, a list of possible matches appear in a table below the text field: Complete code for this component is shown, demonstrating what many of us already know: there’s much to be done on the both client and server sides to make AJAX work. It also highlights well one of the downsides of Ajax: there’s a fair amount of work a page developer must do to set up the Ajax environment. Taking that example, the authors then reimplement the same component as a JSF component. For those new to JSF or unfamiliar with writing JSF components, some of the inner workings of the component can seem a bit overwhelming, but the advantage for those that would like to consume this component is hard to miss. The requirement for reuse goes from copying several JavaScript files into one’s project, adding the script includes, and writing all the (X)HTML markup to display the component to adding one JAR to the project and adding two lines to the markup: the tag library declaration, and this line: <jcr:directorySearch /> And, if that one example were not enough, Schalk and company go on to implement a spell check text area component for JSF. This component "extends HtmlInputTextArea and provides a simple Ajax-enabled spell-checking facility," which can be used with a single line of code like this: <jcr:spellCheckTextArea cols="30" rows="15" value="#\{user.interests}" /> which results in something like this: That’s all there is to it. For component authors, this should be extremely exciting, as it very handily encapsulates all the desired functionality in an easy to deploy and use package, instantly making the component more attractive to end users. That, I think, is the crux of the authors' assertion that JSF and Ajax are a perfect match. There’s nothing magic about JSF that makes Ajax components easier to write, but the encapsulation provided by a JSF component offers a perfect way for component authors to deliver their components. In a nutshell, this chapter highlights the strengths of both Ajax and JSF in a very clear and easy to follow manner. If you’re not using either technology, a quick read through the chapter should really get you excited about the future of both of these great technologies. ### [Two 'Quick' Notes](/2006/two-quick-notes/) Two 'Quick' Notes I thought I’d take a second to make two quick fairly self-congratulatory announcements: Last Friday, I took and passed the Sun Certified Java Programmer exam. To be honest, going in, I was extremely nervous and wondering if it was worth it, as the practice exams title: "A book for which I give a qualified and hesitant recommendation" were extremely difficult and tended to focus on little, annoying gotchas like missing `import`s. The test itself wasn’t that bad. Either the practice exams were designed to over prepare you for the real thing, or I got a lucky set of questions, as the real thing wasn’t as scary. That’s about all I can say about the test, given the confidentiality agreement I had to sign. In fact, I may have already said too much, so I’ll move on. :) I plan to move next to the Sun Certified Java Developer test at some point, probably late this year or early next. An Ajax presentation at my local JUG and my second son due in November will likely keep me busy for a while, though." The second "quick" note is that I was given today commit access to the reference implementation of JavaServer Faces. I’ve been working with the development team (Ryan Lubke in particular) for quite some time now doing things like fixing bugs, expanding i18n support, and helping implement a few features. After proving I understand the system they use and that I’m not likely to delete the whole source tree, Ryan gave me access to commit directly instead of through him. I’m pretty excited about it. Given my blog’s almost solitary focus on JSF-related issues, my interest in the framework should be somewhat self-evident. It will be exciting to be able to help the continued development of what I feel is one of the best Java web frameworks on the market. That’s it. If you were hoping for something useful and insightful from this post, I apologize. I’ll try to post something substantive in the next few days. :) ### [A Disappointing Wait](/2006/a-disappointing-wait/) A Disappointing Wait Several months ago at work, we evaluated a handful of methods for dependency downloads. We looked at extending our home grown solution, ivy, maven ant tasks, and even the unthinkable: migrating to maven2. In the end, we decided to stay with our home grown solution, as we were led to believe that the next version of ant would have transitive dependency management built in. We concluded that it would be a waste of time to migrate to one solution, just to do it again when the new ant came out, so we waited, and, oh, how disappointed we were. On August 27, 2006, Ant 1.7 beta 1 (not the 2.0 I had hoped to see) was announced. Here is the text of the announcement on the web site: Ant 1.7 introduces a resource framework. Some of the core ant tasks such as <copy/> are now able to process not only file system resources but also zip entries, tar entries, paths, …​ Resource collections group resources, and can be further combined with operators such as union and intersection. This can be extended by custom resources and custom tasks using resources. Ant 1.7 starts outsourcing of optional tasks to Antlibs. The .NET antlib in preparation will replace the .NET optional tasks which ship in Ant. Support for the version control system Subversion will be only provided as an antlib to be released shortly. Ant 1.7 fixes also a large number of bugs. Ant 1.7 has no support for Java6 features, but first tests on Java6 did not fail. That’s all they could think of to highlight on the front page, and the WHATSNEW document doesn’t show much more. It looks like bug fixes, random tweaks, and 4 new tasks. That’s a long wait for so little improvement. August 27, 2006 may very well mark the day that ant gave up the fight against a surging maven2. ### [JSF, PhaseListeners, and GET Requests Redux](/2006/jsf-phaselisteners-and-get-requests-redux/) JSF, PhaseListeners, and GET Requests Redux In an earlier post, I detailed how my company got around JSF’s dependence on POST requests in our efforts to implement pretty URLs. While this approach has worked well for us for quite some time, a pretty major flaw in the approach revealed itself to us in the past few days. In the application for which this PhaseListener was written, we display order information for our customer service group. A recent feature request was the ability to approve an order from this application, which is basically the assignation of an order number. The most user-friendly way to do this, we thought, would be an in-place edit. For the user, it would be quick and easy, and look really cool, so we altered the page to use the excellent Ajax4jsf library for the in-place edit and data submission. We hit a pretty big snag, though: the Ajax request was failing. In fact, the method on the managed bean wasn’t being called at all. To make sure it wasn’t a4j-related, I added a plain <h:commandButton/> to see if I could get the method to fire, but, again, it failed to run. To make a long story short, it turns out that if I hit the page directly ("/index.jsf" in my test case), everything worked as expected. If I hit the page via a pretty URL ("/prettyurl/"), it would fail. After talking to Ryan Lubke, the JSF maintainer at Sun (a million thanks, by the way), he pointed me to section 2.2.1 of the JSF spec: The JSF implementation must perform the following tasks during the Restore View phase of the request processing lifecycle: * Examine the FacesContext instance for the current request. If it already contains a UIViewRoot: Set the locale on this UIViewRoot to the value returned by the getRequestLocale() method on the ExternalContext for this request. For each component in the component tree, determine if a ValueBinding for "binding" is present. If so, call the setValue() method on this ValueBinding, passing the component instance on which it was found. ** Take no further action during this phase. He added, "So your [pretty URL PhaseListener] adds your custom ViewRoot to the Context. We get to the actual part of RestoreViewPhase and see it’s already there, so we exit the phase and continue processing." That’s no good. His suggested fix is to extend HttpServletRequestWrapper, override getPathInfo(), and set that on the ServletContext. That may sound scary, but it’s actually not too bad. First, let’s look at the HttpServletRequestWrapper: class PrettyUrlRequestWrapper extends HttpServletRequestWrapper { private String template; @Override public String getPathInfo() { return "/" + template; } public PrettyUrlRequestWrapper(HttpServletRequest reg) { super(reg); } public void setTemplateName(String template) { this.template = template; } } I added this as a private class in the same source file as the PrettyUrlPhaseListener. I then altered the PL to do, for example: PrettyUrlRequestWrapper wrapper = new PrettyUrlRequestWrapper(request); wrapper.setTemplateName("/product-view-" + tab + suffix); context.getExternalContext().setRequest(wrapper); instead of UIViewRoot view = context.getApplication().getViewHandler() .createView(context,"/product-view-" + tab + suffix); context.setViewRoot(view); where suffix is context.getExternalContext(). getInitParameter ("javax.faces.DEFAULT_SUFFIX"); and tab is an application-specific parameter (the "tab" to display in the view). The end result of all of this is that I can hit the URI /Gopher/product/FXY02/details and the PhaseListener (using logic in the other post and not displayed here) sets the state on the backing bean and "tricks" JSF into displaying "product-view-details.xhtml" and allows <h:commandButton /> to function as expected. To clarify the problem, Ryan also noted (via IRC, so please forgive the odd syntax), "First request to prettyURL → RestoreViewPhase (UIViewRoot already exists) → RenderResponse. Click the button to initiate a post-back. The [pretty URL PhaseListener] detects the URL, and creates a new view which means the view won’t be restored properly from the initial request. So, you can go the wrapper approach (which I think is good as the URL is normallized during the processing) or you could try determining of the request is a postback and if it is, not creating the view." Since I have the wrapper approach, I think I’ll stick with that. I think it’s much cleaner than the old way anyway. ### [Debugging jsf-extensions](/2006/debugging-jsf-extensions/) Debugging jsf-extensions One of the things that has been frustrating with trying to come up to speed with jsf-extensions is that I just didn’t know where to look in all the Javascript involved to see what was going on. Today, I "watched" as Ed Burns walked a fellow extensions learner through debugging his app. Here’s what I learned. Assuming you’re using it (and if you’re not, you should be), open up Firebug and click on the "Debugger" tab. In the "Scripts" drop down at the bottom, select the script ending in com_sun_faces_ajax.js. Here are some useful lines in this script1: Line 440: By inspecting the variable xml, you can see the response from the server. Line 453: You can see the id of each component that is to be rendered. Line 454: You can see, in the "content" variable on the right, the actual content that will be rendered. There are obviously countless more interesting lines, but these are the only ones Ed discussed specifically, and should be enough to show those interested in such things where to start looking. Hope that helps. While I’m on the subject, my boss was able to get jsf-extensions working in his project, so we’ll now be able to get a better feel for both jsf-extensions and Ajax4jsf. 1 In the interests of full disclosure and fairness to Ed, the descriptions of the lines you see are mostly direct quotes of him, with minor changes to make it more readable in this context. :) ### [Ajaxifiying JSF](/2006/ajaxifiying-jsf/) Ajaxifiying JSF In October, I will be presenting Ajax at the <a target="_newwindow" href="http://wiki.okcjug.org">Oklahoma City Java Users Group</a>, of which I am a member (and vice president now, by the way, for what that’s worth). As I’ve prepared for that talk, I’ve thought quite a bit about the web apps I write, which are, for the most part, pretty boring. I like to think that they’re functional, but I have to admit that they’re pretty plain. Ajax, though, along with the Javascript pretties that usually accompany an Ajaxified application, is a good way of fixing that "problem", assuming it’s done properly. That line of thinking has affected how I’ve approached a new app I started at work, but finding a library that works well with JSF (read as, in a JSF-friendly manner) has been a bit of a challenge. My goal with this part of the app is role and group management for users. The behavior I was hoping to achieve was to allow the web user to select a system user from a list box (<h:selectOneListbox/>), and have four other list boxes (<h:selectManyListbox/>) populated with the assigned roles, avaialble roles, assigned groups, and available groups for the selected user. Pretty simple, in theory. My first effort used Direct Web Remoting (DWR), and it worked pretty well. The documentation was a bit difficult for me to follow (which could be more my fault than the docs), but, with a little persistence, I got it working. It was not pretty, though. Here’s what my view markup looked like: <h:selectOneListbox id="users" size="20" style="width: 175px" onclick="getUserRoles(this);"> <f:selectItems value="#\{authBean.users}" /> </h:selectOneListbox> with the accompanying Javascript looking like this: function getUserRoles(elem) { var id = elem.options[elem.selectedIndex].value; AuthBean.getDwrUserRolesMap(populateRoles, id); } The ugly part was the JSF code. One of the main complaints I heard about DWR and JSF going into this effort is that DWR lives outside the JSF lifecycle, and that showed itself in how I handled the server side. I’ll not show the code as it’s not that interesting, but I basically created four Map`s (they translate quite nicely to Javascript associative arrays), populate them with the appropriate data, and return them all in a `List. Here is what the populateRoles() function looked like which updated the UI with the returned data: function populateRoles(data) { DWRUtil.removeAllOptions("authForm:user_roles"); DWRUtil.removeAllOptions("authForm:user_groups"); DWRUtil.removeAllOptions("authForm:remaining_roles"); DWRUtil.removeAllOptions("authForm:remaining_groups"); DWRUtil.addOptions("authForm:user_roles", data[0]); DWRUtil.addOptions("authForm:remaining_roles", data[1]); DWRUtil.addOptions("authForm:user_groups", data[2]); DWRUtil.addOptions("authForm:remaining_groups", data[3]); } A little ugly, but it worked. I was pretty happy with the overall result, but not real happy with the means, so I decided to look for a more JSFy way to go about it. Having been privy to discussions by Ed Burns about his jsf-extensions project, I decided to give it a go. Unfortunately, it was not a pleasant experience. Based on the documentation, I think should be able to do this: <h:selectOneListbox id="users" size="20" style="width: 175px" onclick="new Faces.Event(this, { render: 'authForm:user_roles,authForm:remaining_roles,authForm:user_groups,authForm:remaining_groups' }); return false;"value="#\{authBean.currentUser}"> <f:selectItems value="#\{authBean.users}" /> </h:selectOneListbox> Despite several variations, including the use of ajaxZones as suggested on the mailing list, I was unable to get to much of anything to work. I know that it can work; I’ve seen the car store demo, which is pretty cool. I was not, however, able to replicate that success in my project. I could get it to make the call to the server, but it never updated the UI. Very frustrating. Needing to get something working so that I can actually code my app, I decided to try <a target="newwindow" href="https://ajax4jsf.dev.java.net">Ajax4jsf</a> and had _much better success. The change for Ajax4jsf was pretty simple. Here’s that very same select box: <h:selectOneListbox id="users" size="20" style="width: 175px" value="#\{authBean.currentUser}"> <a4j:support event="onclick" reRender="user_roles,remaining_roles,user_groups,remaining_groups"/> <f:selectItems value="#\{authBean.users}" /> </h:selectOneListbox> I also apparently had to wrap the area in a <a4j:region selfRendered="true"> tag to make things work (though I may test that a bit more when I get a chance). After making the requisite web app changes, I redeployed and tested the application. When I clicked the user list, the action on the backend was indeed fired, but I ended up getting nothing but a blank page in my browser at the end of the request. After a quick email to the mailing list and a very helpful link from Adam Brod, I found my problem: a JSF newbie mistake. I had forgotten to wrap my form in <h:form> tags. Once I made that change, it worked like a charm. That, of course, could be the reason jsf-extensions didn’t work for me — something I plan to test, if for nothing else, peace of mind. I have A4J working, though, so I’m not sure I see the value in switching to jsf-extensions (beyond the personalities — Ed Burns, Jacob Hookom, etc — behind it and the stated goal of the project which is to be a playground of sorts for possible JSF 2.0 features). If I can get it working, I’ll sit down with the rest of the guys in my office, and we’ll make a decision. For now, though, I have a working solution, and I can continue implementing the application and getting some real work done. :) ### [The Tyranny of Choice](/2006/the-tyranny-of-choice/) The Tyranny of Choice As I’ve mentioned before, my company is trying to decide if we really need to keep using Spring now that we’re in a "full" JEE environment. As I’ve pondered this over the past few days, I’ve realized (as I figured we would) that the choice is not so simple. Our desire in this evaluation is to try to make the best decision for our company, but that’s not so easy with the cacophony of voices out there. As I detailed in "A Little Less Spring in Our Step?", our thinking was that since we use JSF, we could use its IoC, supplemented by container injection to replace what Spring does for us (templates notwithstanding). I started a new app this week, so we decided I’d experiment with that and see how it goes, and, thus far, it really hasn’t been too bad. I have things working, but things aren’t quite as easy as they once were. Under the old way, I could tell Eclipse to deploy my app to the server and start debugging, but, with EJB3, we have to package our app correctly to get injection and such to work. Since MyEclipse does not appear to support EJB3 yet, that means I have to use ant to package and deploy my archive, which means a lot of window switching. That’s not a big deal, but it’s not a nice feature either. ;) Recently, there have been a number of articles about Spring and JPA, which is one of our main interests in EJB3 (we need to do some SOA stuff, so the ease of development and deployment of session beans and web services is also of interest. Plus JMS, JMX, …​). This shows that we can maintain our commitment to and investment in Spring, and still gain the advantage of using the standard ORM (of course, "standard" here means "official", not standard as in "commonly used." That title clearly goes to Hibernate), making switching providers, should the need arise, even easier. But what do we lose? Session bean injection? We’re not doing that right now anyway. DataSource injection? We’re doing that now through Spring, but defining a JNDI lookup bean and wiring it in through the config. Hmm…​ Ater reading the comments here, I’m really not sure. Gavin, of course, loves EJB3 (as do I), but Rod and others seem not to. Both parties are, of course, a bit biased, but is that because they feel that way honestly, or because they have to because preivous public positions or employers require that they do. Or a mix of both. It’s tough to say, and far be it from me to try to guess at then malign someone’s motives, but that uncertainty does require that I take their comments with a grain of salt the size of a <a title: "I stole this line :)">Ford Taurus</a>. Rick Hightower seems to be somewhere in the middle, tied to neither platform, and he prefers Spring. Being someone whose opinion I tend to value and trust (though I’ve never actually met him ;) ), his stance lends a good deal of support to maintaining our Spring commitment. Gavin (and Rod), though, are no slouches themselves. Ah, the tyranny of choice. I feel like Robin Williams in Moscow on the Hudon trying to buy coffee. Maybe we should just switch to Ruby where, apparently, we’d pretty much have only one choice. Ugh. Forget I said that. :)" So, we have a dilemma that we need to resolve and move on. I don’t want it to come down to the toss of a coin, but, personally, I’m having a hard time making a decision. My experience this week, though, has made me wonder if our all-EJB3 experiment is worth finishing, so maybe that tells me something. I’m certainly leaning toward ending the experiment. I’ve long been a Spring fan, and 2.x looks really exciting. If we need session bean injection, I think we can always use aspects (neatly handled by Spring) to force container injection at object creation time. That may be the route we go. As Matt Drudge would say, Developing…​ ### [The Front Porch Test](/2006/the-front-porch-test/) The Front Porch Test Everyone knows that one of the most important things a software project is a good name, but coming up with a good name is not easy. To help with the process, we apply what my boss, Mitch, refers to as the front porch test, which is actually a rule of thumb from the pet world. It goes like this: When picking a name for a dog, imagine yourself standing on the front porch yelling the dog’s name out into the neighborhood. If you think you’d feel like an idiot yelling that name, then choose something else. Replace "dog" with "program" and you should get the idea. ### [Yahoo! UI Meets JavaServer Faces](/2006/yahoo-ui-meets-javaserver-faces/) Yahoo! UI Meets JavaServer Faces In my ongoing efforts to learn the JSF framework as thoroughly as possible, I decided to write a component, but, with the myriad of high quality components available, what was left for me to do? :P At the suggestion of my brother, who has been watching a similar effort underway in the Wicket space, I’ve decided to wrap Yahoo’s UI library. The problem I ran into pretty quickly, though, was that the documentation wasn’t too clear as to what I needed to make it happen (though it’s quite likely I was having an obtuse moment or three). There are a plethora of resources that discuss what needs to be done, but all seemed either incomplete or too disjointed (see disclaimer above). So, to help ameliorate that, let’s walk through wrapping Yahoo’s calendar component as a JSF component, step by step. Before I go much further, though, I must note that I am by no means an expert in this, so it’s likely that you’re going to see some less than ideal examples. So, without further ado…​ When starting any project, it’s good idea to try to get a complete picture of what you’re going to need. In my efforts to wrap YAHOO.widget.Calendar, I found that I need to create following files: src/main/ com/steeplesoft/jsf/components/yui/calendar CalendarRenderer.java CalendarTag.java UICalendar.java META-INF faces-config.xml yuisf.tld There are other files in my project, but these are the pertinent ones for now. With which file you start when writing components is probably largely a matter of personal taste, but we’ll start looking at things with yuisf.tld, as that will define how our tag looks to the outside world, giving us a good idea of what we’ll need to do in the rest of the files. Here’s what the TLD looks like: <?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>0.1</tlib-version> <jsp-version>1.2</jsp-version> <short-name>yuisf</short-name> <uri>http://steeplesoft.com/yuisf</uri> <display-name>YahooUIJsfTags</display-name> <description> Yahoo! User Interface JSF Tags This tag library contains tags which wrap several of the Yahoo! UI components. </description> <tag> <name>calendar</name> <tag-class> com.steeplesoft.jsf.components.yui.calendar.CalendarTag </tag-class> <body-content>JSP</body-content> <description>Display a JavaScript calendar</description> <attribute> <name>textField</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <description>Text field that holds the date selected</description> </attribute> </tag> </taglib> Most of this should be fairly self-explanatory, so we’ll skip down to the tag element. The first thing we do is give the tag a name, calendar (surprise, surprise), which will be the name used in your JSP templates. Next, we define the class that will implement this tag, com.steeplesoft.jsf.components.yui.calendar.CalendarTag. Skipping a bit more, we see one attribute element. This is where we define what attributes a user can set on our tag. For this tag, we declare a textField attribute, which is required. CalendarTag implements our tag. Since we don’t need any JSF 1.2-specific features, and we want the tag to be available to a wider audience, we’ll target 1.1, which means that our class will need to extend UIComponentTag. Let’s take a look at that class now: package com.steeplesoft.jsf.components.yui.calendar; import javax.faces.component.UIComponent; import javax.faces.el.ValueBinding; import javax.faces.webapp.UIComponentTag; import com.sun.faces.util.Util; public class CalendarTag extends UIComponentTag { private String textField=null; public String getComponentType() { return UICalendar.COMPONENT_TYPE; } public String getRendererType() { return UICalendar.RENDERER_TYPE; } protected void setProperties(UIComponent component) { super.setProperties(component); UICalendar calendar; try { calendar=(UICalendar)component; } catch (ClassCastException cce) { throw new IllegalStateException("Component " + component.toString() + " not expected type. Expected: UICalendar. Perhaps you're missing a tag?"); } if (textField != null) { if (isValueReference(textField)) { ValueBinding vb = Util.getValueBinding(textField); calendar.setValueBinding("textField", vb); } else { calendar.setTextField(textField); } } } public String getTextField() { return textField; } public void setTextField(String textField) { this.textField = textField; } } There are three methods that we need to override: getComponentType(), getRendererType(), and setProperties(UIComponent component). In our implementation of the first two methods, we simply return a public static String from UICalendar, which we’ll see in a moment. These values will be used to help tie the component in just a moment. The third method is <a title: "quoth the Ryan Lubke">where the magic happens</a>. Since we want the component to be value binding aware, we set the textField attribute to rtexprvalue=false in yuisf.tld, and check to see if the value passed is a literal or value binding expression, and handle it appropriately. Is that overkill for this field? Most likely. ;) Note also, that we have accessors for each attribute exposed in the TLD." UICalendar is the actual component. For no particularly compelling reason, I’ve chosen to extend javax.faces.component.UIPanel. Let’s take a look: package com.steeplesoft.jsf.components.yui.calendar; import javax.faces.component.UIPanel; public class UICalendar extends UIPanel { public static final String COMPONENT_TYPE = "com.steeplesoft.jsf.components.yui.calendar.Calendar"; public static final String RENDERER_TYPE = "com.steeplesoft.jsf.components.yui.calendar.Calendar"; protected String textField; public String getTextField() { return textField; } public void setTextField(String textField) { this.textField = textField; } public UICalendar() { setRendererType(RENDERER_TYPE); } public String getFamily() { return "YuiCalendar"; } } This class doesn’t do much of anything of interest, but it’s important for a couple of reasons. Via the constuctor and getFamily, more pieces are put in place to tie all of our files together to make our new component. We also defined a property and accessors for our textField attribute, which will make working with the component in Java code a bit nicer. Note also that public static Strings defined at the top. We’ve already seen these referenced once in our tag class, and we’ll see in a moment the final place these values are referenced. All of this work is for naught if JSF doesn’t know how to render the component. We’ll do that now, via CalendarRenderer: package com.steeplesoft.jsf.components.yui.calendar; import java.io.IOException; import java.net.URL; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.render.Renderer; import com.steeplesoft.jsf.components.yui.utils.RendererHelper; public class CalendarRenderer extends Renderer { private static final String CALENDAR_CSS_RENDERED_SCRIPT_KEY = "yui_calendar_css_rendered"; private static final String CALENDAR_RENDERED_SCRIPT_KEY = "yui_calendar_js_rendered"; public CalendarRenderer() { // } public void encodeEnd(FacesContext context, UIComponent component) throws IOException { if ((context == null) || (component == null)) { throw new NullPointerException(); } ResponseWriter writer = context.getResponseWriter(); if (!RendererHelper.hasBeenRendered(context, RendererHelper.YAHOO_RENDERED_SCRIPT_KEY)) { RendererHelper.writeScriptTag(writer, component, RendererHelper.RESOURCE_PREFIX +"/META-INF/yahoo.js"); } if (!RendererHelper.hasBeenRendered(context, RendererHelper.DOM_RENDERED_SCRIPT_KEY)) { RendererHelper.writeScriptTag(writer, component, RendererHelper.RESOURCE_PREFIX +"/META-INF/dom.js"); } if (!RendererHelper.hasBeenRendered(context, RendererHelper.EVENT_RENDERED_SCRIPT_KEY)) { RendererHelper.writeScriptTag(writer, component, RendererHelper.RESOURCE_PREFIX +"/META-INF/event.js"); } if (!RendererHelper.hasBeenRendered(context, CALENDAR_RENDERED_SCRIPT_KEY)) { RendererHelper.writeScriptTag(writer, component, RendererHelper.RESOURCE_PREFIX +"/META-INF/calendar/calendar.js"); } if (!RendererHelper.hasBeenRendered(context, RendererHelper.JS_UTIL_RENDERED_SCRIPT_KEY)) { RendererHelper.writeScriptTag(writer, component, RendererHelper.RESOURCE_PREFIX +"/META-INF/js-utils.js"); } if (!RendererHelper.hasBeenRendered(context, CALENDAR_CSS_RENDERED_SCRIPT_KEY)) { RendererHelper.writeCssLinkTag(writer, component, RendererHelper.RESOURCE_PREFIX +"/META-INF/calendar/calendar.css"); } writeCalendarMarkUp(context, writer, component); } protected void writeCalendarMarkUp (FacesContext context, ResponseWriter writer, UIComponent component) throws IOException { UIComponent textField = component.findComponent((String)component.getAttributes().get("textField")); URL sxURL = CalendarRenderer.class.getResource("/META-INF/calendar/CalendarTemplate.txt"); String sxTemplate = RendererHelper.readInFragmentAsString(sxURL); sxTemplate = sxTemplate.replaceAll("%%%DIV_ID%%%", component.getId()) .replaceAll("%%%TF_ID%%%", textField.getClientId(context)) .replaceAll("%%%RESOURCE_PREFIX%%%", RendererHelper.RESOURCE_PREFIX); writer.write(sxTemplate); } } This class is the most interesting of all that we’ve done thus far, as this is where the user interface magic happens. It is via the renderer that the component is turned from Java source, TLDs, and view templating mark up into a real live HTML (in our case) widget. For those not familiar with the calendar component, here is what we want our output to look like: <input id="j_id_id15:test" type: "text" name="j_id_id15:test" readonly="readonly" /> <script type: "text/javascript" src="resource.jsf?r=/META-INF/yahoo.js"></script> <script type: "text/javascript" src="resource.jsf?r=/META-INF/dom.js"></script> <script type: "text/javascript" src="resource.jsf?r=/META-INF/event.js"></script> <script type: "text/javascript" src="resource.jsf?r=/META-INF/calendar/calendar.js"></script> <script type: "text/javascript" src="resource.jsf?r=/META-INF/js-utils.js"></script> <link type: "text/css" rel="stylesheet" href="resource.jsf?r=/META-INF/calendar/calendar.css" /> <img id="img_j_id_id18" alt="calendar" src="resource.jsf?r=/META-INF/calendar/calendar_icon.gif" onclick="show(this,'j_id_id18')" /> <div id="j_id_id18" style="visibility: hidden; display: inline;" /></div> <script type: "text/javascript"> function j_id_id18_calOnSelect() { var tf = document.getElementById("j_id_id15:test"); tf.value = formatDate(j_id_id18_cal.getSelectedDates()[0]); var cal = document.getElementById("j_id_id18"); cal.style.visibility = 'hidden'; } j_id_id18_cal = new YAHOO.widget.Calendar("j_id_id18_cal","j_id_id18"); j_id_id18_cal.onSelect = j_id_id18_calOnSelect; var pos = YAHOO.util.Dom.getXY("img_j_id_id18"); var img_height = parseInt(YAHOO.util.Dom.getStyle("img_j_id_id18", "height")); elem = YAHOO.util.Dom.get("j_id_id18"); elem.style.top = pos[1] + img_height - 1 + "px"; elem.style.left = pos[0] + "px"; elem.style.position = 'absolute'; j_id_id18_cal.render(); </script> Wow! That’s some pretty ugly markup, but what you get out of that generated mess is, in my opinion, worth it, and the user will never see that (unless he’s crazy enough to view the page source). That mark up, by the way, is generated by this template snippet: <h:inputText id="test" readonly="true"/> <yuisf:calendar textField="test"/> Let’s break things down a little bit. Since this tag does not support any children tags (plus the fact that it seemed like a good idea), we do all of our work in encodeEnd(). After a little error checking, we get a reference to the ResponseWriter used to output our HTML. The next several blocks of code handle sending the Yahoo! Javascript files to the browser (the mechanics of which are beyond the scope of this article, but feel free to browse the source). Care is taken to prevent sending the file more than once in the event that more than one calendar is on the page. The actual markup output occurs in writeCalendarMarkUp(). I’ll not muddy the waters by explaining exactly how it works, but suffice it to say that a template is loaded from the class path and markers in the template are replaced with values from the tag (big tip of the hat to Ed, whose code I shamelessly stole). The final piece to tieing this together is faces-config.xml: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <faces-config> <component> <description> Yahoo! UI Calendar </description> <display-name>Yahoo! UI Calendar</display-name> <component-type>com.steeplesoft.jsf.components.yui.calendar.Calendar</component-type> <component-class>com.steeplesoft.jsf.components.yui.calendar.UICalendar</component-class> <component-extension> <renderer-type>CalendarRenderer</renderer-type> </component-extension> </component> <render-kit> <description> Renderkit implementation for the Calendar component </description> <renderer> <component-family>YuiCalendar</component-family> <renderer-type>com.steeplesoft.jsf.components.yui.calendar.Calendar</renderer-type> <renderer-class>com.steeplesoft.jsf.components.yui.calendar.CalendarRenderer</renderer-class> </renderer> </render-kit> </faces-config> Here we define both a component and a render kit. Note that component-type is the same as UICalendar.COMPONENT_TYPE, and component-class is our UICalendar class. For the render kit, component-family is what UICalendar.getFamily() returns (if you had a group of components that used the same renderer, each class would return the same string for its family). The renderer-type is that same as UICalendar.RENDERER_TYPE, and, of course, renderer-class points to our Renderer child. With all of that done, we need to package our new component. In the component jar, you’ll obviously need the compiled Java classes, but you’ll also need the META-INF directory in the root of your jar (which is why I chose to put it in the root of my source directory). You are now ready to put the resulting jar (and it’s dependencies) in your web application and start using the component. Simple, eh? :) While this gets a functioning component (and a pretty cool one at that), it’s certainly not feature complete, nor is it an example of how one should write a component. Hopefully, though, it will get you started writing your own components as it did me. So what’s the future of this component? The short answer is, I’m not completely sure. All I know is that it will be open sourced somewhere. Discussions about where the project will live are pending, but I hope to have that nailed down pretty soon. If nothing else, I’ll host them here. Watch this space for more information on that. ### [A Little Less Spring in Our Step?](/2006/a-little-less-spring-in-our-step/) A Little Less Spring in Our Step? Friday I had an interesting discussion with my boss, Mitch. I have been doing a lot of thinking about Java EE 5 and what it offers, and that has me reevaluating some of our technology decisions. Most notably, which was the bulk of my discussion with Mitch, is, "Do we really need Spring anymore?" Currently, the way we use Spring is simply as a way to wire together classes and get us a HibernateTemplate. While that is what it was designed to do, in part, our usage is admittledly likely very basic. It is that realization, though, that made me wonder if we need Spring at all. As I’ve noted, we’ve committed to using GlassFish as our application server, which gives us a full JEE stack, something Spring was designed to obivate. We’re also a JSF shop, so we get a pretty decent dependency injection mechanism for free. Given JSF’s IoC/DI, and JEE 5’s resource injection, I think we can get the benefits of Spring from the EE environment. For example, a typical app for us has a JSF-managed bean to back one or views. Through faces-config.xml, we create a ServiceLocator class that creates the Spring ApplicationContext and exposes one or more methods to retrieve our "service" objects from the Spring Context. We wire that into each JSF-managed bean, so we can then push all DI off on to our Spring configuration. In applicationContext.xml, we create beans for various business method functionalities as well as our DAO layer, wiring everything together as appropriate. Enter JEE 5, stage left. One of the features I’m looking forward to using in EE 5 is the Java Persistence API. JPA will give us a container-/provider-agnostic way of mapping our domain objects to database tables. As we migrate to using JPA in lieu of Hibernate, the HibernateTemplate becomes less and less useful. Furthermore, since an EE 5 container can inject the Entity Manager resource, we don’t need Spring to manage our Hibernate SessionFactory anymore, so we can remove both of those objects (as well as many of their dependencies) from the Spring config. The way I see it, we can also handle our service objects differently in at least a couple of different ways. My first though was that we could have JSF manage those beans for us. We could configure them in the faces-config.xml (or split them out into a separate file and add that to the JSF config in web.xml) and just wire them into the backing beans as appropriate. While that will work, we still have to manage that mapping manually, which is a bit of a bore sometimes. An alternate approach (which I’ll confess I’ve not thought through fully) is to annotate and deploy our service beans as session beans, stateful or stateless as appropriate, and use the EE 5 container’s resource injection mechanism to inject the beans into the backing beans at run-time. That would simplify our XML, as well as decreasing the complexity of our backing beans, even if just slightly. So, with the injection of Entity Managers for DAOs, and sessions beans for our service layers, where does that leave Spring? We don’t need it in the DAO layer anymore, nor do we need it to tie our view and service layers together anymore. Does that make it completely useless to us? Not necessarily, as we occasionally have to use JDBC, and the JDBCTemplate is really nice. But, for the bulk of the heavy lifting, that puts Spring in the same position I was in junior high sports: on the side watching and wishing. We haven’t made the decision to pull the plug on Spring yet, but it has been placed on our "do we really need this technology list." Time will tell if my hunch is correct and if we can put Spring out to pasture. It’s not that we hate you Spring, but EJB3 is not EJB2. Not by a long shot. ### [SOAP to slsb](/2006/soap-to-slsb/) SOAP to slsb As part of our migration to GlassFish, one of my tasks is to migrate all of the web services we’ve exposed via Mule to a session bean environment, which won’t be too hard since we only have two such deployments. The code changes are really pretty small, but non-obvious (given my nascent EJB3 knowledge). For those that might be in a similar situation, let’s take a quick look at what this process entailed. Under Mule, the classes were Spring-managed, so we were able to leverage Spring’s IoC and lifecycle offerings to make things pretty easy. We simply created the bean definition (with all of its dependencies) in the Mule config, then wrote a little more XML to tell Mule to expose the bean’s methods as a web service. To make this class a session bean, all we’d have to do then, or so I though, was put a @Remote annotation on the interface and a @Stateless annotation on the implementation, and we’d be pretty much done. My guess was close, but not quite accurate. As I started the code migration, I quickly realized that we wouldn’t be able to use Spring dependency injection unless we cobbled it in somehow. My first attempt was to create the Spring ApplicationContext in the constructor of my POJO, getting a reference to the JdbcTemplate from that context, and setting it on my POJO (which extended JdbcDaoSupport). This seemed a bit clunky, but, in theory, would work. For reasons I can’t quite explain, though, it did not. Attempts to create (implicity, via Spring) the SQLErrorCodeSQLExceptionTranslator would fail spectacularly with what appeared to be a NullPointerException (the stack trace was a little vague despite its verbosity). My hunch was that the failure was related somehow to the lifecycle of my session bean. To test my theory, I moved the context creation to initDao(), a JdbcDaoSupport method I overrode. I then added an explicit call to that method to make sure it ran before my business method did. After packaging and deploying the application, my out-of-container test client showed that that configuration did indeed work. Putting an explicit call at the top of each business method, though, was quite distasteful, so I dove further into the EJB3 spec in search of something that would help. Surely there were lifecycle methods I could use. I was not disappointed. EJB3 offers the annotation @PostConstruct which, based on my limited research and conjecture, marks a method as one to call post-construction. I know you’re likely as mystified as I was. ;) At any rate, I left my initDao() method as it was, added the annotation, and removed all explicit calls to the method. Repeating my tests showed that this annotation did exactly what I had hoped it would, but I wasn’t quite done with the code. For no real good reason, I wanted to use container injection for the DataSource, thereby using the EJB container for everything I could. With that goal in mind, I added a DataSource member variable as well as the annotation to ask for the injection of the resource: @Resource (name = "jdbc/Comergent") DataSource dataSource; Then, in my initDao() method, I manually constructed the two Spring classes I needed. Having done all of that, I tested again to make sure I had not broken anything, which I hadn’t. Some may question my choice to move the handling of these classes and resources from the Spring config to my code, and all I can say is that I have no real good reason. At the time, it just felt like the right way to handle it. I may at some point change my mind, but that’s the way it is right now. :) Overall, knowing what I know now, the task itself was not that difficult, though the level of effort was certainly heightened due to my lack of depth with EJB3. Migrating the remaining service, though, should be a breeze. For those that like to see code, here it is: @Stateless public class ComergentPartnersSessionBeanImpl implements IComergentPartners { protected Log logger; IComergentPartners service; protected JdbcTemplate jdbcTemplate = null; @Resource ( name = "jdbc/Comergent" ) DataSource dataSource; public ComergentPartnersSessionBeanImpl() throws Exception { logger = LogFactory.getLog(this.getClass().getName()); } @PostConstruct protected void initDao() throws Exception { if (jdbcTemplate == null) { SQLErrorCodeSQLExceptionTranslator trans = new SQLErrorCodeSQLExceptionTranslator(); trans.setDataSource(dataSource); jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); jdbcTemplate.setExceptionTranslator(trans); } } /* Lots of business methods removed for brevity */ } ### [Embedding JSF with Winstone](/2006/embedding-jsf-with-winstone/) Embedding JSF with Winstone Sometimes, when developing a JSF application, it would be nice not to have to wait for your favorite container to start up. That’s especially true if your container is a full JEE stack like GlassFish or JBoss. Likewise, there are times when you might need to embed a web application in another, say some server process or desktop application. While there are a number of options available, I’d like to demonstrate how to embed a simple JSF application using the Winstone Servlet Container. To help demonstrate how this is done, we’ll use a well know sample application: Duke’s guessNumber game, and, to make things even more interesting, we’ll convert the application to use Facelets (mostly because I love Facelets, but partly because I didn’t care to figure out how to make Winstone compile JSPs ;) ). First, let’s take a look at the web app itself. To convert the application to a Facelets app, we’ll have to rename the JSPs, then make them conform to XHTML and Facelets specifications. First off, a really easy one: index.html. This page simply redirects us to guessNumber.xhtml. I could probably have done this in web.xml, but it was in the original app, so we’ll just run with it like that. index.html: <html> <head> <META HTTP-EQUIV=Refresh CONTENT="0; URL=greeting.jsf"> </head> <body> </body> </html> Pretty simple and boring. Let’s now take a look at our template file (for a fuller introduction to using Facelets, please see Rick Hightower’s excellent article, as well as Jim Hazen’s Getting Started article): layout.xhtml: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <head> <title><ui:insert name="title">Default title</ui:insert></title> <link rel="stylesheet" type: "text/css" href="./css/main.css"/> </head> <body> <div style="float: left"> <h:graphicImage id="waveImg" url="/wave.med.gif" /> </div> <div> <ui:insert name="content"></ui:insert> </div> </body> </html> Nothing real exciting there either. Next we have greeting.xhtml and response.xhtml. greeting.xhtml: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <ui:composition template="layout.xhtml"> <ui:define name="title">Number Guess</ui:define> <ui:define name="content"> <h:form id="helloForm" > <h2>Hi. My name is Duke. I'm thinking of a number from <h:outputText value="#\{UserNumberBean.minimum}"/> to <h:outputText value="#\{UserNumberBean.maximum}"/>. Can you guess it?</h2> <h:inputText id="userNo" value="#\{UserNumberBean.userNumber}" validator="#\{UserNumberBean.validate}"/> <h:commandButton id="submit" action="success" value="Submit" /> <br /> <h:message style="color: red; font-family: 'New Century Schoolbook', serif; font-style: oblique; text-decoration: overline" id="errors1" for="userNo"/> </h:form> </ui:define> </ui:composition> </html> response.xhtml: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <ui:composition template="layout.xhtml"> <ui:define name="title">Number Guess</ui:define> <ui:define name="content"> <h:form id="responseForm" > <h2><h:outputText id="result" value="#\{UserNumberBean.response}"/></h2> <h:commandButton id="back" value="Back" action="success"/> </h:form> </ui:define> </ui:composition> </html> Having fixed up our views to work using Facelets, let’s now see exactly how we do the embedding. That magic is done in the following class. WinstoneServer.java: package embed; import java.net.URL; import java.util.HashMap; import java.util.Map; import winstone.Launcher; public class WinstoneServer { Launcher winstone; public void startup() { Map args = new HashMap(); try { URL webdir = getClass().getResource("/WebContent"); args.put("webroot", webdir.getPath()); System.out.println(args.toString()); Launcher.initLogger(args); winstone = new Launcher(args); // spawns threads, so your application doesn't block } catch (Exception e) { e.printStackTrace(); } } public void shutdown() { winstone.shutdown(); } public static void main(String args[]) { WinstoneServer server = new WinstoneServer(); server.startup(); } } That code is taken pretty much verbatim from the Winstone documentation. I split it out into methods on the class to make it prettier, but that’s about it. It’s an extremely simple process. Of course, there are many more options available, all of which are documented on Winstone’s site. My goal here isn’t to be a Winstone tutorial, so we’ll just use the minimum configuration, which is where to find the web root. The web root probably needs a word here. What I’ve done in my example, which you’ll see in the archive attached to this article, is to put the web root directory in the source directory. By doing it this way, when Eclipse compiles my project it moves my web root to the build directory, making it simple to load it from the classpath. There are at least two other ways to accomplish the task: hard coding a path on the filesystem, and archiving the web root to a .war and telling Winstone to use the war. Each has its pros and cons. Your choice will depend on your intended usage. Ideally, for a packaged and deployed application, it would be nice to be able to jar the web root up with the application, but I have not had any luck getting it to load the web app from inside a jar. Given the limited scope of this demonstration, though, I opted not to pursue that very far. Now, the UserNumberBean class, the Faces-managed bean that is the actual heart of the application. I’ve included the full source code here for a couple reasons: the upgrade to JSF 1.2 necessitated some source changes, and there was apparently some sort of error in the inclusion of the code in the article linked above resulting in the case of some identifiers being mangled somewhat. UserNumberBean.java: package guessNumber; import java.util.Random; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.validator.LongRangeValidator; import javax.faces.validator.ValidatorException; import com.sun.faces.util.MessageFactory; public class UserNumberBean { protected int maximum = 0; protected boolean maximumSet = false; protected String[] status = null; protected int minimum = 0; protected boolean minimumSet = false; protected Integer userNumber = null; protected Integer randomInt = null; protected String response = null; Random randomGR = new Random(); public UserNumberBean() { randomInt = new Integer(randomGR.nextInt(10)); System.out.println("Duke's Number: " + randomInt); } public void setUserNumber(Integer user_Number) { userNumber = user_Number; System.out.println("Set userNumber " + userNumber); } public Integer getUserNumber() { System.out.println("get userNumber " + userNumber); return userNumber; } public String getResponse() { if (userNumber != null && userNumber.compareTo(randomInt) == 0) { randomInt = new Integer(randomGR.nextInt(10)); return "Yay! You got it!"; } else { return "Sorry, " + userNumber + " is incorrect."; } } public String[] getStatus() { return status; } public void setStatus(String[] newStatus) { status = newStatus; } public int getMaximum() { return (this.maximum); } public void setMaximum(int maximum) { this.maximum = maximum; this.maximumSet = true; } public int getMinimum() { return (this.minimum); } public void setMinimum(int minimum) { this.minimum = minimum; this.minimumSet = true; } public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException { if ((context == null) || (component == null)) { throw new NullPointerException(); } if (value != null) { try { int converted = intValue(value); if (maximumSet && (converted > maximum)) { if (minimumSet) { throw new ValidatorException( MessageFactory.getMessage (context, LongRangeValidator.NOT_IN_RANGE_MESSAGE_ID, new Object[]{ new Integer(minimum), new Integer(maximum) })); } else { throw new ValidatorException( MessageFactory.getMessage (context, LongRangeValidator.MAXIMUM_MESSAGE_ID, new Object[]{ new Integer(maximum) })); } } if (minimumSet && (converted < minimum)) { if (maximumSet) { throw new ValidatorException(MessageFactory.getMessage (context, LongRangeValidator.NOT_IN_RANGE_MESSAGE_ID, new Object[]{ new Double(minimum), new Double(maximum) })); } else { throw new ValidatorException( MessageFactory.getMessage (context, LongRangeValidator.MINIMUM_MESSAGE_ID, new Object[]{ new Integer(minimum) } )); } } } catch (NumberFormatException e) { throw new ValidatorException( MessageFactory.getMessage (context, LongRangeValidator.TYPE_MESSAGE_ID)); } } } private int intValue(Object attributeValue) throws NumberFormatException { if (attributeValue instanceof Number) { return (((Number) attributeValue).intValue()); } else { return (Integer.parseInt(attributeValue.toString())); } } } The web.xml and faces-config.xml files used to wire the web application together are pretty standard, but I’ll include them here for your perusal: web.xml: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>JavaServer Faces Guess Number Sample Application</display-name> <description>JavaServer Faces Guess Number Sample Application</description> <!-- Use Documents Saved as *.xhtml --> <context-param> <param-name>javax.faces.DEFAULT_SUFFIX</param-name> <param-value>.xhtml</param-value> </context-param> <!-- Special Debug Output for Development --> <context-param> <param-name>facelets.DEVELOPMENT</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>com.sun.faces.verifyObjects</param-name> <param-value>true</param-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> <context-param> <param-name>com.sun.faces.validateXml</param-name> <param-value>true</param-value> <description>Set this flag to true if you want the JavaServer Faces Reference Implementation to validate the XML in your faces-config.xml resources against the DTD. Default value is false.</description> </context-param> <context-param> <param-name>com.sun.faces.verifyObjects</param-name> <param-value>true</param-value> <description> Set this flag to true if you want the JavaServer Faces Reference Implementation to verify that all of the application objects you have configured (components, converters, renderers, and validators) can be successfully created. Default value is false. </description> </context-param> <listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener> <!-- Faces Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- Faces Servlet Mapping --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <security-constraint> <!-- This security constraint illustrates how JSP pages with JavaServer Faces components can be protected from being accessed without going through the Faces Servlet. The security constraint ensures that the Faces Servlet will be used or the pages will not be processed. --> <display-name>Restrict access to JSP pages</display-name> <web-resource-collection> <web-resource-name>Restrict access to JSP pages</web-resource-name> <url-pattern>/greeting.xhtml</url-pattern> <url-pattern>/response.xhtml</url-pattern> </web-resource-collection> <auth-constraint> <description>With no roles defined, no access granted</description> </auth-constraint> </security-constraint> </web-app> faces-config.xml: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd"> <faces-config> <application> <locale-config> <default-locale>en</default-locale> <supported-locale>de</supported-locale> <supported-locale>fr</supported-locale> <supported-locale>es</supported-locale> </locale-config> <view-handler>com.sun.facelets.FaceletViewHandler</view-handler> </application> <navigation-rule> <description>The decision rule used by the NavigationHandler to determine which view must be displayed after the current view, greeting.jsp is processed.</description> <from-view-id>/greeting.xhtml</from-view-id> <navigation-case> <description>Indicates to the NavigationHandler that the response.jsp view must be displayed if the Action referenced by a UICommand component on the greeting.jsp view returns the outcome "success".</description> <from-outcome>success</from-outcome> <to-view-id>/response.xhtml</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <description>The decision rules used by the NavigationHandler to determine which view must be displayed after the current view, response.jsp is processed.</description> <from-view-id>/response.xhtml</from-view-id> <navigation-case> <description>Indicates to the NavigationHandler that the greeting.jsp view must be displayed if the Action referenced by a UICommand component on the response.jsp view returns the outcome "success".</description> <from-outcome>success</from-outcome> <to-view-id>/greeting.xhtml</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <description>The "backing file" bean that backs up the guessNumber webapp</description> <managed-bean-name>UserNumberBean</managed-bean-name> <managed-bean-class>guessNumber.UserNumberBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>minimum</property-name> <property-class>int</property-class> <value>0</value> </managed-property> <managed-property> <property-name>maximum</property-name> <property-class>int</property-class> <value>10</value> </managed-property> </managed-bean> </faces-config> The archive attached to this blog does not have the dependencies included for size and (possible) legal restrictions, so here’s a list of what my workspace has: commons-el.jar commons-logging-1.0.4.jar el-api.jar el-ri.jar jsf-api-1.2.jar jsf-facelets-1.1.jar jsf-impl-1.2.jar log4j-1.2.13.jar winstone-0.8.1.jar That’s all there is to. To run the sample application, simply run embed.WinstoneServer, point your browser at http://localhost:8080, and start guessing. As I’ve hopefully made clear, embedding a JSF application can be quite simple, though that simplicitly is linked somewhat to the embedding environment. Please note that this sample is not meant to be a catalog of best practices for JSF, Facelets or Winstone embedding, but to be a simple introduction to the topic, and, to that end, I hope you’ll find it useful. (You can download the source archive here). ### [FacesUtil: A missing, yet important piece](/2006/facesutil-a-missing-yet-important-piece/) FacesUtil: A missing, yet important piece A reader brought to my attention that I have never posted the code to FacesUtil, a convenience class used, for example, in my JSF, PhaseListeners, and GET Requests article, so I’ll fix that oversight now. Before I get to the code, though, let me preface it by saying this: This code has grown as several developers have hacked on it, so it my not be consistent, and probably doesn’t embody any sort of best practices. It does, however, work well for us, and that’s our primary concern. :) Note also, that this code has not been updated to the 1.2 specification yet, so you’ll at least get warnings if not errors should you use this in a 1.2 environment. I am currently in the process of updating the class, but, for now, here it is in its current state. FacesUtil.java import javax.faces.FactoryFinder; import javax.faces.application.Application; import javax.faces.application.ApplicationFactory; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.faces.el.ValueBinding; import javax.faces.webapp.UIComponentTag; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; /** * Utility class for JavaServer Faces. * */ public class FacesUtil { /** * Get servlet context. * * @return the servlet context */ public static ServletContext getServletContext() { return (ServletContext) FacesContext.getCurrentInstance() .getExternalContext().getContext(); } /** * Get managed bean based on the bean name. * * @param beanName * the bean name * @return the managed bean associated with the bean name */ public static Object getManagedBean(String beanName) { Object o = getValueBinding(getJsfEl(beanName)).getValue( FacesContext.getCurrentInstance()); return o; } /** * Remove the managed bean based on the bean name. * * @param beanName * the bean name of the managed bean to be removed */ public static void resetManagedBean(String beanName) { getValueBinding(getJsfEl(beanName)).setValue( FacesContext.getCurrentInstance(), null); } /** * Store the managed bean inside the session scope. * * @param beanName * the name of the managed bean to be stored * @param managedBean * the managed bean to be stored */ public static void setManagedBeanInSession(String beanName, Object managedBean) { FacesContext.getCurrentInstance().getExternalContext().getSessionMap() .put(beanName, managedBean); } /** * Get parameter value from request scope. * * @param name * the name of the parameter * @return the parameter value */ public static String getRequestParameter(String name) { return (String) FacesContext.getCurrentInstance().getExternalContext() .getRequestParameterMap().get(name); } /** * Add information message. * * @param msg * the information message */ public static void addInfoMessage(String msg) { addInfoMessage(null, msg); } /** * Add information message to a sepcific client. * * @param clientId * the client id * @param msg * the information message */ public static void addInfoMessage(String clientId, String msg) { FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg)); } /** * Add error message. * * @param msg * the error message */ public static void addErrorMessage(String msg) { addErrorMessage(null, msg); } /** * Add error message to a sepcific client. * * @param clientId * the client id * @param msg * the error message */ public static void addErrorMessage(String clientId, String msg) { FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg)); } /** * Add warning message. * * @param msg * the warning message */ public static void addWarningMessage(String msg) { addWarningMessage(null, msg); } /** * Add warning message to a sepcific client. * * @param clientId * the client id * @param msg * the warning message */ public static void addWarningMessage(String clientId, String msg) { FacesContext.getCurrentInstance().addMessage(clientId, new FacesMessage(FacesMessage.SEVERITY_WARN, msg, msg)); } /** * Evaluate the integer value of a JSF expression. * * @param el * the JSF expression * @return the integer value associated with the JSF expression */ public static Integer evalInt(String el) { if (el == null) { return null; } if (UIComponentTag.isValueReference(el)) { Object value = getElValue(el); if (value == null) { return null; } else if (value instanceof Integer) { return (Integer) value; } else { return new Integer(value.toString()); } } return new Integer(el); } private static Application getApplication() { ApplicationFactory appFactory = (ApplicationFactory) FactoryFinder .getFactory(FactoryFinder.APPLICATION_FACTORY); return appFactory.getApplication(); } private static ValueBinding getValueBinding(String el) { return getApplication().createValueBinding(el); } public static HttpServletRequest getServletRequest() { return (HttpServletRequest) FacesContext.getCurrentInstance() .getExternalContext().getRequest(); } private static Object getElValue(String el) { return getValueBinding(el).getValue(FacesContext.getCurrentInstance()); } private static String getJsfEl(String value) { return "#{" + value + "}"; } } ### [JSF, PhaseListeners, and GET Requests](/2006/jsf-phaselisteners-and-get-requests/) JSF, PhaseListeners, and GET Requests UPDATE: For a missing piece of code, please see this entry. In one of our applications at work, we needed to be able to deep link to certain pages to allow external applications to get at specific pieces of data, product and order information to be specific. Since JSF 1.x does not support HTTP GET requests, this poses a problem. In order to get (no pun intended) information to the backing bean for processing, the data would have to be POSTed. This obviously makes bookmarking the resulting page useless. Our initial solution was to write a servlet filter which would get a reference to the current FacesContext, then get a reference to the appropriate JSF managed bean, and pump data into it. This actually worked rather well, but, at Ed Burns' suggestion, I decided to reimplement this a JSF PhaseListener (many thanks to Ryan Lubke for his help!). A PhaseListener is "an interface implemented by objects that wish to be notified at the beginning and ending of processing for each standard phase of the request processing lifecycle." At any rate, what I was able to do is register a PhaseListener to execute on the RESTORE VIEW phase (for a GET request, the only two phases that run are the RESTORE VIEW and RENDER RESPONSE phases). In a nut shell, what the beforePhase() method does is this: * Get the Request URI and break it into parts. The URI is expected to be in the format /Context/application/parm1/parm2/parm3/…​ * The "application" is extracted from the URI, and the rest is passed off to the appropriate handler * Inside the handler, a reference to the managed bean for the "application" is retrieved from the FacesContext * As appropriate for each handler, data is pulled from the URI and injected, via setters, into the managed bean * The ViewRoot is set for the appropriate output page. If this is not done, the server will return a 404, as /Context/application does not exist on the filesystem. * The method returns, as does beforePhase(), and the lifecycle is completed. What comes out the other end is the expected pages, just as if someone had filled out a form and clicked submit. It’s really quite nifty. Of course, all of that is pretty tough to follow with out some code, so here we go. First, let’s register the PhaseListener: <lifecycle> <phase-listener> com.iecokc.gopher.view.util.PrettyUrlPhaseListener </phase-listener> </lifecycle> Next, let’s look at the PhaseListener itself: public class PrettyUrlPhaseListener implements PhaseListener { private static final Log logger = LogFactory.getLog(PrettyUrlPhaseListener.class); FacesContext context = null; public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } public void beforePhase(PhaseEvent e) { PhaseId phase = e.getPhaseId(); if (phase == PhaseId.RESTORE_VIEW) { try { context = FacesContext.getCurrentInstance(); HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); String uri = request.getRequestURI(); if (uri != null) { // Split the URI by / to get its component parts String[] parts = uri.split("\\/"); String application = parts[2]; // This PhaseListener knows about two "applications", // product lookup, and the cleverly titled, Dude // Where's My Order if ("product".equals(application)) { handleProductLookups(parts); } else if ("dwmo".equals(application)) { handleDudeWheresMyOrder(parts); } } } catch (Exception ex) { logger.error(ex.getMessage()); ex.printStackTrace(); } } } protected void handleProductLookups(String parts[]) { String partNumber = ""; // If there aren't enough parts to complete the request, redirect // to the product home page if (parts.length != 5) { // There's no way to determine what this should be // programmitcally, so we'll hardcode the value here (and in // handleDudeWheresMyOrder()). // Be careful to note that we say .jsp and not .jsf, or you'll // get a nasty recursion error. UIViewRoot view = context.getApplication().getViewHandler(). createView(context,"/productViewHome.jsp"); context.setViewRoot(view); } else { try { partNumber = URLDecoder.decode(parts[3], Charset.defaultCharset().displayName()); String tab = parts[4]; UIViewRoot view = context.getApplication(). getViewHandler(). createView(context,"/productViewResults.jsp"); context.setViewRoot(view); ProductViewBean bean = (ProductViewBean) FacesUtils.getManagedBean("pvForm"); if (tab != null) { bean.setTab(tab); } if (partNumber != null) { bean.setPartNumber(partNumber); } } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } } } protected void handleDudeWheresMyOrder(String parts[]) { if (parts.length != 5) { UIViewRoot view = context.getApplication(). getViewHandler().createView(context,"/dwmoHome.jsp"); context.setViewRoot(view); } else { String orderNumber = ""; try { orderNumber = URLDecoder.decode(parts[3], Charset.defaultCharset().displayName()); String tab = parts[4]; UIViewRoot view = context.getApplication(). getViewHandler(). createView(context,"/dwmoResults.jsp"); context.setViewRoot(view); DudeWheresMyOrderBean bean = (DudeWheresMyOrderBean) FacesUtils.getManagedBean("dwmoForm"); if (tab != null) { bean.setTab(tab); } if (orderNumber != null) { bean.setOrderNumber(orderNumber); } } catch (UnsupportedEncodingException ex) { ex.printStackTrace(); } } } public void afterPhase(PhaseEvent e) { // We don't care about this } } There’s one more step. Currently, our application is only configured to map *.jsf to the FacesServlet, so we’ll need to add a couple more mappings to make our "virtual" URLs work. This goes in web.xml: <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/product/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/dwmo/*</url-pattern> </servlet-mapping> If you had the rest of our code, you should now be able to deploy the web page and point your browser at /Context/product/ABC123/tab and learn all about one of our products. :) Since you don’t have the rest of the app, you obviously can’t do that, but hopefully I’ve provided enough information for you to implement a similar solution. As always, any comments and enhancements are much appreciated. ### [MyEclipse and GlassFish](/2006/myeclipse-and-glassfish/) MyEclipse and GlassFish My shop has adopted MyEclipse as the standard development environment. Our recent adoption of GlassFish, though, makes things a little difficult for MyEclipse (and likely Eclipse in general) as integration with the app server has not yet landed in any GA release that I’m aware of. This difficulty, however, is not insurmountable. Let’s take a look at how to debug a GlassFish-hosted application using (My)Eclipse. Obviously, to start, you’ll need MyEclipse and GlassFish installed. Their respective web sites cover that, so I won’t here. The only change you’ll need to make to GlassFish is to enable debugging. To do that, log on the admin console, and navigate to Application Server→JVM Settings→General. On this page, you’ll first need to make sure that the Enabled checkbox on the Debug line is checked. In the next field, Debug Options, make a note of the value for the "address=" portion. That will be the port that we give to MyEclipse. Click Save to commit your changes, and let’s move on to MyEclipse. As things stand now, MyEclipse does not have a connector for GlassFish. It does, however have one for SJSAS 8.1, which is close enough for our needs. We’ll start by configuring that. Open the preferences dialog (Window→Preferences), and expand the MyEclipse branch on the left of the dialog. You should now see an "Application Servers" branch. Expand that and find and select "Sun Java Application Server Edition 8.1." On this tab fill out the information it asks for, making sure to select Enabled at the top. Before clicking OK, select JDK under "Sun Java Application Server Edition 8.1" on the left. Make sure a JDK and not a JRE is selected, then click OK. Now, you’ll need to create a "Remote Java Application" for each application you want to debug. To do this, go to Run→Debug…​ In the dialog that appears, select "Remote Java Application" on the left, and click New. In the Name field, enter the name of the application, then select the project by clicking on the Browse…​ button. The only other change you’ll need to make is to change the port under Connection Properties to what you noted from the GlassFish configuration, which is most likely 9009. Switch to the Common tab, and check Debug in the "Display in favorites menu" box. Hit apply, then close the window. You will now need to tell MyEclipse to deploy the application to GlassFish. To do this, right click the project and select MyEclipse→Add and Remove Project Deployments…​ Make sure the desired project is selected in the drop down, then click Add. Under Server, select Sun Java Application Server 8.1 / 8.2, select Packaged Archive, and click Finish. MyEclipse will then build and deploy the WAR file to GlassFish. Once that finishes, click OK. You are now ready to debug your application by clicking the down arrow by the bug in the tool bar at the top and selecting the application you just configured. MyEclipse will attach to your local GlassFish application, and stop execution at any breakpoint you may have set. Switch to your favorite browser <subliminal>Firefox</subliminal> and point it http://localhost:8080/foo, where foo is the desired context root. The only "big" issue I’ve found so is that it appears that you have to manually redeploy your app when you make changes. This doesn’t appear to be required when deploying as an exploded archive, but I’ve had bad luck with that under GlassFish for reasons I haven’t taken the time to track down. So there you have it. The process isn’t perfect, but it should at least get you going until MyEclipse finishes the promised GlassFish connector currently in the works. ### [JIRA and GlassFish](/2006/jira-and-glassfish/) JIRA and GlassFish Officially, GlassFish is not a supported platform for JIRA, Atlassian’s extremly popular issue tracker. Since we’re migrating to GlassFish at work, it’s pretty important that we get it the two to work together. As it turns out, it’s really not that bad at all. Here’s what I had to do to get JIRA, PostgreSQL, Active Directory and GlassFish all playing nicely together. The first step, of course, is to download the JIRA distribution (For our purpose here, I’m going to assume that GlassFish and PostgreSQL are already installed an running.) Once JIRA has been downloaded, we need to extract the archive to our work area and make our mods. In our case, the mods were pretty simple: database location, plus Active Directory integration, which means two files need to be modified. For the database, you’ll need to modify entityengine.xml, which you will want to copy from webapp/WEB-INF/classes to edit-webapp/WEB-INF/classes. We’ll need to make two changes in this file: the transaction factory, and the data source. For the transaction factory, we need to locate the element, and edit it to look like this: <transaction-factory class="org.ofbiz.core.entity.transaction.JNDIFactory"> <user-transaction-jndi jndi-server-name="default" jndi-name="UserTransaction"/> <transaction-manager-jndi jndi-server-name="default" jndi-name="UserTransaction"/> </transaction-factory> For the curious, that change is just the removal of java:comp/ from the JNDI name. For the data source, find the element toward the end of the file. This is what ours looks like: <datasource name="defaultDS" field-type-name="postgres72" helper-class="org.ofbiz.core.entity.GenericHelperDAO" check-on-start="true" use-foreign-keys="true" use-foreign-key-indices="true" check-fks-on-start="true" check-fk-indices-on-start="true" add-missing-on-start="true" check-indices-on-start="true"> <jndi-jdbc jndi-server-name="default" jndi-name="jdbc/Jira"/> </datasource> Of course, you need to make sure that the datasource jdbc/Jira is configured in GlassFish. If you need help with that, this blog entry should be helpful. For Active Directory integration, copy osuser.xml from webapp/WEB-INF/classes to edit-webapp/WEB-INF/classes. Since this file is smaller, I’ll show it in its entirety: <opensymphony-user> <authenticator class="com.opensymphony.user.authenticator.SmartAuthenticator"/> <provider class="com.opensymphony.user.provider.ldap.LDAPCredentialsProvider"> <property name="java.naming.factory.initial"> com.sun.jndi.ldap.LdapCtxFactory </property> <property name="java.naming.provider.url"> ldap://foo:389 </property> <property name="searchBase"> cn=Users,dc=foo </property> <property name="uidSearchName"> sAMAccountName </property> <property name="java.naming.security.principal"> cn=ESP Service Account,cn=Users,dc=foo </property> <property name="java.naming.security.credentials"> bar </property> <property name="exclusive-access"> true </property> </provider> <provider class="com.atlassian.core.ofbiz.osuser.CoreOFBizCredentialsProvider"> <property name="exclusive-access">true</property> </provider> <provider class="com.opensymphony.user.provider.ofbiz.OFBizProfileProvider"> <property name="exclusive-access">true</property> </provider> <provider class="com.opensymphony.user.provider.ofbiz.OFBizAccessProvider"> <property name="exclusive-access">true</property> </provider> </opensymphony-user> Once those files have been created, from the root of the JIRA work directory, issue the command "build ear". Technically, you have a choice between WAR and EAR deployment. I chose EAR, as it saves me one step (changing the context root) at deployment. It will most likely take a few minutes for that task to complete. Once it has, log on to the GlassFish admin app, navigate to Applications→Enterprise Applications, click deploy, then click Browse to find your EAR, which will be in the directory dist-generic in your JIRA working directory. Select the ear, click OK, click Next, change the app name if you’d like, then click Finish. This process, too, will likely take a few minutes, but, once it’s done, you’re ready to point your browser at your new JIRA installation and begin configuring it. It’s that easy! ;) ### [New Blog Site](/2006/new-blog-site/) New Blog Site I have decided to do my blogging here, rather than inside Joomla! on the (mostly working) main site.  I think things will be a bit easier to manage here, with a little less clutter on the main site.  Since I didn’t have much there, that shouldn’t be an issue for anyone at all. :) On the "mostly working" part, an explanation is probably due.  I changed hosts, and just copied the DB to use with a new installation of Joomla!, so the database thinks there are certain plugins installed, while the filesystem doesn’t know anything about them, so some things are broken.  I’ll get around to fixing that soon, I hope, but there are higher priority items on my plate at the moment. ### [JSF and Annotations](/2006/jsf-and-annotations/) JSF and Annotations Recently at work, we looked, ever so briefly, at a new web framework called Stripes. It looked rather cool, as it was largely annotation-based, but, given its glaring lack of any wide-spread usage, we never seriously considered it. Today, I was on The Server Side (you do read TSS, right? ;) ) and noticed that Struts has released a Java 5 addon. One of the additions is annotation support whose only problem appears to be that it’s tied to Struts (that’s a joke ;) ). At any rate, all of this annotation on the web tier got me to thinking (again) about my favorite Java web tier technology, JSF. The only "real" complaint I have with the framework is the XML, minimal as it is (I’m past the JSF learning curve, so I don’t have a problem with that anymore :) ). Being a big fan of annotations and IoC, I’ve been wondering if/when JSF will finally support configuration via annotations. Until this morning, I’ve just assumed that I won’t see that support until 2.0, but a thought occured to me: why can’t it be bolted on to 1.x? In the interest of full disclosure, I’ve never written my own annotations, and I’m not too terribly familiar with the internals of either major JSF implementation, but I have in my mind a back-of-a-napkin sketch of a possible solution. My initial guess is that it might be possible to write a class (a FacesServlet child, maybe) that scans the classpath (optionally restricted by context-params, for example) looking for annotated classes and methods. Armed with the knowledge gleaned from the scan, we would then be able to build the context (I’m hoping) in a similar fashion to parsing faces-config.xml. Is it doable? Am I off my rocker? I don’t know. Hopefully, I’ll have a chance to find out soon, assuming someone in the know doesn’t disabuse of the notion before I get started. :) World’s Fastest Update: Ed Burns gave me this link, which looks to be exactly what I was looking for. That will save me a lot of time. :) ### [JSF and File Downloads, Take Two](/2006/jsf-and-file-downloads-take-two/) JSF and File Downloads, Take Two Yesterday, I detailed some issues I was having getting a JSF app to allow the download of an Excel spreadsheet as the result of a backing bean action being called. My solution involved a servlet and some JavaScript, with just a -pinch- a fistful of kludge. Thanks to the esteemed Mr. Chad Cummings, I have a better solution, and it involves one small change to the backing bean (the navigation target returned) and the addition of this snippet to the JSF page: <h:panelGrid columns="1" rendered="#\{batchAuditReportBean.workBook != null}"> <f:verbatim> <iframe src="success.jsp" style="visibility: hidden"/> </f:verbatim> </h:panelGrid> Is it still a bit of a hack? Maybe so, but it does work, and is a whole lot cleaner. That’s a plus in my book, so I’m going to commit this to our Subversion repository. ### [JSF and File Downloads](/2006/jsf-and-file-downloads/) JSF and File Downloads At IEC, we have an application used to report inventory counts. Part of the app creates an Excel spreadsheet using POI. The user selects a batch from a select/combo, click on the button, and the server sends them a spreadsheet. The basic work flow is this: Display the page User selects a batch and clicks the button JSF calls the specified action on the backing The backing bean creates the spreadsheet, then navigates to success.jsp, a plain ol' JSP The JSP pulls the backing bean from the session, gets the workbook reference from it, and streams that to the user using a ServletOutputStream. This works well under Tomcat and JSF 1.1. Our goal, though, is to migrate to a full JEE 5 environment, hosted on GlassFish. GlassFish, though, ships with JSF 1.2, as JSF is now part of the JEE spec (starting with version 5). This poses a problem, though, as there has apparently been a good deal of work in view handling in 1.2 that breaks this behavior. Ed Burns has been nice enough to take a look for me, but, while waiting for him to get time to help me, I took a stab at fixing it. My tentative work around for it is as follows: Alter the form to use a "normal" (read as: non-JSF) form and submit to a servlet. Write a servlet that in effect duplicates the JSF lifecycle: Build/load the FacesContext Get a reference to the backing bean Pull the batch id from the request and set it on the backing bean. Call the action method. At this point, the servlet works the same as the JSP: Get the reference to the workbook Stream the workbook to the user. This works, but is a pretty ugly hack. In fact, check out the code: public class ExcelServlet extends HttpServlet { /** * If you examine FacesContext, you'll find that the setFacesContextAsCurrentInstance method is protected. */ private abstract static class ProtectedFacesContext extends FacesContext { protected static void setFacesContextAsCurrentInstance(FacesContext facesContext) { FacesContext.setCurrentInstance(facesContext); } } public ExcelServlet() { super(); } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.getFacesContext(request, response); BatchAuditReportBean report = (BatchAuditReportBean) FacesUtils.getManagedBean("batchAuditReportBean"); report.performTask(); org.apache.poi.hssf.usermodel.HSSFWorkbook workBook = report .getWorkBook(); ServletOutputStream sos; try { response.setHeader("Cache-Control", "max-age=1"); response.setHeader("Content-Disposition", "attachment; filename=\"InventoryErrorReportServlet.xls\""); response.setContentType("application/vnd.ms-excel"); sos = response.getOutputStream(); workBook.write(sos); sos.flush(); } catch (IOException ioe) { System.out.println("IO Exception: " + ioe.toString()); } response.getOutputStream().close(); } private FacesContext getFacesContext(ServletRequest req, ServletResponse res) { /** Try to get it first */ FacesContext facesContext = FacesContext.getCurrentInstance(); if (facesContext != null) return facesContext; // Use the FactoryFinder to grab the Lifecycle object FacesContextFactory contextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); // Here's where the ProtectedFacesContext comes in facesContext = contextFactory.getFacesContext(this.getServletContext(), req, res, lifecycle); ProtectedFacesContext.setFacesContextAsCurrentInstance(facesContext); return facesContext; } } This code doesn’t yet have the parameter fetching, but you can see how unattractive it is. Hopefully, Ed will have a nicer fix for me. Until then, I may have to put this monstrosity in production. ### [A Java-based 'Playground' App](/2005/a-java-based-playground-app/) A Java-based 'Playground' App As I’ve noted earlier, I’ve been debating whether or not I should continue PHP development and move to only Java. Part of the process has included writing a web application using some of the newer Java libraries…​ What I needed was something simple to help me try out some of the newer (at least to me) Java libraries. What I came up with is a wish list application. There is no telling how many times my wife and I saw a movie, book, CD, etc. that we thought that we would like to get but didn’t have the "mad money" to do so at the time, then forgot about by the time we had the cash for a frivolous purchase (or rental). I kept telling myself that I needed a way to track that, so, finally, Wish List was born. It’s a simple app. It lists items that are on the wish list. If one authenticates, items and types can be added and edited. It currently supports only one wish list, a restrication that may or may not change in the future. Source for this application can be found here. Bear in mind that this is a learning project, so it is likely overengineered and quite possibly poorly implemented. At any rate, the techonologies used in this app are Hibernate, Spring, and JavaServer Faces. While I’ve used Hibernate before, I’ve taken this opportunity to use it as heavily as I can (given the simple schema) to get a better handle on foreign key handling and the like. Spring and JSF are both new to me, and, so far, I’m in love. I’ll not going into details why here (you can read their respective web sites for that), but they really make web development easier. Very cool technologies. I’ve also used the DAO and Service patterns (I may have just made up those pattern names :) to help abstract things a bit. So where does that leave things? Right now, things aren’t looking too good for PHP. PHP is a great language and allows you to build things extremely quickly, but the lack of a VM makes certain programming practices impractical for a large application. Java, on the other hand, does not have that limitation, but the code, build, test cycle is longer than that for PHP, though that’s not something I’m completely averse to. The main problem with switching to all Java development is a practical one: I have a good deal of PHP code that would have to be rewritten, or I’d have to find a hoster that supports both and doesn’t cost a fortune. So…​ No decision yet, but if I found a good hoster, that might change things. Time will tell. At any rate.. Download the code and take a look at it. It’s not in any real shape for deployment, as the database has to be created manually and a default user (MD5 password and all) would have to be manually added, but you can at least browse the code. If I get time, I’ll add some code to initialize the environment as best I can. ### [There has to be a decent ORM for PHP](/2005/there-has-to-be-a-decent-orm-for-php/) There has to be a decent ORM for PHP For quite a while now, I’ve been using PEAR’s DB_DataObject to do data persistence, but I’ve never been quite satisfied with it. As I’ve used Hibernate more and more, I find myself increasingly disappointed with DB_DataObject, so I went searching for a solution. While I haven’t searched real hard, I’ve done some googling, and come up with two possible solutions: EZPDO, and Metastorage. Just from glancing at Metastorage’s web site, it looks like it’s REALLY heavy, whereas EZPDO seems to be much lighter, with simplicity being a design goal (which may turn out to be more limiting than helpful. Who knows?). That being said, I think I may give EZPDO a whirl once I get Class Portal out the door. Unless I miss my guess, EZPDO will let me implement the DAO pattern that has served me so well in my Java coding. It may be that 1.1 has completely redesigned and rewritten data access code. Time will tell. Other than, Class Portal is progressing pretty nicely. I think it’s at the point that I can migrate my Sunday School’s site to it. I just have to finish up my ad hoc migration script. ### [To PHP or not to PHP...](/2005/to-php-or-not-to-php/) To PHP or not to PHP…​ After years of PHP development, I find myself trying to decide if I should stick with the language…​I have been doing PHP for years; since the PHP3 days. I have found it to be a powerful and flexible language that is easy to code in and deploy. Every web application I have running at home, on this site, or any of the other hand full of sites I maintain or help maintain is written in PHP. I love the language. However, after having professionally written in Java in addition to other languages, including PHP, I am now in a full time, 100% Java position, and, having had the opportunity to dig deeper into the myriad of libraries available in Java, I find myself wondering if I should use only that. I have been writing Java applications since JDK 1.1 (AWT-based applications…​ woo! ), though my time has been split among several languages (C/C++, PHP, Delphi, bash, etc). I’ve always viewed Java as a powerful language, and have always enjoyed writing in it, but I’ve never seen the need to do only Java. My experience with Java in the web realm wasn’t overwhelming. Write, compile, archive, deploy, test, rinse, repeat. With PHP, I write and test. Point a browser at the file (through a web server) and off you go! Java was a bit more tedious (IDE support was pretty weak) and I just didn’t see the need to put myself through that. Since starting my new job, though, I have been able to really dig into some technologies that I’ve been eyeing for some time now, namely, JavaServer Faces (JSF), Hibernate, Eclipse, and Spring. The combination of these four items addressed most of my concerns with regard to the development cycle (granted, they’ve been around in one form or another, but since my job until recently wasn’t Java-heavy, I haven’t had the chance to really look at them). JSF takes a lot of the pain out of writing a web interface (PHP has similar problems, but also has a viable solution or two); Hibernate, in my experience, is the best Object/Relation Mapping and persistence tool on the market in any language; Spring makes wiring everything together; and Eclipse is just a great, multi-purpose IDE. Having had the chance to learn these tools has really changed the way I look at web development and how to structure web applications. PHP, while it can use the same techniques, does suffer from performance penalties (since the environment must be recreated, for the most part, with every request), not being VM-based. Are these obstacles able to be overcome? Sure, they are, but you have to think differently. Is PHP still a viable language? Absolutely! The release of PHP 5 has shown that PHP isn’t just a toy language, as some might suggest, but that it is very much targeted at enterprise use. While it’s not perfect, as no language is, I think it is still a very suitable language for web development. My quandry, though, cernters around the fun I’m having with Java at work and if having that same fun at home is worth giving up the positvies (and the fun) that PHP offers. And I don’t know how to answer that question. Another thing that makes me hesitant about adopting a single language for work and play is the danger of becoming a one trick pony. Over the years, I’ve met people that know only one language, or only one language well, whether it’s C/C, COBOL, Java or even PHP. These people tend to get stuck doing things in one particular fashion and seem to tend to have problems thinking creatively. Since I know several languages (though I would hesitate to don the "expert" moniker in any of them), I can look at problem and say, "In C, we would…​" or "Java has a nice implementation of…​" There’s a part of me that would hate to give up that cross-pollinization that using multiple languages gives me. Of course, the corollary to that idea is that I’m completely off-base in my one-trick pony fears. I don’t know what I’m going to do. I might experiment with doing the next Steeplesoft project in Java and see how things go. We’ll have to see…​ ## Pages ### [Presentations](/presentations/) Below is a (non-exhaustive) list of the presentations I’ve given over the years, ordered roughly by date. It’s a bit bare, but I’ll try to get others added as soon as I can. April 2022 jOOQ: Database Abstractions Without Distractions …​ Older :) Oracle Turns Java up to 11 ### [Tags](/tag2/) {% assign tags = "" | split: "," %} {% for tag in site.tags %} {% assign t = tag | first %} {% assign tags = tags | push: t %} {% endfor %} {% assign tags = tags | sort_natural %} {% for tag in tags %} {% assign t = tag | downcase | replace: " ", "-" %} {{ tag }} - {{ site.tags[tag] | size }} Posts {% endfor %} ### [404](/404.html) 404 Page not found :( The requested page could not be found. ### [posts/index.html](/blogs/) ← First Older Posts → Securing Claude Code: Guardrails for AI-Assisted Development by Jim Manico Apr 21 2026 In a presentation to OWASP London, Jim Manico, founder of Manicode Security, presents how he uses Claude Code to bootstrap projects safely using Claude Code and carefully scripted prompts and inputs. Using the approach he demos, developers won’t just vibe code sloppy, insecure software, but will set up their projects to get deterministic, high quality results. Manico begins by starting Claude and having it create a new repository on GitHub. Once the repository..... Read More › Koin: The Way Object Handling Was Mint to Be Feb 20 2026 Sharp-eyed readers of this series may have noticed something…​suboptimal: Up until this point, we’ve been creating certain objects as global variables. They’re immutable, so that may be technically OK, but those of a certain age have been taught for years how wrong that is, so technically OK or not, it just feels gross. In this post, we’re going to fix that with by implementing inversion of control with Koin... Read More › Moar Data! Jan 21 2026 In the last entry, we looked at how to read data from the device’s local database using Room and display it on the screen, but we did so using dummy data. In this entry, we’ll look at how to use Room in our components to persist user-entered data in our SQLite database... Read More › Decompose and Data. Let's See What You Got Jan 11 2026 In the last post — months ago (and, yes, I hand typed the em dash, not some soulless AI :) — we added support for the Room database API, so now we can store data, but we have no way of seeing what we’ve saved. We also have no way of giving it data to save. In this post, we’ll tackle the first part by creating views to show what we have, then loading the database..... Read More › Make Room for Some Data Aug 26 2025 So far, we have a runnable application that has two screens. We can navigate between those screens, but the app doesn’t really do anything. In this post, we’ll start to fix that. We’ll lay out the data model for the application, then introduce the library, Android Room, we’ll use to access it... Read More › Decompose Navigation: Let's Add a Screen Aug 6 2025 In the last post, we added the various pieces to make navigation possible and stopped JUST short of the goal line. In this post, we’ll finish up our navigation discussion by adding a new screen and seeing navigation in action... Read More › Decompose Navigation and the Root Component Aug 5 2025 So far, we have an app that runs but has only one "screen". Decompose makes adding more screens — and navigating between them — pretty simple. In this post, we’ll start to see how that’s done... Read More › What's Up with expect/actual? Jul 7 2025 In the last post, we saw — and then ignored — a couple of interesting keywords: expect and actual. In this short post, I’ll give what I hope is enough of an explanation to satisfy the mildly curious. To recap, the code in question looks like this: composeApp/src/commonMain/kotlin/com/steeplesoft/giftbook/Platform.kt interface Platform { val name: String } expect fun getPlatform(): Platform So…​ what..... Read More › Compose Multiplatform with Decompose Jul 6 2025 In this installation in my Mobile App Development series, I’m going to introduce our next architectural layer, Decompose. We’ll look at what it is, why you might want it, and how to get started... Read More › Getting Started with Compose Multiplatform Jun 26 2025 In this installation in my Mobile App Development series, we’ll take a look at the most foundational piece of the puzzle, Compose Multiplatform. We’ll see what it is and how to use it... Read More › ← First Older Posts → ### [posts/index.html](/posts/page2/) ← Newer Posts Older Posts → Mobile App Development Series Introduction Jun 25 2025 In recent years, I’ve found myself needing to build a mobile app here or there, and it has been, at times, a bit of a struggle as the landscape — and opinions about it — are wide and varied. There are debates about native, hybrid, and cross-platform approaches, and once you’ve made that decision, you have to wade through a lot of opinions on what library..... Read More › This Blog Now Roqs. I mean... it always has, of course, but now it REALLY does Mar 20 2025 Years ago, I started this blog on WordPress, then moved to awestruct, then to JBake, then to Jekyll. I’ve not done that because I like to change things, though I must admit I’ve enjoyed doing it each time, but because I’m looking for something that best suits my needs... Read More › A Recap of my night at the Oklahoma City JUG Mar 12 2025 Last night, I had the opportunity to present at my local jug, the Oklahoma City Java User Group. My topic was building applications Kotlin/Compose Multiplatform. For the most part, it was awesome. More on that in a moment. The presentation was an introduction to the technologies that I’ve found helpful in building cross-platform applications. I tried to be clear that what I was presenting is my current architecture and that things..... Read More › Coil AsyncImage with Authentication Feb 3 2025 I’ve been working on a side project that includes both a backend (Quarkus-based, of course) and a mobile app (I’m using Kotlin Multiplatform, but that’s a topic for another time). In this project, I need to display an image (think profile picture), but the link is secured, meaning I need to authenticate with the server to get it. I couldn’t find anything in the Coil docs..... Read More › Christmas 2024 - Human and Divine Dec 25 2024 This year was a very light year in blogging for me — even by my recent standards —  for a lot of reasons that probably aren’t of much interest to others. That said, I want to close the year out as I have for years with a Christmas post. I realize that many of you may not celebrate Christmas, and for others it’s just another holiday plus..... Read More › Inter-container Communications with Testcontainers Feb 19 2024 I recently found myself in need of having two different Testcontainers communicate with each other. To someone more familiar with Docker, the solution might have been more obvious, but, alas, I am not that man. :P After asking in the Testcontainer Slack, I got a pointer, so I thought I’d share it here in case it might help someone else. To be specific, I needed to have the OpenTelemetry Collector pushing trace data..... Read More › Christmas 2023 - I Heard the Bells on Christmas Day Dec 25 2023 As 2023 comes to a close, I want to take a slightly different approach to my Christmas greetings. I’d like to share with you a Christmas carol, and the story behind it. The poem, written by Henry Wadsworth Longfellow, explores the contrasting despair in his heart against the hope of Christmas. Having lost his wife to a fire, and having his son critically wounded in the Civil War, Longfellow struggled with his faith..... Read More › Quarkus for Frontend Devs Aug 11 2023 A friend of mine is a very good Angular developer. For a project he’s been asked to help with, though, he finds himself needing to do some backend work. Since that’s a bit outside his wheelhouse, he asked me for advice. In this post, I’ll write up what I told him in case it might be of use to someone else. Executive Summary In my opinion, the "best" starting..... Read More › Incorporating preview/experimental features in WildFly Jul 7 2023 One of the toughest challenges facing a mature product like WildFly is adding features without breaking existing users. It’s especially difficult when that project serves as the foundation for a commercial product downstream that requires a higher degree of stability. While WildFly is a wholly independent project, it’s not completely immune to concerns that EAP may have with regard to API stability, long term support, etc. That has made it difficult..... Read More › MyFaces 4 on WildFly Jul 5 2023 For several years now, WildFly has supported the ability to install and use different Jakarta Faces (Faces) implementations, either across every application deployed to the server, or for a specific application only. We supported running either Mojarra and MyFaces, with versions running all the way back to 1.2. With the move to Jakarta EE 10, however, that feature was temporarily broken simply because there was not a 4.0-compliant version of MyFaces available..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page3/) ← Newer Posts Older Posts → WildFly, Micrometer, and OpenTelemetry May 15 2023 With the release of WildFly 28, we’ve made a few changes to our supported telemetry libraries that are worth noting. In this post, I’ll give a quick overview of those changes. Perhaps the more pressing/disruptive is that we’ve removed support for MicroProfile OpenTracing and MicroProfile Metrics. MP OT itself has been deprecated/replaced by the working group with MicroProfile Telemetry. MP Metrics, though, continues to evolve in ways..... Read More › WildFly, Arquillian, Testcontainers, and Kafka Aug 24 2022 Back again with another Testcontainers example. This time, though, the environment is a bit different. We’ll be looking at a Jakarta EE application using WildFly and MicroProfile Reactive Messaging (MP RM), and we’re going to test it using Arquillian and Testcontainers. Let’s get to it. :) The Application To make things simple, we’ll develop a really simple application. It will have one endpoint that takes an entity, then..... Read More › Quarkus Dev Services, jOOQ, Flyway, and Testcontainers: A Full Example Apr 20 2022 I have written a few posts about using Quarkus with Testcontainers, Flyway, and jOOQ. Since posting those, I’ve learned some new tricks that have changed how I integrate the various tools. In this post, I’d like to share a complete example that shows how use Quarkus, Quarkus Dev Services, Testcontainers, and Flyway together for a zero (ish) local config setup. Introduction To state things more clearly, the project developed here will..... Read More › Exporting Arquillian Archives Mar 22 2022 A big part of the testing we do on WildFly involves in-container testing, for which we use Arquillian. It’s a great tool when it works right, but sometimes things don’t. When that happens, I find it helpful to examine the archives that the tests produce. Fortunately, Arquillian makes that easy if you know that magic words, and they’re not easy to find, so I’m going to..... Read More › Testing with Quarkus, jOOQ, and Testcontainers Redux Jan 15 2022 In a recent post, I showed how one could fairly easily test your Quarkus application against a Testcontainers-managed Postgres database. While that works great, my set up is a little more complex, and I found the solution lacking. In a nutshell, as part of my build, I use Flyway with H2 to create a schema, then jOOQ’s code generation against H2 to create the needed classes. That all worked well enough until..... Read More › Testing with Quarkus, jOOQ, and Testcontainers Dec 29 2022 In a project I’ve been working on, I’ve been targeting PostgreSQL, but testing with H2. While that works, I’m a big fan of having the test environment match production as much as possible. That said, I don’t like to have external system dependencies for tests, such as requiring having a database installed. That’s where Testcontainers comes in. In this post, I’ll look at..... Read More › Merry Christmas, 2021 Dec 25 2021 To all my readers, I’d like to wish a merry Christmas, and a happy new year. In a world seeking hope, my prayer is that each of you would find real, lasting hope, in the birth the baby we celebrate today, Jesus Christ, Emmanuel, God with us. (Image source. Thanks, Dr. Mounce :)... Read More › WildFly and Micrometer Oct 18 2021 Earlier in the summer, I wrote some about the addition of OpenTelemetry support in WildFly. With the release of WildFly 25, that support is now official and in the wild. With 25 behind us, we start looking at 26, and my next effort will be to integrate Micrometer metrics into the server. In this post, we’ll take a look at what that might mean, as well as presenting a way to take an..... Read More › A Quarkus Command Line Application Oct 10 2021 Most people know Quarkus as a great way to build fast, scalable microservices. What many may not be aware of, however, is that Quarkus can also be used to build command line applications as well. In this post, we’ll take a look at how we can leverage the Quarkus ecosystem we already know to build a command line utility quickly and easily. The command line application we’ll build actually already exists..... Read More › An Update on OpenTelemetry and WildFly Jul 9 2021 In a recent post, I worked through setting up OpenTelemetry support in your Jakarta EE application. Since that time, I’ve put quite a bit of work into integrating that support, as teased in the post, into WildFly. In this post, I’d like to provide an update on what that WildFly support currently looks like, and put out a request for feedback. These changes are now part of the official WildFly builds..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page4/) ← Newer Posts Older Posts → OpenTelemetry and Jakarta REST Services Jun 2 2021 Knowing what’s going on in your microservices deployment is extremely important when something goes wrong. In a distributed system, though, it can be difficult to know where things have gone wrong. That’s where a tracing system such as OpenTelemetry can be immensely valuable. In this post, we’ll build two simple services, one of which calls the other, and trace the execution from end to end. The Parent POM We..... Read More › A Simple Jakarta EE 9.1 REST Project May 25 2021 Jakarta EE 9.1 was released today, which now lets developers use — officially — Java 11 with the shiny new Jakarta EE namespace introduce in EE 9. So what does a simple Jakarta EE 9.1 REST project look like? I’m so glad you asked. :) Let’s start with the Maven POM: pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http..... Read More › Microprofile Fault Tolerance Retry in Action Mar 2 2021 As part of some of my recent work, I’ve gotten some exposure to some Microprofile specs I’ve not had the opportunity or need to use. One of those is Fault Tolerance. I was curious to see it action, so I’ve cobbled together this simple example that demonstrates some of that spec’s features, namely retries and fallback. It should be noted that the Fault Tolerance spec actually provides..... Read More › Securing and Testing Quarkus Applications using Keycloak and Wiremock Feb 17 2021 Obviously, web apps need to be secured. If you’re brave (and some might say foolish), you can roll your own security. Unless you have compelling reasons to do so, however, you probably shouldn’t. Almost as if by design (nyuk nyuk), Quarkus makes it easy to use any OpenID Connect server. One such server is Keycloak, an open source offering also from Red Hat. If your experience is like mine, though, securing..... Read More › Merry Christmas, 2020 Dec 25 2020 Merry Christmas! After what has been a tough year, my prayer is that this Christmas season will be relaxing and refreshing for us all. To help celebrate the season — I hope — I’ve embedded my church’s Christmas program, Christmas Under the Arches. My prayer is that it encourages you all and helps you focus on the Reason we celebrate. :)... Read More › Java 15: New and Notable Sep 15 2020 JDK 15 hit General Availability today. While I spend most of my time in Kotlin these days, I do keep a close on Java, as it still has a special place in my heart, so I thought I’d make a quick post highlighting some of its new features. :) There are quite a few changes in the release, so I’ll list all of them, but focus on the ones I think most..... Read More › Writing CLIs with Spring Boot and JCommander Jul 15 2020 I was recently asked to convert a Spring Boot-based "CLI" to a real CLI utility. It was actually just a normal Spring Boot application with REST endpoints that we’d hit with curl. Pretty ugly. After a few frustrating hours, I finally settled on a solution that seems to work pretty well for us. It uses Spring Boot, of course, as that’s our library of choice, plus JCommander for the argument..... Read More › Hands-free Flyway and jOOQ May 14 2020 Recently, I started working on a new project and I wanted to give Jooq a go. I also wanted to integrate Flyway: I wanted jOOQ to generate its various classes based off the database schema, and I want to Flyway to create that schema. That’s all easy enough, but I’m resisting, right now, committing the generated classes to source control (to avoid the churn and additional maintenance), so how do I..... Read More › Building Maps in Kotlin Apr 8 2020 Over the years, I’ve found myself processing a set of data and storing it in a Map, say, something like Map<Long, List<String>> (think something like a list of Room objects, keyed by a building id). I have found myself writing it something like this (in non-idiomatic Kotlin): val foo = map.get(key) if (foo == null) { foo = MutableList<String>() map.put(key, foo) } foo.add..... Read More › Custom Methods in Spring Repositories Feb 28 2020 One of the great things about Spring Data Repositories is that they provide a number of query methods out of the box, with the ability to add additional queries simply by adding carefully named methods to the interface, and Spring generates the actual implementation for you. Sometimes, though, you do need to color outside the lines a bit. Thankfully, Spring allows us to do this. You just have to ask it nicely. Here’s..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page5/) ← Newer Posts Older Posts → Restoring a Deleted Git Branch Feb 25 2020 Thanks to haste and some sloppy copy-and-paste, today I deleted the wrong remote Git branch. There’s nothing like learning in a panic, but that’s what happened. Here’s what I learned on how to fix that. While watching that all-important branch being deleted erroneously is a heart-stopping moment, as it turns out, restoring the deleted branch is Super Easy. Barely an Inconvenience. All you need to..... Read More › Best Advice I've Been Given: Check Your Ego Feb 5 2020 The Red Hat twitter account just asked this question: "Communities grow by uplifting others. What is one piece of advice you’d offer to a new developer? Reply below and then check out some advice from #RedHatter @somalley108." Here’s my input. As a general rule, if you’re writing software, you’re probably pretty intelligent. That intelligence, while important, of course, can also become a hindrance. For example, I&#8217..... Read More › Dear MockK, Repeat After Me Jan 16 2020 The project I’m working on is using Mockk in the unit tests. It’s a great library that has made true unit testing so much easier. I ran into a problem, though, where I needed a method I was mocking to return the value it was receiving. To be more specific, we were passing an object to a Spring repository method that had been built inside the method to test, and, to..... Read More › Merry Christmas, 2019 Dec 25 2019 Merry Christmas! For God so loved the world, that He gave His only begotten Son, that whoever believes in Him shall not perish, but have eternal life. -- John 3:16... Read More › Executable Kotlin Scripts Dec 23 2019 A user in #kotlin on Freenode asked how to run a Kotlin script. While the Kotlin docs are pretty clear on how to do that, I thought I’d make a quick post to show how to make an easily executable Kotlin script. The first step is to name the file with a .kts extension: test.kts println("Hello, world!") You can then run it like this: $ kotlinc -script test.kts Hello, world! That..... Read More › Testing Spring Repositories with Flyway Dec 20 2019 With my recent job change, I’ve gotten a chance to use Spring Boot in anger a bit. It’s been fun, and I’ve learned a fair bit about the current state of Spring (I still love you, Jakarta EE!). One of my tasks involved adding a query method to a repository, and I wanted to make sure the query worked before I pushed it upstream. To do that confidently, of..... Read More › When Testing with a Different Database Chokes on Your DDL Dec 13 2019 I recently found myself writing a test that needed a database. Unfortunately, our testing database, H2, doesn’t support all of the features of our production database, PostgreSQL. This meant that the Flyway migrates used to manage the production database broke in the testing environment. The fix for this turned out to be pretty simple. To set the scenario, imagine you have this table: CREATE TABLE foo ( id bigint PRIMARY KEY, some_json JSONB ); The..... Read More › Easily Switching JDKs Aug 26 2019 Development environments can get fairly complex, and making sure you’re using the right version of some library or another can be annoying on the best of days. I have a situation like that where my "day job" requires (still, and hopefully not for much longer) JDK 8, but my side projects, learning efforts, etc. can use a more modern version. Years ago, Charles Nutter shared a shell script he uses to switch JDKs..... Read More › Java to Kotlin Conversion Question. And Answer. Jul 18 2019 Recently, in the #kotlin channel on Freenode, a user asked a question about what was happening to his Java code when using IDEA’s convert-to-Kotlin functionality. He left before anyone had the time to answer, and while he likely doesn’t read my blog, I’m going to answer his question here anyway. :) Here is his (slightly edited) question: I use intellij idea to convert a java code to kotlin..... Read More › Getting started with Micronaut: Kotlin, JPA, and JWT Feb 12 2019 The Micronaut guides are really pretty good. So far, I’ve found just about everything I need. The biggest obstacle so far has been that, at times, the content was scattered across several guides and usually in the wrong language: I’m interested in Kotlin, but the guides seem to be mostly in Java or Groovy. This isn’t surprising, as budgets are limited, of course. What I would like to do..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page6/) ← Newer Posts Older Posts → Kotlin+Micronaut and IDEA Don't Get Along Together Jan 25 2019 Recently, I’ve been experimenting with Micronaut, a new-ish "modern, JVM-based, full-stack framework for building modular, easily testable microservice and serverless applications" from the makers of Grail. So far, I’ve been really impressed. The documentation has been excellent, and the framework is very easy to get started with. I have, though, run in to some trouble writing tests, or, more accurately running tests. I spent far too much time..... Read More › Merry Christmas, 2018 Dec 25 2018 I hope you all have a merry Christmas. More importantly, I hope you take the time to think about the birth of the child that gives Christmas its meaning. "The birth of Christ is the timeless event that leads us to believe that the cries of a broken world have actually been heard. A Savior has been born. The vault of Heaven truly has been opened" -- Author Unknown Thanks be to God for His indescribable..... Read More › A Possibly Silly Question about Java Visibility Dec 20 2018 This morning, I was asked a question by a coworker that we both thought we knew the answer to: if a method is protected, can other classes see that method? The answer surprised us: maybe. :) It’s a pretty simple, basic question, but I thought I’d mention it in case there’s a beginner wondering, or more senior developers, such as myself and my team mate, that just have it wrong..... Read More › Getting Started with Eclipse MicroProfile, Part 8: The Conclusion Oct 24 2018 Many times, one of the hardest parts of getting started with a particular piece of technology is figuring out how to get started. :) In this series, I’ve used an extremely simple project to show how to do just that with a number of MicroProfile implementations. Obviously, a real application will have many more concerns than we dealt with in this application, but what this effort gave us is working, runnable, and testable build..... Read More › Getting Started with Eclipse MicroProfile, Part 7: Helidon Oct 21 2018 Up next in our series comes an offering from, to me, a somewhat surprising source, Oracle, and that offering is Helidon. I first heard about in September 2018, and while it’s still pre-1.0, it looks extremely promising. Like Hammock, Helidon projects are jar projects, so we need to set the package type appropriately, then import the Helidon dependencies: <packaging>jar</packaging> <properties> <helidon.version..... Read More › Getting Started with Eclipse MicroProfile, Part 6: Hammock Oct 19 2018 This time around, we’re going to start looking at a slightly different take on MicroProfile implemenations. Whereas Payara Micro, Thorntail, OpenLibery, and TomEE are all based on application servers (albeit stripped down versions), our implementation in this post, Hammock, is based on a CDI container. Rather than start what amounts to an app server under which a web is deployed, we’ll be spinning up a plain ol' CDI container, which will..... Read More › Getting Started with Eclipse MicroProfile, Part 5: TomEE Oct 18 2018 In this installment of our series, we’re going to take a look at the last of what I think of as the more traditional, app-server-based/-spawned implementations, TomEE. TomEE is a fully Java EE-enabled distribution of the venerable workhorse Tomcat, and comes with support for creating MicroProfile applications, so let’s see what that looks like. This should come as no surprise at this point, but setting up a..... Read More › Getting Started with Eclipse MicroProfile, Part 4: OpenLiberty Oct 17 2018 Having looked at Thorntail last time, we’ll take a look at OpenLiberty this time. OpenLiberty is the open source project under which, as I understand the state of things, IBM’s WebSphere Liberty is developed. In this installment, we’ll give its MicroProfile support a quick spin. We start by setting up our POM: <packaging>war</packaging> <properties> <app.name>openliberty</app..... Read More › Getting Started with Eclipse MicroProfile, Part 3: Thorntail Oct 16 2018 In the last installment, we talked about Payara Micro. In this, we’re going to look at Thorntail. Thorntail, née WildFly Swarm, is based on WildFly from Red Hat and is said to be "just enough app-server". Much like Payara Micro, Thorntail exposes a battle-tested application server platform, stripped down for microservices usage. Let’s a take a look at what it takes to deploy our application on Thorntail. Before..... Read More › Getting Started with Eclipse MicroProfile, Part 2: Payara Micro Oct 15 2018 Payara Micro is a MicroProfile implementation from the good folks at Payara, based on Payara Server, which is itself based on GlassFish. Whew! If you’re familiar with either GlassFish or Payara, you should feel right at home with Payara Micro. To start, we need to understand how Payara Micro deploys the application. Payara Micro spins up an instance, albeit a somewhat stripped down version, of Payara Server. Once the server instance has started..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page7/) ← Newer Posts Older Posts → Getting Started with Eclipse MicroProfile, Part 1: the Application Oct 14 2018 To start our investigation, we need an application to work with. Part of the problem with getting started applications is making sure that your example is complicated enough to be interesting, but not so complicated that the greater message is lost in the details of the app. MicroProfile 2.0 is made up of a number of components: MicroProfile Config 1.3 MicroProfile Fault Tolerance 1.1 MicroProfile Health Check 1.0 MicroProfile JWT Authentication..... Read More › Getting Started with Eclipse MicroProfile, Part 0 Oct 13 2018 The Eclipse MicroProfile is a community-driven profile initially developed by Red Hat, IBM, TomiTribe, Payara and the London Java Community (LJC). Launched in 2016, it was intended to sit alongside Java EE’s Web and Full profiles, offering Java EE developers a smaller, lighter set of standards with which they could build microservices. Today, MicroProfile lives as an Eclipse project, and is being supported and actively developed by its creators as well as..... Read More › Easy File Copy in Kotlin Jun 24 2018 Copying files in Java is, I think, header than it seems it should be. Typically, I see that done with, say, a ByteArrayInputStream and a ByteArrayOutputStream . Thanks to Kotlin’s extension function capabilities, this operation is a one-liner: File("/path/to/destination").writeBytes(File("/path/to/source").readBytes()) That could even be an extension function itself: fun File.copyFile(dest: File): Unit = dest.writeBytes(this.readBytes())... Read More › VirtualBox Shared Folders under Linux May 29 2018 My work machine runs Windows (go ahead and laugh. I’ll wait). While I’ve been able to tweak the machine and get a moderately acceptable setup, there are times when I’d really like to use Linux for something, so I spin up a virtual machine with VirtualBox. While that works, I don’t really like having source code — especially with changes in flight —&#8201..... Read More › Resurrecting Turbo Vision Apr 23 2018 If you wrote software on a DOS system in the 80s or 90s, you probably used one of the Borland products, Turbo Pascal or Turbo C, with that beautiful, beautiful blue, mouse-enabled text-based user interface (TUI, if you will). Those IDEs were powered by a library called Turbo Vision (TV), which Borland documented and published for others to use. I loved it. While we all live in a GUI world and there are..... Read More › Jerkey: A Kotlin DSL for Jersey Apr 11 2018 I’m currently working on a DSLs-in-Kotlin presentation for my local JUG, so I need a good domain in which to work. HTML is a great sample domain, but it’s been done to death. After a bit of head scratching, I’ve come up with what is, I think, a somewhat novel domain: REST application building. Sure, there are libraries like Ktor, but suffers from some very serious NIH..... Read More › String.format()... You May Be Doing It Wrong Mar 29 2018 If you’ve been working with Java for very long, you’ve probably had occasion to use String.format() . And, if you’re like me, you may very well have been doing it "wrong". Let’s take a look at what was, for me, common usage, and how, maybe, you should be doing it. Let’s start by taking a look at a mildly complex — and highly..... Read More › Roku and Hotel Wifi Feb 1 2018 I was recently on a business trip and, as is my custom, I took along my Roku box so that I would have something to watch in the hotel room in the evenings. Unfortunately, the hotel wifi required that you sign in on each device in order to access the internet, but this Roku is old enough that it didn’t offer way to do that. I found some options in The Tubes, but..... Read More › Firefox, Wine, and Linux Jan 19 2018 Wise or not, I recently made the move to Linux on my work machine. For the most part, it works wonderfully. For reasons that aren’t too terribly relevant here, I found myself needing (or wanting) to run the Windows version of Firefox. While I could run it successfully, it wouldn’t connect to the internet. After a whole lot of digging, I finally found the answer, which I thought I should document..... Read More › String.split(), Java 8 style Sep 27 2017 Today I found myself with a common problem: I had a delimited string of an unknown number of parts that that I needed split apart and process. Prior to Java 8, implementing that might looked something like this: for (String part : string.split("\\n")) { if (!myList.contains(part)) { if (!part.isEmpty()) { myList.add(part); } } } While that works and seems to be pretty efficient, I felt it could use a stream makeover, as I find the..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page8/) ← Newer Posts Older Posts → Chesterton's Fence and the Software Developer Sep 24 2017 Recently at work, we found an odd scenario with a REST (-ish ;) endpoint from another team: If the request provided a list of, say, 11 IDs in the query string, the system would only return information on the first 10 of them, silently dropping anything over that seemingly odd limit. The initial reaction was of, course, "Well, let’s just increase the limit." To be honest, I had the same reaction, but then I..... Read More › My Book Has Finally Been Published Jul 31 2017 As the title states, my book has finally been published. You can get it (and you know you want to) at a number of places: Packt Amazon Barnes and Noble I had fun and learned a lot while working on this. I hope you find it useful... Read More › Getting JavaFX ListViews to Honor Container Width Apr 25 2017 I recently struggled trying to text in a JavaFX ListView to wrap inside the container like I asked it to, rather than extend (and disappear) past the boundaries of the container. After some discussion on Twitter and a bit of Googling, I found an answer that I thought I’d share here to, perhaps, save someone some time. Let’s start by looking at what I’m trying to solve using this..... Read More › Compiling for Java 8 and Java 9 Apr 15 2017 In a project I’m working on for my book, I need to share classes between two applications. One, an Android project, requires Java 8. The other, a desktop JavaFX application, needs to run under Java 9, complete with module support. The problem with this is that the Maven tooling isn’t quite ready for Java 9, so it’s not as simple as I would like. I have, however, found a..... Read More › JavaFX Frameworks Mar 12 2017 In my work on my book, I’ve spent quite a bit of time with JavaFX. In the chapter I just submitted, I wrote the application using the NetBeans RCP, which I think is a great piece of software. My only "complaint", I think, is more of a philosophical one more than a technical one, and even stating it that way is probably really over-selling it: for the most part, to use the..... Read More › Struggling with Swagger Codegen Jan 26 2017 For both my day job and a side project, I need want to generate and manage my REST APIs in a contract-first manner using Swagger. From looking at the docs, the answer seems to be Swagger Codegen, but I’m finding that it’s not that simple. Here’s the workflow I’d like to accomplish: One One a One b Two Three Three a... Read More › Merry Christmas, 2016 Dec 25 2016 In the same region there were some shepherds staying out in the fields and keeping watch over their flock by night. And an angel of the Lord suddenly stood before them, and the glory of the Lord shone around them; and they were terribly frightened. But the angel said to them, "Do not be afraid; for behold, I bring you good news of great joy which will be for all the people; for today in..... Read More › NetBeans 9 Nightlies Nov 9 2016 Perhaps I’m a bit of a glutton for punishment, but I have an odd addiction to nightly builds. In working on this book, I need to use NetBeans 9, which, of course, is not out yet. They are, however, publishing nightly builds. Being a command line guy at heart, I’d prefer not to have to go to the download page every time, so I did what any good geek would do..... Read More › Call Me Crazy, But I'm Writing a Book Oct 6 2016 A few weeks ago, I was approached by an acquisition editor with Packt Publishing, asking if I might be interested in working on a book with them. Long story short, I signed the paper work and started working on the title Java 9 Blueprints. Books in Packt’s Blueprints series offer a different project in each chapter, showing each is built, explaining the technologies used, etc. So far, it feels a lot like what..... Read More › mv /dev/oracle/NetBeans /dev/apache/ Sep 14 2016 Yesterday, the NetBeans team announced plans to move NetBeans from Oracle to Apache. This move was met by a mix of skepticism and optimism. I’ve ranged between the two myself, to be honest, but I’ve landed on optimsim. My first thought, snarky as it is, was that "Apache is where projects go to die". Think Apache OpenOffice. After discussing that with some peers, though, I remembered that 1) OpenOffice was already..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page9/) ← Newer Posts Older Posts → Android App Development Quandary Jan 11 2016 I have a grand total of one Android application in the Play Store, Cub Tracker. It serves two functions for me: it helps me manage my sons' Cub Scout den, and it gives me a means for experimentation in the mobile realm. For the most part, it has done well for me on both counts for the past few years. I am currently faced with an issue of new functionality (which is mostly irrelevant for..... Read More › Merry Christmas, 2015 Dec 25 2015 At the end of another busy year, full of stress and grief, it’s my hope and prayer that the true message of Christmas, not "getting along with family", but the birth of the Savior of the world, would settle your hearts, and that True Peace would be yours. Merry Christmas!... Read More › Kotlin and CDI Nov 5 2015 If you’ve been following my blog, you’ve probably noticed that I’ve been spending a lot of time with Kotlin of late. (For the curious, I really like it so far, but I haven’t done just a whole lot with it.) I’ve experimented with writing simple JSF and JAX-RS apps in it, largely to see if I can make it work. With those hurdles cleared..... Read More › Kotlin-RS Nov 3 2015 In keeping with theme of "use existing frameworks with Kotlin" and misleading titles, here’s a quick and dirty demonstration of writing JAX-RS applications using Kotlin. For those that read my Kotlin Faces post, the pom.xml for the project will look very familiar: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance..... Read More › Kotlin Faces Oct 29 2015 There’s a chance that at least some of you saw the blog title and thought: "Ah ha! A Kotlin wrapper/helper for JSF!" and rushed over to check it out. If so, mission accomplished. :) This really isn’t anything that ambitious. Sorry. :) At JavaOne this week, I spent a good deal of time talk to Hadi Hariri, Developer Advocacy Team Lead at JetBrains, about their Kotlin language. With my long background in..... Read More › Bad Horse! Sep 28 2015 If you’re a Doctor Horrible fan, here’s something fun and goofy to start your week. No clue how they did it, but it’s hilarious. :) (h/t to my brother) $ traceroute -m 255 bad.horse traceroute to bad.horse (162.252.205.157), 255 hops max, 52 byte packets 1 172.23.195.1 (172.23.195.1) 1.863 ms 1.193 ms 8.432 ms 2 172.23..... Read More › Be Careful with Statics Jul 16 2015 I recently came across an interesting piece of code at work: private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); What struck me as odd was the private qualifier and that the fact that SimpleDateFormat is not thread-safe. Is the private some odd attempt to work around concurrency issues, or was thread safety just overlooked? That led me to this question: Is a private static still one instance per JVM, or does the..... Read More › An Introduction to Programming with Minecraft at the Oklahoma City JUG Jun 30 2015 On Monday, July 13, I will be leading the monthly OKC JUG session, whose topic this month is "An Introduction to Programming with Minecraft Mods". We’ll be using a modified version of the curriculum Arun Gupta has developed for this Devoxx4Kids program, with examples taken from the book he and his son wrote, Minecraft Modding with Forge: A Family-Friendly Guide to Building Fun Mods in Java. Here is the announcement sent to..... Read More › Running IDEA 14 on Java 8 on the Mac Jun 26 2015 My team at work was having some issues with IDEA and the Checkstyle plugin. Based on the error message, and without actually looking at the JARs, it seemed pretty clear that the issue was a JDK version issue. While I think this issue has been resolved, when I set up my Mac months ago, I was forced to install Java 6 in order to install IDEA, but, apparently, the new version of the Checkstyle plugin..... Read More › Changing the GlassFish Admin Users's Password Programmatically May 29 2015 Recently, in the #glassfish channel on Freenode, a user was having trouble configuring GlassFish in a Docker environment. He was scripting the configuration of the server, but was having trouble setting the admin user’s password, since the change-admin-password command takes input from stdin. Fortunately, there’s REST API for that. This curl command will do what the user needs to do without any need for additional input: curl -X POST..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page10/) ← Newer Posts Older Posts → Custom Maven Packaging Type Apr 24 2015 As I’ve noted in a previous post, I recently moved my blog from Awestruct to JBake. This also allowed me to migrate the building and publishing of the blog contents to the toolchain that I know pretty well (Maven). What bothered me, though, was that my POM defined the project as a jar packaging type: the build produces no jar file and, in fact, doesn’t process any Java at all. What..... Read More › From Awestruct to JBake Mar 19 2015 For some time now, I have been using awestruct to power my blog, and, for the most part, I’ve been happy. However, I have found, especially on the Mac, the Ruby-based environment more difficult to setup than I would like. While I have solved this problem before, it presented itself once again when I was issued a Mac upon joining NetSuite. I can, of course, muddle through it, but I’m..... Read More › Multitenant PostgreSQL Feb 18 2015 As more and more of our applications move into "the cloud", multi-tenancy has become a pretty big thing these days. In a nutshell, "multi-tenancy" means handling multiple customers data using, say, a single server. This concept scales, of course, to clusters, etc., but the concept is the same: a bunch of people’s data all mixed together in one big bucket. The problem, then, for the development team is isolating one customer..... Read More › Merry Christmas 2014 Dec 25 2014 To all of my readers, I wish you all a very Merry Christmas. My hope, as always, is that even in the busyness and the hustle of the Christmas season, you will find the peace and joy of God brought to us so many years ago in the birth of the Christ child. Christmas Time Again by Smalltown Poets... Read More › Book Review: RESTful Java Patterns and Best Practices Oct 21 2014 I recently received a copy of RESTful Java Patterns and Best Practices, by Bhakti Mehta for review. Here are my thoughts on the book. Bhakti Mehta is a former coworker of mine from Sun/Oracle. We both worked on the GlassFish project, though not on the same team. RESTful Java Patterns and Best Practices is a short book, covering many topics. If I had to pick one main issue, that would be this: it felt..... Read More › Contract-First REST APIs with RAML Oct 15 2014 Yesterday, at the OKC JUG, I presented on the topic of Contract-first REST API development with RAML. This post is a rough blogification of that discussion. For those of you who were at the meeting, the preamble to the source demo (introduction, background, options discussion, etc) have been not been reproduced here. tl;dr: You can find the demo source here and play around with it. Introduction RAML is a specification for describing REST..... Read More › So long, and thanks for all the fish Oct 3 2014 As so many of my friends and peers have done before me, it’s time to use that admittedly overplayed Douglas Adams quote and announce my departure from Oracle. I joined Sun Microsystems in July of 2008 as a member of the GlassFish team, working primarily on the Administration Console. Over time, I would add REST to my work load, which has been my primary responsibility for the past few years. I’ve..... Read More › Can I Use Dropwizard for This? Aug 11 2014 I’ve been toying with using DropWizard as my…​ deployment platform for a personal project, but I need/want JAX-RS 2 and CDI, which is a problem for the the stable DW. There is a branch that is migrating to JAX-RS 2 (and Jersey 2.9), and it sort of works, but trying a simple injection is causing a failure I can’t quite figure out: Caused by: A..... Read More › Book Review: JavaFX 8: Introduction by Example Jun 25 2014 Carl Dea, this time with the help of Mark Heckler, Gerrit Grunwald, José Pereda, and Sean Phillips, recently published an updated and greatly expanded introductory work on JavaFX, with both the title and content updated to reflect the updates in the JDK and library. tl;dr: A solid introduction with a plethora of usable examples. You can purchase it here. To start with, let’s take a quick glance at the table of contents..... Read More › LiveJournal Export Jun 24 2014 I have a personal LiveJournal blog that I’d like to migrate to Awestruct. Unfortunately, LiveJournal’s export tool is really limited, allowing the export of only one month at a time. There are tools to work around that, but the only ones I’ve seen require Windows, which rules me out. In typical geek fashion, then, I wrote my own tool, ljexport, a very quick-and-dirty JavaFX 8 application. All..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page11/) ← Newer Posts Older Posts → JavaFX and Maven Jun 9 2014 I’ve been tinkering with a couple of different JavaFX projects for a while now. Due to other commitments, they’ve been largely ignored recently, but I made some time this weekend to return to them. Since I last looked at them, Java 8, and, thus, JavaFX 8, have been release, so I decided to see how the tooling in NetBeans has changed to stay apace with the development of the libraries. While..... Read More › 14 NetBeans Web Development Tips in 7 Minutes May 29 2014 Recently, Geertjan Wielenga, Principal Product Manager in the Oracle Developer Tools group, posted a video on his blog showing "14 NetBeans Web Development Tips in 7 Minutes", which showed off several nice tips for the IDE (#1 and #5 are my favorites). If you’re like me, sometimes you don’t have (or don’t want to make) time to watch a video, so I thought I’d make a table..... Read More › File Uploads with JAX-RS 2 May 1 2014 If you search for how to upload a file to a JAX-RS 2 endpoint, most suggestions will point you to implementation-specific approaches. While that works, it defeats one of the purposes of a spec: portability. There are some posts out there that will point you in the right direction, though. What I’ll do here, then, is present a clear, portable solution to the problem. In this example, we’re going..... Read More › Book Review: Java EE and HTML5 Enterprise Application Development Mar 19 2014 I was recently sent a copy of Java EE and HTML5 Enterprise Application Development by John Brock, Arun Gupta, and Geertjan Wielenga. This is my review of the book. SY300.jpg" alt="Cover" width="162" height="300"> While this a fairly short book (176 pages), the authors managed to work a fair amount in. As you probably guessed from the title, the book covers Java EE in the context of an HTML5 application. Given the..... Read More › Book Review: 50 Android Hacks Mar 5 2014 50 Android Hacks by Carl Sessa is, as you may have deduced from the title, a collection of 50 tips and tricks to help Android developers of all skill levels handle a variety of problems. For the most part, I found the book very helpful. Before I get to that, I have a minor quibble: I’m not sure "hacks" was the best choice of words. I understand the marketing aspect of it, but..... Read More › CLI Libraries Compared Feb 5 2014 I recently ran across a couple of pretty cool libraries for creating command-line tools: Airline from the Airlift project, and crest from Tomitribe. Having spent the last few years working on administration for GlassFish, this is an area near and dear to my heart, so I thought I’d cobble together a quick example using each to see how usable they are. Before we look at the code, I need to lay out..... Read More › Integrating Bitbucket and Jenkins Feb 5 2014 If you’re like me, you have your source code hosted in a hosted environment (such as Bitbucket), but you have a local continuous integration server (such as Jenkins). It would be really nice if you could have Jenkins build your project every time you commit, but without the heavy requirement of polling your repo. In this post, I’ll show you how to integrate the two to do just that. The first..... Read More › Android Lifecycles Jan 3 2014 I’ve been getting a number of bug reports from my app Cub Tracker that had me stumped. I was getting NullPointerExceptions where I shouldn’t be. After some digging, I think I finally found the culprit: device rotation. While rotating the device does, indeed, trigger the error, it goes deeper than that. My problem is that the app doesn’t correctly save the state of the view, which becomes problematic when..... Read More › Merry Christmas 2013 Dec 25 2013 As is my custom, I want to thank all of my readers, especially those who have joined the discussion, and wish you all a merry Christmas. In all the hustle of the season, it is my hope and prayer that the joy and peace brought to us in the person of Jesus Christ will be an ever-present blessing in your lives. "... Read More › Ceylon: a First, Quick Take Nov 22 2013 Last week at Devoxx, Red Hat announced the release of Ceylon 1.0, "a modern, modular, statically typed programming language for the Java and JavaScript virtual machines." A fan of learning languages, I started taking the tour. In no particular order, and without any lengthy rumination, here are my initial thoughts on the language. Mixin inheritance Mixin inheritance looks pretty interesting. While I’m no Scala expert, it strikes me as being very similar..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page12/) ← Newer Posts Older Posts → Import Maven Artifacts to Ceylon Repos Nov 22 2013 In trying to come up to speed on Ceylon, I’ve run into some issues with module import dependencies. I’m pretty sure they’re all pilot error, but it was suggested that I import the jars into the Ceylon repository and specify the dependencies between the modules. This would, effectively, be functionally the same as the <dependencies> element in the Maven POM. In classic geek, over-engineer-the-solution..... Read More › Book Review: Instant Vert.x Oct 16 2013 I recently acquired a copy of Instant Vert.x (Kindle version here) by Simone Scarduzio. It’s a short book (54 pages), so here’s my short-ish review. :) Your first question might be, "What is Vert.x"? From its web site, Vert.x is a lightweight, high performance application platform for the JVM that’s designed for modern mobile, web, and enterprise applications. http://vertx.io/ While that description says it..... Read More › Awestruct NetBeans Plugin Sep 30 2013 Several weeks ago, I posted blurb about a JavaFX project I had cobbled together, DoctorFX. It is an effort to build a semi-graphical editor for Asciidoc, but it is, currently, very basic. I had some spare time last week, so I decided to add some features to it. As I thought about what needed to be added and what that would require, I thought that, perhaps, an architectural change was warranted. With some time..... Read More › Book Review: Beginning Java EE 7 Sep 24 2013 Java Champion and JUG leader Antonio Goncalves recently released his third book on Java EE, Beginning Java EE 7. Just from the title and the table of contents, it’s clear that Antonio set a very ambitious goal for this book, and I think he delivered what he promised. Java EE is, of course, a large, diverse set of technologies, so the book itself, to do the platform justice, must also be pretty wide..... Read More › Gradle Tip: Better Test Debugging Sep 24 2013 In a recent post, I showed how to attach a debugger to tests run from the command line via Gradle. While it worked, it turns out that it’s a bit over kill. Try this instead: $ gradle -Dtest.debug test :compileJava :processResources UP-TO-DATE :classes :compileTestJava :processTestResources :testClasses :test Listening for transport dt_socket at address: 5005 Attach your debugger to port 5005, and off you go. No need to modify your build. Kudos..... Read More › Gradle Tip: Running a Single Test Sep 24 2013 Using Maven, to run a single test (class), you would issue mvn -Dtest=MyTest. Gradle has similar functionality (gradle -Dtest.single=MyTest), though it seems to be much more powerful. You can get all the details here... Read More › Gradle + Arquillian + GlassFish Embedded Sep 13 2013 I’ve recently been migrating all of my personal projects to Gradle. Since I use Arquillian, that means migrating that part of the build as well. However, being still fairly new to Gradle, how to handle that integration wasn’t immediately obvious. Thanks to Benjamin Muschko and Aslak Knutsen, I’ve finally gotten a working setup. While there is a Gradle plugin, as I understand things, it only supports the container lifecycle..... Read More › Gradle Tip: Attaching a Debugger Sep 10 2013 Maven offers a nice script to allow for attaching a debugger to your build, mvnDebug. Gradle does not. Again, though, Gradle makes it pretty easy to add this to your build. Let’s say you want to debug your tests: build.gradle test { if (System.getProperty('DEBUG', 'false') == 'true') { jvmArgs '-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=9009' } } From the command line, issue gradle -DDEBUG=true test: $ gradle -DDEBUG=true test :compileJava..... Read More › Gradle Tip: Seeing Standard Streams During Tests Sep 10 2013 I’m not a real big fan of using standard out as a debugging strategy (I prefer an IDE and break points, for what it’s worth), but there are times when it’s either necessary or just convenient. The standard Gradle configuration, though, makes this a bit more difficult than it probably should be. Fortunately, Gradle also makes it easy to change: build.gradle test { testLogging.showStandardStreams = true } If you&#8217..... Read More › Building "Fat Jars" with Gradle Sep 4 2013 Sometimes, such as when building command line Java apps, it would be nice to bundle all of the app’s dependencies in a single jar so that the user need not collect and manage these. With Gradle, that can be easily accomplished with the following lines: build.gradle jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } } } When you run gradle assemble, you should find..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page13/) ← Newer Posts Older Posts → Filtering Mail using JavaMail Sep 4 2013 At the Lee House, we have an email problem: there’s just too much of it. Over the years of signing up for contests, coupons, and other things, we seem to have amassed a giant number of subscriptions to various lists, which gives us a lot of (usually) junk email. The simple solution, of course, is just to unsubscribe, but some of those are actually occasionally useful. Throw in a pinch of proscratination and..... Read More › WebJars and JSF Aug 28 2013 WebJars, for those that haven’t heard, is a project that takes popular client-side web libraries and packages them in JARs to make their use in Java-/JVM-based web apps simpler. The web site notes that you can easily see which libraries a project is using simply by looking at its dependencies, and that transitive dependencies automatically appear. It’s a pretty compelling project, but, for some reason, it doesn&#8217..... Read More › A Quick-start for Scala and Gradle Aug 22 2013 For those interested, here’s a quick and simple project to get you started using Gradle and Scala together: build.gradle apply plugin: 'scala' repositories{ mavenCentral() mavenLocal() } dependencies{ compile 'org.slf4j:slf4j-api:1.7.5' compile "org.scala-lang:scala-library:2.10.1" testCompile "junit:junit:4.11" } task run(type: JavaExec, dependsOn: classes) { main = 'Main' classpath sourceSets.main.runtimeClasspath classpath configurations.runtime } src/main/scala/Main.scala object Main extends App..... Read More › Gradle, 'provided' scope, and Java EE 7 Aug 22 2013 Maven has a dependency scope, provided, that indicates that the dependency should not be in the archive. Gradle does not provide such a scope out of the box, but it’s easy enough to add. The following Gradle build demonstrates a very bare-bones Java EE 7 web application setup: build.gradle apply plugin: 'war' repositories { mavenCentral() mavenLocal() } configurations { provided } sourceSets { main { compileClasspath += configurations.provided } } dependencies { provided 'javax:javaee-api:7.0' }... Read More › A Simple OAuth2 Client and Server Example: Part II Jul 12 2013 In the last post, we took a look at the server side of our OAuth2 system. In this post, we’ll take a quick look at the unit tests that will act as TheUser. Let’s get right to the code: @RunAsClient public class AuthTest extends Arquillian { @ArquillianResource private URL url; private Client client = JerseyClientBuilder.newClient(); @Deployment public static WebArchive createDeployment() { WebArchive archive = ShrinkWrap.create(WebArchive.class) .addPackages(true, "com.steeplesoft.oauth2") .addAsWebInfResource..... Read More › Setting Up Droidium for Android Testing Jul 12 2013 Many know Arquillian as a great integration, functional, acceptance testing platform. Until recently, I thought of it solely as a great Java EE tool, but an Arquillian extension, known as Droidium, allows you to use Arquillian to help drive your Android testing. I spent some time tonight trying to get it set up for Cub Tracker and thought I’d share what (little) I have so far. Rather than use Ant as the Android..... Read More › A Simple OAuth2 Client and Server Example: Part I Jul 11 2013 When implementing web site security, OAuth2 almost always comes up. We’ve had requests to implement OAuth2 in the GlassFish REST interface, and, it turns out, I have a similar need on a personal project. Looking at the spec, though, OAuth2 can be pretty daunting. Fortunately, you don’t need to understand it all, and Apache has a project, Oltu (nee Amber) that handles most of the implementation. Before we get too excited..... Read More › What's the Deal With Containerless Frameworks? Jul 8 2013 I’ve been spending some time with the Play Framework recently, and one of my first questions was, "Can I deploy this to an app server?", to which the answer is "No. Play is its own container". That (to be honest) somewhat disappointing answer reminded me of some discussions I recenlty saw but mostly ignored about "containerless frameworks". I’m afraid I’m going to have to let my dumb hang out..... Read More › Backing Up Your Data with Duplicity Jun 26 2013 For those wanting to backup their data, there are a myriad of commercial products, ranging from economical to absurdly expensive, from basic to extremely flexible and robust. Depending on your needs, though, you need not spend any money at all to get a pretty poiwerful backup system. In this entry, I’ll show how I backup my workstation using duplicity. Installing duplicity should be as simple as telling yum or apt to install the..... Read More › JavaFX and AsciiDoctor: a Quick and Dirty Hack Apr 30 2013 You may or may not have noticed ([1], [2]), but I’ve been spending a lot of time with AsciiDoc lately. While it might simply be a case of noticing what you’re thinking about, it seems the tool has been gaining more and more momentum. From AsciiDoctor to Awestruct, to Jason Porter’s Maven plugin, it seems to be everywhere. At any rate, in need of a break, I wondered if..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page14/) ← Newer Posts Older Posts → Syncing Playlists with Android Devices Apr 29 2013 While I love my Android devices, one thing that has always bugged me is syncing music with them. Sure, there are some apps that claim to be able to do it, but I’ve never found one that will do what it says and be a decent music player at the same time (perhaps someone out there can point me to a good one). For the most part, then, I’ve settled on..... Read More › Setting Up an Awestruct-based Blog Apr 19 2013 In case you missed the announcement, I recently migrated my blog from Wordpress to Awestruct, the static site generation tool written by several JBoss engineers. As can be expected with a tool this new, there were some bumps and bruises along the way, but I managed — with lots of help — to make it to production with my efforts. To be a good open source citizen, then, I thought I..... Read More › Fairwell, WordPress! Apr 15 2013 Last summer, I put up a quick entry about a new way to blog, which I’ve enjoyed using. After suffering through yet another WordPress security breach (which I’ll admit might be partly my fault through how I have my site set up and "maintained"), I’ve decided to take the next logical step and just move the whole thing to Awestruct. Overall, it’s been an enjoyable process, but..... Read More › DoctorFX Apr 5 2013 Earlier today, I wrote about a quick and dirty hack I put together to create a very simple editor for AsciiDoc files. While I have no immediate plans to make this a full-featured editor, there’s a part of me that can’t help but hack on it. This evening, I added support for loading and saving files. In fact, I’m using the editor to write this post. :) For those..... Read More › Error Reporting for Android Apps Apr 5 2013 As every Android developer knows, application crashes are reported back to Google and can be view in the Play Developer’s Console. This is helpful, but, in my experience, sometimes you don’t get enough context. You also don’t get notifications when crashes are reported. Fortunately, there is a tool, called ACRA, that improves the situation quite a bit. In this post, I’ll give you a brief introduction to..... Read More › Initializing JAX-RS Sub-resources Apr 4 2013 This morning, I was reading through the Proposed Final Draft for JAX-RS 2.0 specification, when I found a little nugget that could have saved me some work, specificially in initializing subresources. This is kind of sad to admit (though, surely — hopefully — I’m not alone in this :), but I have been initializing subresource manually. For example: public <T> T getSubResource(Class<T&gt..... Read More › Writing Bash Scripts with Parameters Apr 2 2013 In the course of my work, I often find myself writing a script to automate a routine task. Almost invariably, there are cases where I need the script to behave in slightly different fashion, but only occassionally. My early scripts rather crudely used one if after, which is not very elegant. Finally, after tiring of this clumsy approach, I searched for a better way and found one: getopts. In this shortish entry, I’ll..... Read More › Simulating Swipes in Your Android Tests Feb 13 2013 As some of you may or may not know, I have small Android project, Cub Tracker, that I’ve been working on for quite some time now in my spare time. I’ve been trying to be better about quicker releases, but all the testing for the app is currently manual (and, therefore, hit-and-miss), so updates tend to be a bit slower and very cautious. (For the record, it used to..... Read More › Oracle JDK and the Linux Alternatives System Jan 15 2013 For both work and fun, I run Linux. I’m also a Java guy, which poses some interesting challenges, as most Linux distributions have a long, sad tale regarding shipping Java. Things are a bit better, I guess, with OpenJDK, but I’ve always liked running the "real thing", which historically meant the Sun JDK, and now Oracle’s JDK (Note: current employment has no bearing on that choice ; ). If I were..... Read More › Merry Christmasi 2012 Dec 25 2012 Merry Christmas! “Do not be afraid; for behold, I bring you good news of great joy which will be for all the people; for today in the city of David there has been born for you a Savior, who is Christ the Lord.” — Luke 2:1-20... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page15/) ← Newer Posts Older Posts → Asynchronous JAX-RS Dec 19 2012 Recently, I had to add support for asynchronous REST calls to the GlassFish REST interface to satisfy some customer requirements. In process of doing so, I learned something pretty interesting: while asynchronous REST may mean different things to different people (e.g., I’m pretty sure Atmosphere provides some sort of REST asynchrony, but I’m not sure what UPDATE #1: As noted in the comments, I know next to nothing about Atmosphere..... Read More › Using Server Sent Events and the GlassFish REST Interface Dec 10 2012 Wikipedia defines Server-Sent Events as "a technology for providing push notifications from a server to a browser client in the form of DOM events. The Server-Sent Events EventSource API is now being standardized as part of HTML5 by the W3C." It’s a great alternative to polling the server for updates. Long story short, thanks to the work of the Jersey team, we have "easy" access to this in GlassFish, and we..... Read More › Maven Project Version from the Command Line Oct 30 2012 A friend asked me today how to get a project’s version out of a Maven POM file without having to read and parse it. A quick Google search brought up the answer, which I thought I’d share here. The short answer is this: $ mvn help:evaluate -Dexpression=project.version [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building GlassFish Admin REST Service 4.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-help-plugin:2..... Read More › Yum Pseudo-Transactions Sep 19 2012 If you follow me on Twitter, you may have seen that I’ve been looking for a good media player. This long, painful process involved installing project Foo, along with its 87 dependencies, only to see that I didn’t like it, then running into the same thing with Bar and Baz. Now I have a ton of packages installed that I don’t need, which will irritate me as I think..... Read More › Converting Many Images to One PDF Sep 5 2012 I recently had the need to convert several scanned images into one multi-page PDF. While there are probably tools to help do this manually, I knew that there was a good chance I’d have to do something like this again, quite possibly with a large number of images, so I did what any good geek would do: I scripted it. In this entry, I’ll show how I went about that..... Read More › Annotation Processing the New Way Jul 25 2012 I recently ran into an issue with our dependency injection system: it won’t return a list of interfaces, only implementations. That system, for what it’s worth, is HK2, but CDI has the same "problem". Since the rest of the system worked using these interfaces, I really wanted to solve the discoverability issue rather than redesigning that part of the system. After considering and playing with a Maven plugin, I opted to..... Read More › A New Way to Blog Jul 16 2012 On the Sunday before the recent JAX conference in San Francisco, I was privileged to attend the Speakers' Summit with many of the other speakers for that week. There was a lot of really good discussions, but the biggest thing I took away from it, or at least the most practical, came from Dan Allen’s lightning talk on documentation and removing the pain. That five minute talk stands a good chance of changing..... Read More › Writing Pluggable Java EE Applications, The Explanation Jul 10 2012 I recently posted the slides and the source code from the presentation I gave at JAXConf San Francisco. While that’s helpful for those who were in my session, it’s probably less so for those who weren’t. What I’ll do in this post, then, is discuss the slides and code in detail, skipping over the introductory slides, and getting right to the heart of the matter. The idea..... Read More › Writing Pluggable Java EE Applications Jul 9 2012 I just finished giving my session at JAXConf San Francisco 2012, "Writing Plugged-In Java EE Apps". I think it went pretty well, though I guess I’ll find out how it really went when the reviews come in. :) Either way, I had a great time. As promised, here is a tar ball that includes the code we looked at during the session, as well as the accompanying slides. Hopefully I’ll be..... Read More › Firefox, Linux, and the Java Plugin Jun 20 2012 In a perfect world, Firefox, Linux and the Java plugin would get along happily. You’d install all three, and things would just work. If memory serves, that’s exactly what happened under Ubuntu. However, after installing Fedora 17, it just didn’t want to work for me (I’m not blaming Fedora, mind you. I like to live on the bleeding edge, so I install Java 7 nightlies from tar..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page16/) ← Newer Posts Older Posts → From OS X to Linux Apr 23 2012 When I joined Sun Microsystems "way back" in 2008, I was asked if I wanted a Mac for my work system. Having heard many extol the numerous virtues of the OS, I jumped at the chance. Since then, I’ve even migrated my wife and family to the OS. Trouble arose last fall, though, with the delivery of a new MacBook Pro (whose purchase was somewhat a miracle, brought about by the tireless efforts..... Read More › Java 7, NetBeans, Mac OS X, and a Little Bit of JavaFX 2 Apr 9 2012 In a recent post showing how to use JavaFX 2 and NetBeans on the Mac, I noted that I have been unable to run NetBeans using Java 7 on my Mac for reasons I had not been able to figure out. Now, thanks to a pointer from Scott Kovatch, the technical lead at Oracle for the Mac OS X port of Java, I think I can show you how to do that. In case you..... Read More › Getting Started with JavaFX on the Mac Apr 5 2012 image::javafx_logo_color_1-300x150.jpg As you may have guessed from my recent book review, I’ve been tinkering with JavaFX some, as time as permitted. I’ve been following the technology fairly closely since Sun announced the project way back in 2008. When it was announced that JavaFX 2.0 was finally available, albeit in preview form, for the Mac, I was ecstatic. I ran into issues, though, trying to get it to..... Read More › Book Review: Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology Apr 3 2012 I was privileged to be given a copy of the recently released Pro JavaFX 2: A Definitive Guide to Rich Clients with Java Technology from Apress, authored by !/JavaFXpert">James Weaver, !/weiqigao">Weiqi Gao, !/steveonjava">Stephen Chin, !/deanriverson">Dean Iverson, Johan Vos. This review is a bit overdue, but I hope you find it as helpful as I found the book. For those looking for a quick summary, here it is: Overall, I thought it..... Read More › GlassFish 3.1.2, REST Security, and the Jersey Client Mar 12 2012 I recently blogged about a change we made in GlassFish 3.1.2 with regard to REST security. Specifically, we added some CSRF protection (you can read the details here). For those of you using the Jersey Client, updating your code to support this change is very simple: import com.sun.jersey.api.client.filter.CsrfProtectionFilter; // ... Client client = new Client(); client.addFilter(new CsrfProtectionFilter()); // ... On the client side, that’s all you have to..... Read More › GlassFish 3.1.2 and REST Security Mar 1 2012 As you may know by now, we released GlassFish 3.1.2 yesterday. Tim Quinn has a nice overview of some of the security-related changes, but one change he didn’t cover was one in the RESTful administration area, namely CSRF protection. I won’t go into the details of what CSRF attack is here, but I do want to show we’ve added protections to GlassFish to make sure the..... Read More › Comparing JVM Web Frameworks - A Critique Feb 15 2012 Recently, Matt Raible again presented his Comparing JVM Web Frameworks, this time at JFokus 2012. The intent of the presentation, as best as I can gather from half a world away, is to prevent some of the major JVM-based web frameworks, showing the various strengths and weaknesses, which will allow the audience to choose a framework more easily. While the goal is laudable, I’m just not sure how well executed the attempt..... Read More › CDI @OKCJUG Feb 14 2012 I had the opportunity today to present an introduction to CDI at the Oklahoma City Java Users Group. It was a smaller crowd, but they had great questions nonetheless. After a rough start in a workspace that wasn’t quite as clean as it should have been, I think the rest went fairly well. I had a good time at least. : ) Thanks to all those that came out and asked questions during and after..... Read More › A Jersey POJOMapping Client/Server Example Jan 26 2012 JAX-RS is the specification that describes how to build RESTful interfaces in a Java EE environment. Jersey is the reference implementation of that spec, and, like many implementations, offers features above and beyond what spec does. One feature that I’ve been working with recently is the POJOMapping feature, which makes writing services and clients much easier, as well as typesafe. In a nutshell, what this feature allows you to do is deal..... Read More › Grabbing Screenshots of Failed Selenium Tests Jan 24 2012 For the GlassFish Administration Console, we have quite a few tests (about 133 at last count). Given the nature and architecture of the application, we’ve chosen Selenium to drive our tests. One of the problems we’ve faced, though, is understanding why a test failed due to the length of time the tests take (roughly 1.5 hours to run the whole suite). Sometimes, we can look at the log and know..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page17/) ← Newer Posts Older Posts → Merry Christmas Dec 25 2011 Merry Christmas I hope everyone who happens to find this site this Christmas season has a very special and blessed time with friends and family. On this geek blog, I think it appropriate to leave you all with a retelling of the Christmas story…​through Facebook. God bless!... Read More › Testing Android Applications with Maven, Android-x86 and VirtualBox Nov 22 2011 Testing Android Applications with Maven, Android-x86 and VirtualBox For a few months now, I’ve been working on a small application called Cub Tracker which is designed to help Cub Scout den and pack leaders track the progress of the scouts assigned them. I’m a big fan of testing, so I’ve done my best to follow TDD as I’ve worked on the app. Early on, it became..... Read More › Book Review: Real World Java EE Night Hacks - Dissecting the Business Tier Nov 14 2011 Book Review: Real World Java EE Night Hacks - Dissecting the Business Tier Last week, a great post by Adam Bien brought his latest book, Real World Java EE Night Hacks - Dissecting the Business Tier, to mind. I have since gotten myself a copy and thought I’d share my thoughts here. For starters, this is a very different kind of book. In the foreword, James Gosling describes it this way (and I’ll..... Read More › Funky Object Initialization Oct 25 2011 Funky Object Initialization I’ve been using a technique a lot, recently, for initializing an object a bit more succinctly. It looks pretty odd, I’ll admit, enough so that it really caught a coworker of mine off guard. If you’ve been reading my recent REST posts, you’ve seen this a few times. I like it a lot, so I thought I’d a take a quick look..... Read More › GlassFish REST Client - ComplexExample.java Oct 25 2011 GlassFish REST Client - ComplexExample.java In a series of recent posts, I’ve shown off what the GlassFish 4.0 REST client wrappers should look like, giving simple examples of using the wrappers using both Java and Python, the two currently supported languages. In this post, we’ll take a look at a more complex example, that of setting up clusters and standalone instances, deploying an app, then cleaning up after ourselves. Let..... Read More › GlassFish REST Client Goes to the Flying Circus Oct 6 2011 GlassFish REST Client Goes to the Flying Circus It happened a bit more quickly than I had planned, and, yes, I know that’s a pretty bad Python joke, but, as promised, I just committed code to add support for generating Python REST clients to the GlassFish RESTful Administration interface. Let’s take a quick look at it. One easy egg to crack! Generating the python client looks strangely similar to how it..... Read More › GlassFish REST Interface, a Client-side Perspective Oct 3 2011 GlassFish REST Interface, a Client-side Perspective As I’ve covered here before, GlassFish sports (and has for a while now), a pretty comprehensive set of management and monitoring REST endpoints. While this goes a long way toward opening up GlassFish management to various scripting solutions, the client side is still pretty manual. One my goals in GlassFish 4.0 is to fix that. In this article, I’m going to give you..... Read More › A Quick (and oh so Brief) Look at a Windows 8 Developer Build Sep 15 2011 A Quick (and oh so Brief) Look at a Windows 8 Developer Build Call me crazy, but I tried Windows 8, albeit a developer build. An entry in my feed reader from TechBargains showed up announcing a free download of a Windows 8 developer build. It was free, so I figured it couldn’t hurt to check it out. After the 4G+ download, I was ready to create my VirtualBox Windows 8 VM, which..... Read More › Android at the OKC JUG Sep 13 2011 Android at the OKC JUG Today, I presented basic Android development at the Oklahoma City JUG. In the presentation, we walked through a very simple (and very ugly) note-taking application. The app allows the user to list, view, add, edit, and delete notes. There are no bells and whistles in the app, as I was trying to find something that is non-trivial enough to be interesting, yet no so complex that the audience..... Read More › My First Android App: Cub Tracker Apr 19 2011 My First Android App: Cub Tracker Over the weekend, I published my first Android application, Cub Tracker. Cub Tracker is really a pretty simple application, but one born out of a personal need. My oldest son is a Cub Scout Wolf, and I am his den leader. There have been countless times where we had been out somewhere, and my wife and I would ask each other, "I wonder if there’s a Cub..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page18/) ← Newer Posts Older Posts → Managing GlassFish JDBC Resources via REST Mar 10 2011 Managing GlassFish JDBC Resources via REST I was asked this morning about creating JDBC resources via REST. As with user management, it’s actually pretty simple, once you’ve seen how. Let’s take a look. To create a JDBC resource, you need two different objects, a JDBC Connection Pool and a JDBC Resource. The endpoints for these two objects are http://localhost:4848/management/domain/resources/jdbc-connection-pool and http..... Read More › Adding Users to a GlassFish Realm via REST Mar 9 2011 Adding Users to a GlassFish Realm via REST A user on the GlassFish forums recently asked how to create users in bulk. The asadmin command create-file-user doesn’t support passing the password as a parameter, which makes scripting difficult. The REST interface, though, can help there, and it’s really pretty simple. The REST endpoint of interest is link: http://localhost:4848/management/domain/configs/config/server-config/security-service/auth..... Read More › Debugging GlassFish REST Requests Mar 4 2011 Debugging GlassFish REST Requests If you’ve been following my series on using the GlassFish REST interface, you’ve probably noticed that your JSON and XML output isn’t pretty-printed like mine. While there are several online tools that can fix that for you, there’s no need for the extra step. GlassFish will do that for you. Let’s look at how to make that happen. To configure..... Read More › GlassFish 3.1 Is Now Available Feb 28 2011 GlassFish 3.1 Is Now Available image::http://glassfish.java.net/image/sparky_3.1_orange.gif[style="float: right; padding: 0px 0px 10px 10px;"] For those that may not have noticed, today the GlassFish team officially released version 3.1. This new release brings in a myriad of features, the most significant of which is probably clustering and high availability. The Aquarium is the best place to find links to blogs, screencasts etc. from various GlassFish..... Read More › RESTful GlassFish Monitoring Feb 28 2011 RESTful GlassFish Monitoring In previous posts, I’ve shown various ways to manage a GlassFish 3.1 server via its REST interface. As nice as that is, we also support monitoring your server via REST as well. In this article, we’ll take a look at some of the things you can ask of your server. If you’re familiar with the management interface, you should be immediately comfortable with the monitoring..... Read More › Java EE's Buried Treasure: the Application Client Container Feb 22 2011 Java EE's Buried Treasure: the Application Client Container From time to time, I’m asked about accessing various EE artifacts (EJBs, etc) from a standalone client. Almost invariably, the user is having trouble getting the environment setup, grabbing an InitialContext, etc. Also almost invariably, my answer to them is "use the application client container", which is as far as I can take them. The topic of application client container, or ACC, came..... Read More › GlassFish 3.1, REST, and a Secured Admin User Feb 17 2011 GlassFish 3.1, REST, and a Secured Admin User In my last post on using the GlassFish REST interface, a commenter asked about how GlassFish handles security. So far, all of my examples have been using GlassFish 3.1 out of the box, which doesn’t require authentication (as a convenience for developers, as well as system admins evaluating the server). In production, of course, the server will be secured, which means our client..... Read More › GlassFish 3.1, REST, and Secure Admin Feb 17 2011 GlassFish 3.1, REST, and Secure Admin After posting my last entry, GlassFish 3.1, REST, and a Secured Admin User, I was asked about an entry on using GlassFish 3.1’s REST interface with secure admin enabled. Some of you may be asking, "Isn’t that what you just wrote about?" While the titles sound the same, they’re slightly different, but in a very significant way. Let’s..... Read More › Deploying Applications to GlassFish Using curl Feb 10 2011 Deploying Applications to GlassFish Using curl Over the past few months, I’ve been posting tips on how to use the REST interface in GlassFish v3 and later to perform various functions. My last post used Scala. In this much briefer and far less ambitious post, I thought I’d share how to deploy an app using curl (from the shell of your choice). If you’re familiar with the REST endpoint..... Read More › Running Long-Running Reports with JMS Jan 25 2011 Running Long-Running Reports with JMS At a recent meeting of the Oklahoma City JUG, I was asked by a member how her group could "script" JSF report generation. After a couple of questions, I figured what she really wanted: she wanted a way to allow users to request reports in an ad hoc manner, as opposed to the reports being run on a schedule. In a general sense, this is a pretty easy question..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page19/) ← Newer Posts Older Posts → Merry Christmas, 2010 Dec 25 2010 Merry Christmas, 2010 I’d like to wish all of my readers a very merry Christmas. It is my hope and prayer that in all the hustle and bustle of the season, that the first Christmas, the birth of the Jesus, the Savior of the world, is not lost. To help with that, I’d like to leave you with some of my current favorite Christmas songs. I hope you enjoy them. God..... Read More › GlassFish Administration: The REST of the Story Part II - Deploying Apps Using Scala Dec 17 2010 GlassFish Administration: The REST of the Story Part II - Deploying Apps Using Scala In a previous post (far too long ago :), I began showing off the RESTful administration API in GlassFish v3. In GlassFish Administration: The REST of the Story Part I, I showed the basics of the API, what to send, what you get back, etc. In this post, I want to show a practical use of the API, namely, deploying an application, and..... Read More › The Value of the Stack Dec 14 2010 The Value of the Stack This morning on twitter, I saw an announcement that Mollom has a new backend, one based on GlassFish. I have to be honest. I don’t know much of anything about Mollom beyond this, nor do I know anything about their previous backend other than it was Java-based. The blog post, though, immediately made me think of dynamic languages. These days, it’s hot to be dynamic..... Read More › Adding SCM Branch Information to Your Prompt Oct 25 2010 Adding SCM Branch Information to Your Prompt UPDATE: I’ve modified the scripts and prompt settings to be a bit more intelligent Today, a coworker sent me a link to an old blog post about adding git and svn branch information to your prompt. As awesome and helpful as that was, my first thought was, "What about hg support?" followed quickly, if not somewhat embarrassingly, by, "What about CVS support?" Thinking it would be..... Read More › Running a Single JUnit Test Oct 5 2010 Running a Single JUnit Test Part of my job as a developer is writing unit tests. Lately, though, I’ve been spending more and more of my time in our tests, which take a long, long time to run. For example, to run the GlassFish Admin Console’s StandaloneTest class, the last run took 17 minutes and 36 seconds. Clearly, something needs to be done to speed that up overall, but I have..... Read More › Interested in Remote Method Calls via JS in JSF? Sep 21 2010 Interested in Remote Method Calls via JS in JSF? One of the nicest enhancements to the JSF specification that 2.0 brought was the inclusion of native Ajax support. It is now extremely simple to Ajaxify a JSF application. One thing that it lacks, though, is the ability to call arbitrary methods on JSF (or CDI?) Managed Beans. There is a project that offers that kind of functionality, and it’s been around for..... Read More › Mojarra 1.2_15 Now In Maven Repo Aug 26 2010 Mojarra 1.2_15 Now In Maven Repo Way back in July, Ed Burns released and announced Mojarra 1.2_15, which is mostly a backport of performance fixes from the 2.0 branch. Given recent changes on the Mojarra team1, there was some confusion and difficulty getting the jars published to the java.net Maven repository. I’m happy to report, though, that we’ve gotten those kinks worked out, and that this new..... Read More › Book Review: JSF 2.0 Cookbook Aug 20 2010 Book Review: JSF 2.0 Cookbook image::https://www.packtpub.com/sites/default/files/imagecache/productview/9522.jpg Packt Publishing recently released a book titled JSF 2.0 Cookbook, by Anghel Leonard. When I first heard about this book, I was really anxious to get my hands on it. I really like the cookbook concept, so I was excited to see a work in that vein published for JSF. Packt recently sent me a copy..... Read More › GlassFish Administration: The REST of the Story Part I Aug 20 2010 GlassFish Administration: The REST of the Story Part I Of the many great things about GlassFish, one that is often mentioned most (and is, in fact, what got me involved with GlassFish as an end user years ago) is the Administration Console. It’s an extremely powerful and capable interface, and is, if I may be so bold, orders of magnitudes better than its open source competition (it may even beat commercial competitors, but..... Read More › Book Review: JSF 1.2 Components Jun 9 2010 Book Review: JSF 1.2 Components Some time ago, I was given a copy of JSF 1.2 Components by Ian Hlavats and asked if I’d write a review for it. It’s long overdue, but here are my thoughts on this book. <img src="http://ecx.images-amazon.com/images/I/51WxF2r1EEL.SL500_AA300.jpg" align="right"/>First off, in case you’re guessing, like I did, based on..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page20/) ← Newer Posts Older Posts → Putting Facelets in a Jar May 4 2010 Putting Facelets in a Jar In a recent forum post, a user asked how to store a Facelets file in a database. Although JSF doesn’t support this out of the box (though it would be a nice feature), it’s not too difficult to add. In this entry, I’ll show you how to serve Facelets from a JAR file, then give some thoughts that will help, I hope, implement a..... Read More › GlassFish Roadmap Mar 26 2010 GlassFish Roadmap There has been a lot of speculation and concern about the fate of GlassFish after the Oracle acquisition. Yesterday, though, we were able to unveil the official roadmap for GlassFish, and I think it looks very promising. In short, not much is going to change with regard to the open source side of things, though there are some changes on the commercially supported offering, which is not unexpected. Some of the highlights include..... Read More › Writing Selenium Tests for the GlassFish Admin Console Mar 25 2010 Writing Selenium Tests for the GlassFish Admin Console One of the results of the Oracle purchase of Sun has been an increased focus on testing — not that we didn’t test GlassFish before, but it was mostly manual in my area of the server. The task of automating this fell to me, and, after a little — ahem — testing, I settled on Selenium. For those that..... Read More › Run GlassFish V3 As a Non-Root Service on Gentoo Linux Mar 4 2010 Run GlassFish V3 As a Non-Root Service on Gentoo Linux Byron Nevins, a colleague of mine here at Oracle, has a couple of nice blog entries showing how to run GlassFish as a service, both as root and non-root users, on Ubuntu or Debian. As a Gentoo user, that doesn’t help me much, unfortunately, but, some time ago, I developed a script that works great for me, so I thought I..... Read More › New Components in Mojarra Scales: Part III – sc:imageZoomer and sc:lightbox Feb 18 2010 New Components in Mojarra Scales: Part III – sc:imageZoomer and sc:lightbox In Part II of this series, I introduced the new auto complete component in Mojarra Scales. In this installment, we’ll take a look at two new closely related components, sc:imageZoomer and sc:lightbox. The first component, sc:imageZoomer, displays a thumbnail, and, when clicked, "zooms" that thumbnail up to the full size image. Here is a sample usage: <sc..... Read More › New Components in Mojarra Scales: Part IV – sc:combo Feb 18 2010 New Components in Mojarra Scales: Part IV – sc:combo Yesterday brought us Part III in our look at some new components in Mojarra Scales. Today, Part IV brings us sc:combo, combination, if you can imagine that, of a h:selectOneMenu and h:inputText. The h:selectOneMenu is a nice control as it allows the application author to limit what the user can enter, thus helping insure data integrity (and sanity). Sometimes, though, it would..... Read More › A Comparison Table of 4 Android Phones Feb 11 2010 A Comparison Table of 4 Android Phones I’ve been an iPhone user for about 1.5 years now. I’m mostly happy with it, but I’d kinda like to write applications for it. The problem, though, is that the iPhone uses Objective-C (and I don’t consider writing web apps the same thing as writing an iPhone app ; ). Enter Google’s Android. I can use my existing..... Read More › Merry Christmas! Dec 25 2009 Merry Christmas! As 2009 winds down to a close, it is my hope that you and your family have a very merry Christmas. It is my prayer that in the hustle and bustle of the season, the real meaning — the birth of the Savior of the world, Jesus Christ — is not lost: Do not be afraid. I bring you good news of great joy that will be for all..... Read More › New Components in Mojarra Scales: Part II – sc:autoComplete Dec 22 2009 New Components in Mojarra Scales: Part II – sc:autoComplete In Part I, I introduced the new YUI-backed Scales dataTable component. In this installment in the series, we"ll take a look at another new component available in Scales 2.0, sc:autoComplete. The auto-complete component is likely very familiar to most seasoned web users. As information is typed into a field on the form, suggestions are displayed in a box that appears below..... Read More › GlassFish v3 Virtual Conference Dec 15 2009 GlassFish v3 Virtual Conference This is a little late notice, but we at Sun are holding a "virtual conference" covering GlassFish v3, Java EE 6, etc. You can find details here. It starts in 30 minutes (10:00 CST, 8:00 PST). :)... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page21/) ← Newer Posts Older Posts → GlassFish v3 Is Now Available Dec 10 2009 GlassFish v3 Is Now Available Today, the GlassFish team is pleased to announce the release of GlassFish v3. This release marks the first production-ready release of a Java EE 6 compliant application server. It also marks the culmination of a tremendous engineering effort to transform the very capable but monolithic GlassFish v2 into a small, sleek and scalable modular system, built on OSGi. You can get all the details over at The Aquarium. Of..... Read More › NetBeans 6.8 Is Now Available Dec 10 2009 NetBeans 6.8 Is Now Available While we’re making product announcements, I might as well mention that NetBeans 6.8 is available today as well. I really think NetBeans is the best Free <del>Java</del> multi-language IDE on the market. It’s by no means perfect, but I like it a lot.1 Quoting from the release: Today Sun and the NetBeans™ community are announcing..... Read More › New Components in Mojarra Scales: Part I - sc:dataTable Dec 5 2009 New Components in Mojarra Scales: Part I - sc:dataTable The migration of Mojarra Scales to JSF 2, adding new components has become much easier due to JSF 2’s new composite component feature. In the past couple of weeks, this new capability has paid off in spades as Mojarra Scales has gotten (so far) three new components in rapid succession. In this, the first part of a multi-part series, we’ll take..... Read More › Setting Up a New Web Site on DreamHost Nov 3 2009 Setting Up a New Web Site on DreamHost As a "computer guy," I get asked to help with all things computer-related. My church’s web site is no different. I was recently asked to help set up a new site. Since my time is limited and they need to get things going without waiting on me, I thought I would document my process for them, simple as it is. It occurred to me..... Read More › The Mojarra Scales Demo Has Moved Nov 2 2009 The Mojarra Scales Demo Has Moved With the recent migration of Mojarra Scales to JSF 2, the old location of the Mojarra Scales demo was no longer adequate (upgrading that server posed some issues). For that reason, I have moved the demo to a new home. This server should be more up-to-date (both in terms of the application as well as the application server — which is GlassFish v3, of course..... Read More › JSF 2, h:dataTable, and Ajax Updates Oct 28 2009 JSF 2, h:dataTable, and Ajax Updates While JSF has had Ajax support for a long time now, it has always been through external libraries such as Ajax4Jsf/RichFaces, ICEfaces, DWR, DynaFaces, etc. With JSF 2, the framework now has first class, standardized support for Ajax. This is good news on several fronts. For those that want Ajax support but would rather not import another library, that capability is now baked in, and, for those..... Read More › Mojarra 2.0 hits FCS Oct 19 2009 Mojarra 2.0 hits FCS Ryan Lubke announced today the availability of the first production-ready JSF 2 implementation with the release of Mojarra 2.0. You can download the binaries directly from java.net, or, use the information Ryan posted for specifying a dependency in your Maven pom file. Congrats to (the rest of) the Expert Group and, of course, the Mojarra development team (Ryan, Jim, Ed and Roger)... Read More › GlassFish v3 FishCAT Announced Sep 23 2009 GlassFish v3 FishCAT Announced During the GlassFish v3 Prelude development cycle, the GlassFish team launched an initiative called FishCAT, which is our Community Acceptance Testing program. The program was very successful for Prelude, resulting in many, many reported (and fixed! : ) issues for the Prelude release. As we press hard toward the release of GlassFish v3 final later this fall, this program has been re-launched to help us engage our user community. Through this program..... Read More › Mojarra Scales 1.3.2 Has Been Released Aug 27 2009 Mojarra Scales 1.3.2 Has Been Released Late last night, I published Mojarra Scales 1.3.2. This is mostly a bug and performance fix, but here are some highlights from the release: <sc:links /> (and related supporting classes and components) was modified to allow files only from /scales to fix a pretty glaring security hole in some scenarios When multiple, local requests for a given resource type (CSS or JS) are..... Read More › FacesTester 0.3 Has Been Released Jul 29 2009 FacesTester 0.3 Has Been Released After a lot of changes and a long delay, I’m pleased to announce that we have released FacesTester 0.3 tonight. This version has a large number of new features. Read on the for details. This release has three major changes: removal of almost all external dependencies, support for Servlet filters and listeners, and support for JSF 2. External Dependencies From the start, we have always depended..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page22/) ← Newer Posts Older Posts → I've Updated My About Page Jun 30 2009 I've Updated My About Page I should note here, for those that don’t follow me on Twitter, that I have updated and expanded my About page, for those that are interested in that sort of thing. A word of warning: There’s some personal stuff in there! :)... Read More › JavaOne 2009 Day 4 Jun 18 2009 JavaOne 2009 Day 4 It just occurred to me that I never posted my final wrap up on JavaOne 2009. While it may be that, at this last date, no one cares anymore, I feel I should finish what I started, even if only for me. With that said, here’s my closing thoughts on what I hope is NOT the last JavaOne. Friday was for me, as it was for many it seems..... Read More › JavaOne 2009 Day 3 Jun 5 2009 JavaOne 2009 Day 3 Day 3 of JavaOne 2009, the last full day of the conference, has come and gone. Like the rest of the crowd, I began to wind down a bit early. For no real good reason, I skipped the open general session this morning, or, rather, skipped most of it. I caught the tail end and got the see .Net and Java web services interoperating (using Metro on GlassFish, by the way..... Read More › JavaOne 2009 Day 2 Jun 4 2009 JavaOne 2009 Day 2 JavaOne 2009 Day 2 has come and gone, so here I sit on day 3 typing my recap. I never promised a punctual report! :) My day started with a talk by Max Katz on using JavaFX and Seam in an app. It was an impressive talk. The Exadel folks have done a lot of hard work in getting the two technologies working together. Next up was a talk by Vivek Pandey..... Read More › JavaOne 2009 Day 1 Jun 3 2009 JavaOne 2009 Day 1 JavaOne 2009 started yesterday. It was a long, fun day which started with an interesting general session and ended, for me, with my very first JavaOne presentation (source and slides linked below). The reviews and reactions to the conference have been pretty interesting. Hopefully, mine will be too. The opening general session started, as last year did, with entertainment. As opposed to the loud, attention-demanding dance team, this year we..... Read More › CommunityOne 2009 Jun 2 2009 CommunityOne 2009 Today was CommunityOne, the free conference that precedes, and this year, runs concurrently with JavaOne. This year, my wife was able to travel out with me for a little vacation after JavaOne concludes. With her CommunityOne pass, she got to attend today’s activities with me, which was a nice change from last year. When we landed in San Francisco, we checked in, ate a quick lunch, then jumped into the sessions..... Read More › JavaServer Faces 2.0 Is Final! May 27 2009 JavaServer Faces 2.0 Is Final! See the Executive Committee for SE/EE vote here. Download Mojarra, the reference implementation, here... Read More › FacesTester 0.2 Has Been Released May 21 2009 FacesTester 0.2 Has Been Released Today we released FacesTester 0.2. While this release has a number of bug fixes and more minor enhancements, one of the biggest new features is injection support. Leveraging the InjectionProvider Service Provider Interface (SPI) provided by Mojarra, FacesTester now supports the automagic injection of mock/test objects. For example, the following managed bean: public class ManagedBeanWithJpa { @PersistenceContext(unitName = "em") private EntityManager entityManager; public EntityManager getEntityManager() { return entityManager; } public..... Read More › Making Tables Harder Than They Need To Be May 13 2009 Making Tables Harder Than They Need To Be I know you’re not supposed to do this, but sometimes it’s just easier. Sometimes I use `table`s to layout out my forms. Especially for big forms, it’s just easier to put things in a table than deal with `label`s, CSS, etc. Right or wrong, I do it from time to time, but, thanks to David Geary, I just learned..... Read More › UPDATED: Web Beans Webinar May 11 2009 UPDATED: Web Beans Webinar On May 19th, Pete Muir, JSF 2.0 Expert Group member and Web Beans implementation lead (if I recall correctly) will be leading, in conjunction with The Aquarium, a webinar covering the forthcoming Java Contexts and Dependency Injection JSR (JSR-299, formerly known by the JSR’s former name, Web Beans). Unfortunately, that’s right in the middle of the Oklahoma City JUG’s meeting, so I can..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page23/) ← Newer Posts Older Posts → Book Review: Practical RichFaces Apr 21 2009 Book Review: Practical RichFaces One of the great strengths and successes, I think, of the JavaServer Faces specification is the proliferation of third party components. One of the older and better known component sets is RichFaces, which started out under a company called Exadel and is now part of JBoss. For many, RichFaces is the first add-on component set for a new JSF project, and with good reason. I recently had the opportunity to..... Read More › Mojarra Scales 1.3.1 Has Been Released Apr 21 2009 Mojarra Scales 1.3.1 Has Been Released Early this morning, I published Mojarra Scales 1.3.1. I’ve been remiss in making good updates where when I make release, so, rather than creating a new post for each release long after the fact, I’ll try to being everyone up to the current state in just one. Much has changed over the past few weeks. We started using Scales in the..... Read More › FacesTester Can Now Test State Saving Apr 13 2009 FacesTester Can Now Test State Saving In my experience, a pretty common bug with custom components is improper state saving. Since JSF components are, currently, stateful, it’s important that custom components integrate with the frameworks state saving mechanism correctly. Unfortunately, it can be an error-prone process, as it’s a manual effort. Now, however, custom component authors can use FacesTester to exercise this aspect of their components to help insure proper..... Read More › Happy Easter Apr 12 2009 Happy Easter In Christ Alone: There in the ground His body lay Light of the world by darkness slain Then, bursting forth in glorious day Up from the grave He rose again And as He stands in victory Sin’s curse has lost it’s grip on me For I am His and He us mine Bought with the precious blood of Christ No guilt in life, no fear in death This is..... Read More › FacesTester 0.1 Released Apr 1 2009 FacesTester 0.1 Released About a month ago, I announced a new project, FacesTester, a JUnit-based testing tool for JSF that my good friend Rod Coffin and I have undertaken. Since then, Rod posted a very nice introduction to FacesTester usage. Today, we made our first official release, FacesTester 0.1. The version number should indicate that it’s still a work in progress, but it is already quite functional (I, for one..... Read More › My JSFCentral Interview Has Been Published Apr 1 2009 My JSFCentral Interview Has Been Published Careful readers of my blog (thank you, dear wife! : ) will remember that I was interviewed at JSFOne by the conference co-founder and JSFCentral founder Kito Mann. That interview, complete with transcript, has been published on JSFCentral. I was a bit nervous about how it would turn out, but I think it turned out pretty well. I’m not a big fan of hearing my recorded voice, but..... Read More › The Maven Release Plugin Is Pretty Slick Apr 1 2009 The Maven Release Plugin Is Pretty Slick Maven catches a lot of flak from a lot of people. I’ve even been known to bemoan some its eccentricities from time to time. Over the past year and a half, though, I’ve done more and more with Maven, and I’m to the point now where that’s all I use. In fact, Maven and Ant have traded positions in my..... Read More › Webinar: From Ajax Push to JSF 2.0: ICEfaces on GlassFish Mar 12 2009 Webinar: From Ajax Push to JSF 2.0: ICEfaces on GlassFish The GlassFish webinar series is, I think, a pretty valuable resource for regular readers of my blog, as it covers a lot of topics that I cover here. Today’s webinar, "From Ajax Push to JSF 2.0: ICEfaces on GlassFish," is particularly relevant, as it’s a JSF-related session. Here’s the abstract: Ted will provide details on how..... Read More › Announcing FacesTester Mar 3 2009 Announcing FacesTester One of the issues that has always troubled me with regard to writing JSF applications (or any web application, really) is how hard it is to test them. Some time ago, while discussing various Java web frameworks, I stumbled across a class called WicketTester, which is part of the Wicket project. Using this class, as best as I can tell, Wicket authors can easily test their applications very quickly. Having taken the advice..... Read More › Opinions Wanted: v3 GUI Prototype Feb 25 2009 Opinions Wanted: v3 GUI Prototype As I mentioned in a recent post, we’re investigating some changes to the GlassFish v3 Administration Console. We finally have something fairly concrete to show, and have set up a demo site for you to play with. Ken Pauslen sent an email regarding our demo to the GlassFish users' list, so instead of repeating all of that, I’ll simply quote his email for you below. Note..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page24/) ← Newer Posts Older Posts → What's Happening In the World of Mojarra Scales? Feb 23 2009 What's Happening In the World of Mojarra Scales? I’ve been a bit silent of late on what’s happening with Mojarra Scales, so I thought I’d take a moment to bring everyone up to speed. For starters, and I guess this is the official announcement of this, I’ve moved the project from java.net to kenai.com. Anyone who has used java.net knows that it..... Read More › Another NetBeans Update Feb 19 2009 Another NetBeans Update Since the announcement in the recent layoffs at Sun on how the NetBeans team was affected, there’s been much concern over the health of the project. I’m not on the NetBeans team (I’m just a big Finkel fan! ;) so I can’t say for certain what’s going on, but it seems to me that Sun is still committed to the platform. Evidence of..... Read More › Leveraging Identity with GlassFish and MySQL Feb 11 2009 Leveraging Identity with GlassFish and MySQL Late last year and early this year, I spent a great deal of time to author/edit a white paper detailing the deployment of Sun Identity Manager using GlassFish and MySQL. The paper, with additional input from Ed Ort, Suveen Nadipalli and John Clingan, gives a brief introduction to what identity management is and why you’d want it, then covers the whats, hows, and whys of MySQL..... Read More › NetBeans Program Update - Feb 2009 Feb 11 2009 NetBeans Program Update - Feb 2009 Are you a NetBeans user? Are you wondering what’s going to happen to your IDE of choice given the recent Sun restructuring? The NetBeans Dream Team Call with Matt Thompson the new Sun NetBeans Director, which starts at 10:00am CST today (I just learned about it too) should answer some of your questions. Here are the details: NetBeans Program Update - Feb 2009 with Matt Thompson (the new..... Read More › Webinar Covering GlassFish's ASadmin Tool Jan 22 2009 Webinar Covering GlassFish’s ASadmin Tool Today at 1:00PM CST, the GlassFish team will host a webinar discussing the asadmin utility that ships with GlassFish. Here’s the official annoucment by Eduardo Pelegri-Llopart (webified be me : This week’s webinar set presents ASadmin, the GlassFish administration CLI. The GlassFish GUI console is well designed and very well appreciated by the users but GUIs are not best for automation and power..... Read More › Free JCP Membership for JUGs Through the End of February Jan 21 2009 Free JCP Membership for JUGs Through the End of February If you are a member of a JUG (or happen to run one) and would like to be able to join the Java Community Process (JCP), you now have two options. For US-based JUGs, you can affiliate yourself with the new umbrella JUG-USA. According to Van Riper of the Silicon Valley JUG and the coordinator of the JUG-USA effort, all you need..... Read More › Mojarra Scales Gets a Z-Order Update Jan 16 2009 Mojarra Scales Gets a Z-Order Update As I noted in a recent entry, we are considering moving to a desktop-like interface for the GlassFish Administration Console, where the content is in separate "windows" (decorated DIVs, basically) which can be moved, closed, minimized, etc. As I’ve started working on a concrete implementation of some of those ideas, I quickly realized that we were going to have issues with multiple, overlapping windows. Once..... Read More › Bootstrapping a JSF 2 project Jan 12 2009 Bootstrapping a JSF 2 project I needed a break this afternoon, so I thought I’d see how easy it is to bootstrap a JSF 2 project. One of the biggest complaints about JSF 1.x is all that XML, so JSF 2 is aiming to fix that. How have we done so far? Based on this quick look (which is my first from-scratch JSF 2 app), really, really well. Here are the..... Read More › My Thoughts on AT&T U-verse Jan 5 2009 My Thoughts on AT&T U-verse In a recent discussion, the fact that I have AT&T U-verse came up. I was asked what my thoughts on it are, and I promised a blog about it. This entry is the somewhat belated fulfillment of the promise. First off, for those that don’t know, U-verse is, as best as I can tell, their answer to cable television. With the..... Read More › JSF 2 Gets Declarative Event Handling Dec 23 2008 JSF 2 Gets Declarative Event Handling If you’ve been following the evolution of the JSF 2 spec closely, you have probably seen the addition of a finer-grained event system (if you haven’t seen it, section 3.4 of the spec is the relevant one). These events include things like AfterAddToViewEvent, BeforeRenderEvent, ViewMapCreatedEvent, etc. An application developer could subscribe to these events from a managed bean by using the API exposed..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page25/) ← Newer Posts Older Posts → Changes Are Coming to the GlassFish Admin Console Dec 16 2008 Changes Are Coming to the GlassFish Admin Console GlassFish isn’t just an application server. It’s a community. For that reason, we on the admin console team want to take some time to run some ideas by the user community. For the GlassFish v3 final release due in the middle of next year, we plan to redesign the admin console. Since the admin console is usually high on the list of differentiators..... Read More › Interested in Servlet 3.0? Dec 15 2008 Interested in Servlet 3.0? If so, you might be interested in the latest webinar from The Aquarium covering Java EE 6 and Servlet 3.0. Spec leads Roberto Chinnici and Rajiv Mordani will be leading the next session covering these two topics. Eduardo has the details... Read More › A One-Man JSF 2 Blog Storm Dec 9 2008 A One-Man JSF 2 Blog Storm As the specification writing part of JSF 2 comes to a close, we’re getting a more complete implementation done on the reference implementation, Mojarra. One of the primary developers on Mojarra is Jim Driscoll (the other being Ryan Lubke, who has done such an excellent job on the 1.2 series). Jim, apparently, has been in a writing mood and has posted a number of very..... Read More › JavaFX 1.0 Release Set for December 4 Dec 2 2008 JavaFX 1.0 Release Set for December 4 With the release of JavaFX 1.0 scheduled for this Thursday, December 4, the JavaFX team set up a technical pre-launch call and invited JUG leaders, Java Champions, NetBeans Dream Team members and others to call in and get a sneak peak at what was coming (audio and slides available here). Josh Marinacci was the engineer on hand to give us the preview. A couple of..... Read More › JSF 2.0 Public Review is online Dec 1 2008 JSF 2.0 Public Review is online The current state of the JSF 2 spec has entered the Public Review phase. If you have any interest in JSF, now is a good time to review what we’ve done in the spec thus far and send feedback, which we will discuss and digest for the Proposed Final Draft due out next. You can find the Public Review here, and you can send your comments..... Read More › NetBeans 6.5, Python Support, and Mac OS X Nov 26 2008 NetBeans 6.5, Python Support, and Mac OS X The NetBeans team recently released version 6.5 of the NetBeans IDE, which I really, really like. They also released an Early Access peek at the Python support coming for NetBeans. Unfortunately, it’s not straightforward to get Python and Java EE support in the same installation. The Python EA release is a complete NetBeans installation, i.e., you can’t just add the..... Read More › Seam, WebBeans and GlassFish Nov 18 2008 Seam, WebBeans and GlassFish For some time now, Sun has made use of Ustream.TV to broadcast webinars covering various topics of interest to GlassFish users. That effort continues on November 20th at 11am PST as Eduardo Pelegri-Llopart hosts Dan Allen, author of Seam in Action to discuss Seam, WebBeans, and GlassFish. Some of WebBeans' companion specs (EJB 3.1 and JSF 2) will also be covered by spec leads Ken Saks..... Read More › Extending the GlassFish v3 Prelude Administration Console Nov 6 2008 Extending the GlassFish v3 Prelude Administration Console Today, the GlassFish community is launching GlassFish v3 Prelude (Release Notes and Quick Start Guide). If you are not familiar with what Prelude is, here is a short write up giving the high level details. In this article, I’d like to focus on the third bullet there, "CLI and administration console extensibility." Specifically, we’ll look at what it takes to create a plugin that..... Read More › GlassFish Day Online Nov 6 2008 One more note (for now :) on GlassFish v3 Prelude. Sun is holding an online event called GlassFish Day, which is a day of short presentations (about 10 minutes each). There will be several presentations throughout the day. To see the schedule and decide which ones are of interest to you, please see this entry from The Aquarium... Read More › I've made the plunge Nov 6 2008 I may have made a mistake, but I’ve joined 2007 and hopped on twitter. You can follow me here, or view my latest updates in the sidebar... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page26/) ← Newer Posts Older Posts → Making Your GlassFish v3 Prelude Administration Console Plugin Pluggable Nov 6 2008 Making Your GlassFish v3 Prelude Administration Console Plugin Pluggable In my last article, I talked about writing plugins for the GlassFish v3 Prelude Administration Console, which showed the various integration types supported out-of-the box by the console, but what if a plugin developer would like to allow <i>other</i> plugins to extend it just like the console itself does. In this short article, we’ll show how..... Read More › Not So Late Breaking News Nov 3 2008 Not So Late Breaking News I’ve been meaning to say something about this for while, now, but I have been a bit busy, and was finally beaten to the punch by Alexis Moussine-Pouchkine over at The Aquarium. Before I go any further, go read Alexis' article, paying particular attention to the "real #1 winner" link. Go ahead. I’ll wait…​ image::https://glassfish.dev.java.net/public/image/glassfish_logo_large..... Read More › The Means Stultify the End Sep 12 2008 The Means Stultify the End From time to time, someone, trying to cut through all the hype and spin, will attempt some sort of statistical analysis to determine which web framework is "winning." The results are almost always disappointing, and not because I don’t agree with the outcome, but because the methodology is so flawed. The most recent attempt I’ve discovered, noble as it is, is no different. If you read..... Read More › JSFOne: Day Two Sep 6 2008 JSFOne: Day Two Day two is over, as I sit here on the morning of the third, despite my best intentions. It was a long day for me, but a good one, overall. Despite my two talks scheduled for that afternoon, I took the time to attend one of the JSFOne sessions presented by Ted Goddard of ICEsoft on "Ajax Push/ICEFaces." Ajax Push is the term ICEsoft prefers for what others call Comet (Ajax..... Read More › JSFOne: Day One Sep 5 2008 JSFOne: Day One I’m actually writing this on day 2, but I was up late working and didn’t get a chance last night, so, without further delay, here are my thoughts on JSFOne day #1. This conference is a little different for me, as I’m speaking at this one. My first day, then, was technically Wednesday night. I finally arrived at the hotel and promptly ran into Chris Schalk..... Read More › JSFOne Looms! Aug 23 2008 JSFOne Looms! JSFOne is just a week and a half away, so if you haven’t done so yet, buy those tickets! The Java Posse recently plugged the show in the Quick News section in what I think might be the greatest 34 seconds in Java Posse history. Listen for yourself. ;) http://www.macromedia.com/go/getflashplayer[Get the Flash Player] to see this player. var so = new SWFObject('https://media.dreamhost.com/mediaplayer..... Read More › Maven and Annotations: Not as Easy as It Should Be Jul 11 2008 Maven and Annotations: Not as Easy as It Should Be Over the past year or so, I’ve been slowly migrating — somewhat accidentally — to Maven. I had even begun migrating the build environment for Scales from Ant to Maven, but hit a huge roadblock: annotation processing. Scales depends heavily on compile-time annotation processing, and the only thing I could find on the web was other people with..... Read More › Quercus on GlassFish via the Update Center Jun 25 2008 Quercus on GlassFish via the Update Center Jim Driscoll wrote a really helpful blog entry regarding the GlassFish Update Center module he wrote for Mojarra. After reading that, I decided to revisit Quercus on GlassFish. Using Jim’s incredibly detailed entry, as well as looking at the code in the Mojarra 2.0 SVN repo, I was able to get an Update Center module working that installs and configures Quercus for you, so now..... Read More › Mojarra Scales 1.0 RC2 is out Jun 23 2008 Mojarra Scales 1.0 RC2 is out I have just uploaded RC2 for Mojarra Scales 1.0, a JSF component set born of the Mojarra Sandbox. This release features a number of bug fixes and a handful of new enhancements. When updating, make sure you grab the latest JSFTemplating snapshot from either its download page or Maven, as there are some bug fixes and features there that Scales needs. You can download the last jar..... Read More › GlassFish, PHP and WordPress Jun 18 2008 GlassFish, PHP and WordPress With all the hype around JRuby, Jython, Scala, Groovy, etc., an oft-overlooked dynamic language with JVM support is PHP. Thanks to the hard work of the folks at Caucho Technology, the Quercus project offers a pure Java implementation of the PHP language, sporting support for a lot of the major PHP-based applications. In this entry, we’ll look at how to configure GlassFish to provide easy PHP support..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page27/) ← Newer Posts Older Posts → Where will you be the first weekend in September? Jun 17 2008 Where will you be the first weekend in September? For those of you that like to hear me speak (and, yes, I’m looking at you, Mom!) I will be at JSFOne, a conference brought to you by the No Fluff Just Stuff team and dedicated to the JSF ecosystem. "JSFOne," you say? That’s what I said when I ran into Kito Mann at JavaOne. He mentioned that he and Jay Zimmerman..... Read More › JSF 2.0 Early Access Review Available Jun 3 2008 JSF 2.0 Early Access Review Available The JSF 2.0 Expert Group (operating under the auspices of JSR 314) has released Early Draft Review 1 of the upcoming revision of the spec. We are soliciting feedback, of course, and the window of opportunity for that runs through July 2. If you want to have some input on the direction of the specification, now is the time to speak up. :) The major changes in this..... Read More › Mojarra Scales 1.0 Release Candidate 1 May 27 2008 Today, I released the first release candidate for Mojarra Scales, the JSF component library I helped create. Rather than repeat myself, I’ll just paste the email announcement here: I am pleased to announce the first release candidate of Mojarra Scales 1.0, a new JSF component set. Mojarra Scales started out as the Sandbox for the JSF RI (now known as Mojarra) and was recently promoted to its own java.net project. The..... Read More › JavaOne 2008: Day 4 May 10 2008 JavaOne 2008: Day 4 Like every other day at JavaOne, Friday started with a general session, this one led by James Gosling. Unlike other days, though, today would be a short one. I was a bit late to session, so I missed what Schwartz, Green, and Melissinos were doing on stage with Gosling, but there was a large piece of artwork handed over. Who knows. Well, apparently over 1,000 people, if I had to..... Read More › JavaOne 2008: Day 3 May 9 2008 JavaOne 2008: Day 3 My day started today with the Intel general session. I went in with low expectations for some reason, but came away pretty pleased. The speaker, Douglas Fisher, Vice President, Software and Solutions Group and General Manager, Systems Software Division of Intel Corporation, talked about how software drives innovation in hardware, which makes possible more interesting things in hardware, which in turn drives more innovation in hardware, and the cycle repeats. Years..... Read More › JavaOne 2008: Day 2 May 8 2008 JavaOne 2008: Day 2 Day 2 of JavaOne is effectively over. As I sit here typing, I have one more event, the hands-on-lab Plug Into GlassFish™ V3 With JavaServer™ Faces and jMaki in about an hour, which should be really good. It’s basically a lab showing how to do what Jerome demoed yesterday afternoon in the general session when he added a feature to the GlassFish admin console. The day has..... Read More › JavaOne 2008: Day 1 May 7 2008 JavaOne 2008: Day 1 Good morning. It’s time for my JavaOne 2008 Day 1 report (though it’s actually the morning of the 2nd day :). Thanks to the graciousness of Sun Microsystems, I’m here on the Java Blogger program, giving me really amazing access and privileges. All I have to do is blog about my experience, which I would have done anyway, so over the next few days, I&#8217..... Read More › JavaOne on Your Google Calendar Apr 29 2008 JavaOne on Your Google Calendar Next week, I’ll be off to JavaOne. With everything that’s going on, I thought it would be nice to have my JavaOne schedule on my Google Calendar, which I could then sync with my phone. Sadly, it wasn’t as easy as I thought it would be (though I certainly could be the failure in the process :). After I imported my schedule into Outlook (used..... Read More › Mojarra Gets Groovy Apr 17 2008 Today, Ryan Lubke committed code to the Mojarra tree that will allow a JSF developer to prototype and/or develop just about every JSF artifact using Groovy. When deployed to the server in development mode, the Groovy file can be changed on disk, and the changes will be picked up automatically, allowing one to avoid the compile/package/deploy cycle that can make Java web development so tedious. Once the artifact is "done," the Groovy..... Read More › Reintroducing the JSFTemplating FileStreamer Mar 18 2008 In a blog entry last year, Ken Paulsen gave a short introduction to the FileStreamer utility in JSFTemplating. Since Scales is now using JSFTemplating to make the component authoring process easier, I have been able to use this facility, allowing me to deprecate some custom code. In the process of making the migration, I’ve made changes to JSFTemplating that will be of benefit to all. In this entry, I’d like to..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page28/) ← Newer Posts Older Posts → Web Profile Wackiness Feb 28 2008 Web Profile Wackiness In a recent blog post, Java EE 6 (JSR 316) specification co-lead Roberto Chinnici discussed the two leading proposals for the web profile in the upcoming Java EE 6 specification (For more information about profiles, one can start with this article on TheServerSide.) The part that caught me by surprise and confuses me greatly is why the inclusion of JavaServer Faces in the web profile would be controversial. Having spoken with..... Read More › A ValueChangeListener Question and Answer Feb 19 2008 A ValueChangeListener Question and Answer At the lunch session of the OKC JUG today, a question was asked about the difference between the valueChangeListener attribute and <f:valueChangeListener/>. That is, <h:selectOneMenu id="optionMenu" value="#\{optionBean.selectedOption}" valueChangeListener="#\{optionBean.optionChanged}" onchange="submit()"> <f:selectItems value="#\{optionBean.optionList}" /> </h:selectOneMenu> and <h:selectOneMenu id="optionMenu" value="#\{optionBean.selectedOption}" onchange="submit()"> <f:selectItems value="#\{optionBean.optionList..... Read More › Dependency Management with Ant and Ivy Jan 17 2008 Dependency Management with Ant and Ivy One of my long-standing complaints with Ant is that project dependency management is non-existent in the core Ant distribution. Many will quickly point to the Maven Ant tasks, but I’ve never been really fond of them for one reason or another. The other advice I often get is to use Ivy, but even after several attempts, I had never gotten Ivy to work. With the..... Read More › Announcing Mojarra Scales Jan 2 2008 Some of you may be wondering what the status is on the RI Sandbox. With the announcement of Project Mojarra, we can finally take the wraps off of Mojarra Scales, the promotion of the RI/Mojarra Sandbox to its own project. There are a few differences between the Sandbox of Scales to note, such as package names, namespace, etc. There has also been a fair amount of refactoring inside the library to simplify the components..... Read More › JSFTemplating and Woodstock: Component Authoring Made Easy Jan 2 2008 JSFTemplating and Woodstock: Component Authoring Made Easy In my last post, I alluded to some refactoring done inside the Sandbox / Scales library to simplify the components' code. If you are interested in learning more about what was done, and how you can apply the same techniques to your own JSF components, please see this article, written by Ken Paulsen and myself, with editing help from Rick Palkovic, which shows how one can use JSFTemplating and..... Read More › Announcing Project Mojarra Dec 5 2007 Announcing Project Mojarra It is with a pretty high degree of excitement that we, the <strike>JSF RI</strike> Mojarra development team, announce Project Mojarra. While the project itself is not new (it’s the same, high quality and stable JSF implementation we’re all familiar with ;), the announcement of the new moniker brings to an end a lengthy, and sometimes frustrating, process of deciding on a name that..... Read More › OC4J Seam Archetype Update Oct 25 2007 OC4J Seam Archetype Update Well, that wasn’t hard. I think I have the redeploy issue fixed, and a shared library was the trick. It appeared that the redeployment issue was due to some odd class loading issue, so I decided to try a shared library. To do that, I create the directory in j2ee/home/shared-lib/hibernate/3.2 and put these jars there: antlr-2.7.6.jar asm-1.5..... Read More › A Seam+JPA/Hibernate on OC4J Maven 2 Archetype Oct 25 2007 A Seam+JPA/Hibernate on OC4J Maven 2 Archetype As a follow-up to my entry on getting a Seam and JPA/Hibernate application running on OC4J, I now have an alpha release of a Maven 2 archetype available for use and testing, with heavy emphasis on testing. Using the archetype is pretty simple (assuming you know how to use Maven 2 archetypes in general): mvn archetype:create -DarchetypeGroupId=com.steeplesoft.maven.archetypes -DarchetypeArtifactId=seam..... Read More › Seam and JPA/Hibernate on OC4J 10.1.3 Oct 17 2007 Seam and JPA/Hibernate on OC4J 10.1.3 On a recent project, the architecture we settled on included JavaServer Faces (no surprise, there, I guess:), JBoss Seam and JPA. The production environment is Oracle’s OC4J, so the stack we chose has to deploy (easily) to that container. While I did get it working, it wasn’t easy, nor was it easily reproducible. Now that the pressures of deadlines have passed, I..... Read More › Rich Web Experience, Day 3 Sep 9 2007 Rich Web Experience, Day 3 The third and final day of the Rich Web Experience has come and gone. Today’s schedule is a bit lighter, with two morning sessions, a keynote at lunch, and workshops in the afternoon, leaving us finished (and done with the conference : ) just before dinner. To be honest, I was a bit distracted this morning, as the Sooners were busy shellacking Miami. Though I couldn’t watch it..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page29/) ← Newer Posts Older Posts → Rich Web Experience, Day 2 Sep 8 2007 Rich Web Experience, Day 2 Day two of RWE turned out to be as good as the first. I started the day with two back-to-back talks on the Google Web Toolkit given by David Geary. Just as entertaining and informative as his JSF talks from yesterday. He describes GWT as (roughly) "the coolest piece of software I have ever seen" and it is pretty cool. I’m still not sold on it..... Read More › Rich Web Experience, Day 1 Sep 7 2007 Rich Web Experience, Day 1 Today, I’m attending No Fluff Just Stuff's "The Rich Web Experience" conference in San Jose. Having had a great experience with NFJS’s Greater Oklahoma Software Symposium, I have high expectations for this conference, and, so far, I’ve not been disappointed. After breakfast and an expert panel discussion, I headed off for the sessions. While they were all good today, a couple stand out..... Read More › JUGs Offer More Than Free Pizza Aug 9 2007 JUGs Offer More Than Free Pizza As regular readers likely know, I am currently serving as the president of the Oklahoma City Java Users Group. One of the things we’ve really been focusing on is getting the word out about our JUG, hoping to increase not only attendance, but the size of our speaker pool as well. Since we’ve really started pushing this effort, I’ve done a fair amount..... Read More › Thank you, Sun Jul 31 2007 Thank you, Sun I’m a bit hesitant to post this as I’m afraid that it may come across as self-congratulatory, which is not my intent at all, but I think Sun deserves an "atta-boy." Recently, Sun sought to reward various contributors who they felt have been a boon to GlassFish. On two different occasions, I have been blessed to be recipient of Sun’s largess. At JavaOne 2007..... Read More › Another RI Sandbox Progress Report Jun 15 2007 Another RI Sandbox Progress Report With some help from Ryan Lubke, a number of issues have been fixed in the RI Sandbox, including: * "Standard" Attribute Support * Update various CSS files * Make the tabs default to something prettier and several minor fixes here and there. Having done that, I’ve bumped the version (which I have been awful at maintain thus the jump from 0.1 to the seemingly arbitrary 0.7) to 0.8..... Read More › Comparing the GlassFish and OC4J Admin Consoles Jun 15 2007 Comparing the GlassFish and OC4J Admin Consoles As I’ve noted previously, a recent job change has required that I become familiar with Oracle’s application server, Oracle Containers for Java, or OC4J. I recently set aside time to set up my OC4J environment to test a prototype I have been working on and have running under GlassFish. After getting the server installed and logging on to the administration console, I was struck..... Read More › RI Sandbox Update: A Blogging Hat Trick Jun 8 2007 RI Sandbox Update: A Blogging Hat Trick For my record setting, third blog in a single day, I thought I’d make a quick update on the state of the RI Sandbox components. Just a couple of days ago, a former coworker started asking questions about my download component, which made me realize that I should probably find some time to do some work on them. As a general rule, they’re all..... Read More › A Quick Administrative Note Jun 7 2007 A Quick Administrative Note I recently made a change that I should probably note here: In mid-May, I left my employer of the past 2+ years, IEC, to join Objectstream as a Software Architect, and for whom I will be working at the FAA’s Mike Monroney Aernoautical Center here in Oklahoma City. While I’m very excited about this opportunity (and have enjoyed the past few weeks), it was not an..... Read More › JSFTemplating: Announcing beta support for Facelets templates Jun 7 2007 JSFTemplating: Announcing beta support for Facelets templates The JSFTemplating team is proud to announce that a new, Facelets-compatible format has been added to JSFTemplating and has reached the beta stage. Not all of the Facelets components are currently supported; those that are currently supported are ui:component, ui:decorate, ui:include, ui:define, and ui:remove, with the addition of a new ui:event, which brings the power of JSFTemplating’s events to..... Read More › Virtual Hosting using Apache and GlassFish May 4 2007 Virtual Hosting using Apache and GlassFish While many have found GlassFish to be a great choice for an internal application server, there are others that would like to push it a bit further, and use it in an ASP/ISP envrionment. Jan Luehe discussed GlassFish’s virtual hosting features in a recent blog entry. What I’d like to do in this entry is take the information that Jan presented, and walk through..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page30/) ← Newer Posts Older Posts → TinyMCE Support in the Sandbox Apr 16 2007 TinyMCE Support in the Sandbox I have just committed preliminary support for the TinyMCE JavaScript HTML editor. There are parts that still don’t work correctly, but it’s a good start. This example markup: <h3>Normal editor</h3> <risb:htmlEditor rows="10" cols="85" value="#\{testBean.editorValue}"/> <h3>Simplified editor</h3> <risb:htmlEditor rows="10" cols="85" value="#\{testBean.editorValue}" themeStyle..... Read More › JSFTemplating Meets Facelets Apr 4 2007 JSFTemplating Meets Facelets I could be wrong, but I think it’s safe to say that most people don’t know about JSFTemplating, which is a pity, as it’s a pretty nice alternate ViewHandler implementation from Ken Paulsen, GlassFish admin console architect. One of the coolest features, I think, is its introduction of templating events (e.g., one can attach a beforeEncode event to a component on a page and have..... Read More › Unit Testing EJBs Mar 27 2007 Unit Testing EJBs As we’ve done more and more EJB development, we’ve had to think pretty hard about how to unit test our beans. We’ve tried a couple of different approaches (including not testing, which I don’t recommend ;), but weren’t ever just real comfortable with the results. I’m pretty happy with the method we’re using now, and it’s so..... Read More › GlassFish Success Stories Mar 26 2007 GlassFish Success Stories Jamey Wood and Shreedhar Ganapathy of GlassFish fame asked me some time ago if I would be interested in filling out a questionnaire describing my company's use of GlassFish. I finally got the questionnaire completed and turned back in, allowing Jamey and Shreedhar to finish up the article, which is now posted here. We’ve been using GlassFish in production since, if I recall correctly, March of last year, well..... Read More › Site Outage Mar 19 2007 Site Outage Some of you may have noticed an extended outage of this site for most of last week. It appears that my provider was having NFS issues which, to my knowledge, are ongoing. They told me they were watching my server hoping it would stabilize, all the while all I wanted was a functional site. I finally got them to move me to another server, and things appear to be back to normal. So..... Read More › Using the Woodstock Sortable Table Feb 27 2007 Using the Woodstock Sortable Table At long last, the Woodstock component set is finally here. At IEC, we have been anxiously awaiting its release for quite some time now, as we’ve been hoping to make use of the sortable data table component it offers, which we have now done. Having done it, allow me to show off the component a bit, as well as explain what I had to do make things work..... Read More › Sandbox Demo and Nightlies Available Feb 23 2007 Sandbox Demo and Nightlies Available Thanks to the generosity of Ryan Lubke, Ed Burns and the javaserver.org folks, the Sandbox demo application, which can be found in the Sandbox source tree, is now available online. There are a couple of known issues with it, but it should give you a good sense of the current state of the components. We also have nightly snapshots of the sandbox source, binaries and demo available on the..... Read More › JSF RI Sandbox FileDownload Component Changes Jan 11 2007 JSF RI Sandbox FileDownload Component Changes Today I checked in a couple of changes to the RI Sandbox file download component that will make the component more flexible, and, therefore, more usable. Before these changes, the only way the component could be used was with one of two "methods:" "inline" (e.g., a PDF embedded in the page), or "download" (which was a link with a text anchor). While this worked, it was pretty limiting..... Read More › Merry Christmas! Dec 26 2006 Merry Christmas! My general rule is that I avoid too much personal stuff here. I have other venues for those interested in that kind of thing, but it would be remiss of me if I did not take the time to wish a merry Christmas to those that read this blog. I truly hope your Christmas season was (and continues to be) a happy one, spent with family and friends. More importantly than that, though..... Read More › Why CakePHP? Dec 15 2006 Why CakePHP? A reader recently asked me why I chose CakePHP over other frameworks, such as Prado, so I thought I’d answer that question briefly. What drew me to CakePHP was the "simplicity." I say that cautiously, as there is a bit of a curve, but there’s very little configuration (i.e., no xml). At the time, all the config files in Prado kinda scared me off. I liked how CakePHP..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page31/) ← Newer Posts Older Posts → Yahoo! UI and JSF Update Dec 14 2006 Yahoo! UI and JSF Update I’ve had several people ask for an update on where things stand with my YUI components and their JSF component wrappers, so I figure I should take the time to answer that question. In terms of the state of the components, I currently have (admittedly basic) support for three components: Calendar, Menu and TreeView. Of the three, the Calendar seems to be the most "complete" in terms of..... Read More › Download and Multi-file Upload JSF Components Dec 7 2006 Download and Multi-file Upload JSF Components At work, we have run into two issues several times: 1) We haves app that create PDFs, and we need our JSF apps to send that to the user, and 2) we need to be able to upload multiple files to one of our JSF apps. The solutions we’ve used have been less than exciting. For the first problem, we’d make the backing bean..... Read More › Using Acegi Security With JSF Nov 9 2006 Using Acegi Security With JSF A question that often comes up in when looking through JSF <a target="blank" href="http://forum.java.sun.com/forum.jspa?forumID=427&start=0">forums</a> or idling on IRC is, "How do I secure my JSF app?" to which, of course, there are a myriad of options. At <a target="blank" href="http://www.iec-okc.com">IEC</a..... Read More › Review: Building Ajax JSF Components Oct 12 2006 Review: Building Ajax JSF Components If you’re doing web development, you have likely at least heard of Ajax, and, if you’re not currently using it, you’ve likely investigated its possible use. One of the tricky aspects of working with a technology like Ajax is integrating it with various frameworks. JavaServer Faces, now a standard part of the Java EE stack, is no different. For both a page and component..... Read More › Two 'Quick' Notes Sep 18 2006 Two 'Quick' Notes I thought I’d take a second to make two quick fairly self-congratulatory announcements: Last Friday, I took and passed the Sun Certified Java Programmer exam. To be honest, going in, I was extremely nervous and wondering if it was worth it, as the practice exams title: "A book for which I give a qualified and hesitant recommendation" were extremely difficult and tended to focus on little, annoying gotchas like..... Read More › A Disappointing Wait Sep 1 2006 A Disappointing Wait Several months ago at work, we evaluated a handful of methods for dependency downloads. We looked at extending our home grown solution, ivy, maven ant tasks, and even the unthinkable: migrating to maven2. In the end, we decided to stay with our home grown solution, as we were led to believe that the next version of ant would have transitive dependency management built in. We concluded that it would be a waste..... Read More › JSF, PhaseListeners, and GET Requests Redux Aug 17 2006 JSF, PhaseListeners, and GET Requests Redux In an earlier post, I detailed how my company got around JSF’s dependence on POST requests in our efforts to implement pretty URLs. While this approach has worked well for us for quite some time, a pretty major flaw in the approach revealed itself to us in the past few days. In the application for which this PhaseListener was written, we display order information for our customer..... Read More › Debugging jsf-extensions Jul 28 2006 Debugging jsf-extensions One of the things that has been frustrating with trying to come up to speed with jsf-extensions is that I just didn’t know where to look in all the Javascript involved to see what was going on. Today, I "watched" as Ed Burns walked a fellow extensions learner through debugging his app. Here’s what I learned. Assuming you’re using it (and if you’re..... Read More › Ajaxifiying JSF Jul 27 2006 Ajaxifiying JSF In October, I will be presenting Ajax at the <a target="_newwindow" href="http://wiki.okcjug.org">Oklahoma City Java Users Group</a>, of which I am a member (and vice president now, by the way, for what that’s worth). As I’ve prepared for that talk, I’ve thought quite a bit about the web apps I write, which are, for the most part..... Read More › The Tyranny of Choice Jun 8 2006 The Tyranny of Choice As I’ve mentioned before, my company is trying to decide if we really need to keep using Spring now that we’re in a "full" JEE environment. As I’ve pondered this over the past few days, I’ve realized (as I figured we would) that the choice is not so simple. Our desire in this evaluation is to try to make the best decision for..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page32/) ← Newer Posts Older Posts → The Front Porch Test Jun 7 2006 The Front Porch Test Everyone knows that one of the most important things a software project is a good name, but coming up with a good name is not easy. To help with the process, we apply what my boss, Mitch, refers to as the front porch test, which is actually a rule of thumb from the pet world. It goes like this: When picking a name for a dog, imagine yourself standing on the..... Read More › Yahoo! UI Meets JavaServer Faces May 25 2006 Yahoo! UI Meets JavaServer Faces In my ongoing efforts to learn the JSF framework as thoroughly as possible, I decided to write a component, but, with the myriad of high quality components available, what was left for me to do? :P At the suggestion of my brother, who has been watching a similar effort underway in the Wicket space, I’ve decided to wrap Yahoo’s UI library. The problem I ran into..... Read More › A Little Less Spring in Our Step? May 22 2006 A Little Less Spring in Our Step? Friday I had an interesting discussion with my boss, Mitch. I have been doing a lot of thinking about Java EE 5 and what it offers, and that has me reevaluating some of our technology decisions. Most notably, which was the bulk of my discussion with Mitch, is, "Do we really need Spring anymore?" Currently, the way we use Spring is simply as a way to wire together..... Read More › SOAP to slsb May 9 2006 SOAP to slsb As part of our migration to GlassFish, one of my tasks is to migrate all of the web services we’ve exposed via Mule to a session bean environment, which won’t be too hard since we only have two such deployments. The code changes are really pretty small, but non-obvious (given my nascent EJB3 knowledge). For those that might be in a similar situation, let’s take..... Read More › Embedding JSF with Winstone May 8 2006 Embedding JSF with Winstone Sometimes, when developing a JSF application, it would be nice not to have to wait for your favorite container to start up. That’s especially true if your container is a full JEE stack like GlassFish or JBoss. Likewise, there are times when you might need to embed a web application in another, say some server process or desktop application. While there are a number of options available, I&#8217..... Read More › FacesUtil: A missing, yet important piece May 8 2006 FacesUtil: A missing, yet important piece A reader brought to my attention that I have never posted the code to FacesUtil, a convenience class used, for example, in my JSF, PhaseListeners, and GET Requests article, so I’ll fix that oversight now. Before I get to the code, though, let me preface it by saying this: This code has grown as several developers have hacked on it, so it my not be consistent, and..... Read More › JSF, PhaseListeners, and GET Requests Apr 25 2006 JSF, PhaseListeners, and GET Requests UPDATE: For a missing piece of code, please see this entry. In one of our applications at work, we needed to be able to deep link to certain pages to allow external applications to get at specific pieces of data, product and order information to be specific. Since JSF 1.x does not support HTTP GET requests, this poses a problem. In order to get (no pun intended) information to..... Read More › MyEclipse and GlassFish Apr 21 2006 MyEclipse and GlassFish My shop has adopted MyEclipse as the standard development environment. Our recent adoption of GlassFish, though, makes things a little difficult for MyEclipse (and likely Eclipse in general) as integration with the app server has not yet landed in any GA release that I’m aware of. This difficulty, however, is not insurmountable. Let’s take a look at how to debug a GlassFish-hosted application using (My)Eclipse. Obviously..... Read More › JIRA and GlassFish Apr 19 2006 JIRA and GlassFish Officially, GlassFish is not a supported platform for JIRA, Atlassian’s extremly popular issue tracker. Since we’re migrating to GlassFish at work, it’s pretty important that we get it the two to work together. As it turns out, it’s really not that bad at all. Here’s what I had to do to get JIRA, PostgreSQL, Active Directory and GlassFish all playing nicely together..... Read More › New Blog Site Apr 19 2006 New Blog Site I have decided to do my blogging here, rather than inside Joomla! on the (mostly working) main site.  I think things will be a bit easier to manage here, with a little less clutter on the main site.  Since I didn’t have much there, that shouldn’t be an issue for anyone at all. :) On the "mostly working" part, an explanation is probably due.  I changed hosts, and just..... Read More › ← Newer Posts Older Posts → ### [posts/index.html](/posts/page33/) ← Newer Posts Last → JSF and Annotations Apr 14 2006 JSF and Annotations Recently at work, we looked, ever so briefly, at a new web framework called Stripes. It looked rather cool, as it was largely annotation-based, but, given its glaring lack of any wide-spread usage, we never seriously considered it. Today, I was on The Server Side (you do read TSS, right? ;) ) and noticed that Struts has released a Java 5 addon. One of the additions is annotation support whose only problem..... Read More › JSF and File Downloads, Take Two Apr 5 2006 JSF and File Downloads, Take Two Yesterday, I detailed some issues I was having getting a JSF app to allow the download of an Excel spreadsheet as the result of a backing bean action being called. My solution involved a servlet and some JavaScript, with just a -pinch- a fistful of kludge. Thanks to the esteemed Mr. Chad Cummings, I have a better solution, and it involves one small change to the backing bean (the..... Read More › JSF and File Downloads Apr 4 2006 JSF and File Downloads At IEC, we have an application used to report inventory counts. Part of the app creates an Excel spreadsheet using POI. The user selects a batch from a select/combo, click on the button, and the server sends them a spreadsheet. The basic work flow is this: Display the page User selects a batch and clicks the button JSF calls the specified action on the backing The backing bean creates the..... Read More › A Java-based 'Playground' App Jul 6 2005 A Java-based 'Playground' App As I’ve noted earlier, I’ve been debating whether or not I should continue PHP development and move to only Java. Part of the process has included writing a web application using some of the newer Java libraries…​ What I needed was something simple to help me try out some of the newer (at least to me) Java libraries. What I came up with is..... Read More › There has to be a decent ORM for PHP Apr 13 2005 There has to be a decent ORM for PHP For quite a while now, I’ve been using PEAR’s DB_DataObject to do data persistence, but I’ve never been quite satisfied with it. As I’ve used Hibernate more and more, I find myself increasingly disappointed with DB_DataObject, so I went searching for a solution. While I haven’t searched real hard, I’ve done some googling, and..... Read More › To PHP or not to PHP... Mar 28 2005 To PHP or not to PHP…​ After years of PHP development, I find myself trying to decide if I should stick with the language…​I have been doing PHP for years; since the PHP3 days. I have found it to be a powerful and flexible language that is easy to code in and deploy. Every web application I have running at home, on this site, or any of the other hand..... Read More › ← Newer Posts Last →