Pages

.

JWebPain

At the last JavaOne, Sun pre-announced a technology that Java developers have been wanting desperately for years: decent browser emulation in a Swing component. The demo (of something called JWebPane) got everyone pretty excited. It looked too good to be true. And now maybe it is.

Mind you, I don't have any kind of inside information to share (I wish I did) and I don't know any more than you do what happened to JWebPane. But it's been missing-in-action ever since the Big Demo. Even Sun's bloggers have gone silent on it. The last known-good Sun blog on JWebPane was Alexy Ushakov's blog of 10 December 2008. Ushakov is the tech lead on JWebPane. He hasn't blogged about it since. And neither has anyone else at Sun, from what I can determine.

I have to wonder, at this point, if JWebPane hasn't been back-burnered in favor of something more important (although I can't imagine what that might be, frankly). I'm starting to think JWebPane might actually be pre-announced a second time, at the next JavaOne.

Here's what we know so far. JWebPane is based on WebKit and (of necessity) uses JNI to glue-through to WebKit. It leverages Java2D for rendering and will support an Events API (among others). Contrary to myth, it doesn't require JavaFX. Some additional details can be seen at http://blogs.sun.com/thejavatutorials/entry/html_component, where (interestingly) the JWebPane project was described as 70% complete back in May 2008.

Some JWebPane sample code is given in this slideshow. Of course, there's no way to use the code since JWebPane isn't available for download, but at least you can see some of the basic usage patterns.

Sun has tried before to provide a degree of HTML rendering capability in various components:
Anyone who has tried to use these prior APIs for anything nontrivial knows what the limitations are. They're substantial.

Currently there are two popular substitutes for the not-yet-ready JWebPane. MozSwing is an integration of XULRunner with Swing and is quite an interesting beast in its own right. The Flying Saucer Project is quite a powerful XHTML-rendering technology, notable for its extensive support of CSS (and its lack of support for JavaScript).

MozSwing has been criticized for being heavyweight (something like 50MB), but I think we can safely assume that JWebPane, if it ever sees the light of day, won't exactly be the anorexic runway model of HTML components. It probably also won't be anyone's idea of elegant or performant (judging only from Sun's history on stuff like this), but we'll see.

If you Google around and visit some forums, you can see that developers (believing Sun's promise of nearly a year ago that JWebPane would be ready in 3 months) have held off on new projects, waiting for JWP's release. This is the tragedy that is Sun, though. Sun exuberantly pre-announces a technology that should have been introduced a decade ago, then fails to deliver on a timely basis, betraying the trust of the very developers it hopes to attract with things like JavaFX.

Let this be a case study for other vendors considering pre-announcing exciting new technologies. Be ready to deliver, or else don't pre-announce. If you pre-announce and don't come through, you've simultaneously destroyed your own credibility and antagonized potential customers. And if you're in the software business and the people you've antagonized are developers, you've done yourself a double disservice. (Generally speaking, the last people you want to antagonize, if you're looking to build mindshare, are developers.)

Let's sum it up this way: When in doubt, don't pre-announce. Instead, keep your mouth wide shut.
reade more... Résuméabuiyad

JMenu's 433 methods

I've referred, in previous posts, to the fact that Java's JMenu class has 433 methods. I pick on the JMenu class sometimes when I need a convenient example of the piggishness of Java or inheritance gone to an extreme. An alphabetized list of all 433 of JMenu's methods is shown below.

Please note that JMenu is at the bottom of a 7-level-deep inheritance chain. Hence, it inherits most of its methods. All of the inherited methods are shown below along with JMenu's own declared methods, which come at the bottom.

I explain how this list was generated (using JavaScript, in Firefox) at the end of the list. Please scroll down.

java.awt.Component.action(java.awt.Event,java.lang.Object)
java.awt.Component.add(java.awt.PopupMenu)
java.awt.Component.addComponentListener(java.awt.event.ComponentListener)
java.awt.Component.addFocusListener(java.awt.event.FocusListener)
java.awt.Component.addHierarchyBoundsListener(java.awt.event.HierarchyBoundsListener)
java.awt.Component.addHierarchyListener(java.awt.event.HierarchyListener)
java.awt.Component.addInputMethodListener(java.awt.event.InputMethodListener)
java.awt.Component.addKeyListener(java.awt.event.KeyListener)
java.awt.Component.addMouseListener(java.awt.event.MouseListener)
java.awt.Component.addMouseMotionListener(java.awt.event.MouseMotionListener)
java.awt.Component.addMouseWheelListener(java.awt.event.MouseWheelListener)
java.awt.Component.bounds()
java.awt.Component.checkImage(java.awt.Image,int,int,java.awt.image.ImageObserver)
java.awt.Component.checkImage(java.awt.Image,java.awt.image.ImageObserver)
java.awt.Component.contains(java.awt.Point)
java.awt.Component.createImage(int,int)
java.awt.Component.createImage(java.awt.image.ImageProducer)
java.awt.Component.createVolatileImage(int,int)
java.awt.Component.createVolatileImage(int,int,java.awt.ImageCapabilities)
java.awt.Component.dispatchEvent(java.awt.AWTEvent)
java.awt.Component.enable(boolean)
java.awt.Component.enableInputMethods(boolean)
java.awt.Component.firePropertyChange(java.lang.String,byte,byte)
java.awt.Component.firePropertyChange(java.lang.String,double,double)
java.awt.Component.firePropertyChange(java.lang.String,float,float)
java.awt.Component.firePropertyChange(java.lang.String,long,long)
java.awt.Component.firePropertyChange(java.lang.String,short,short)
java.awt.Component.getBackground()
java.awt.Component.getBounds()
java.awt.Component.getColorModel()
java.awt.Component.getComponentListeners()
java.awt.Component.getComponentOrientation()
java.awt.Component.getCursor()
java.awt.Component.getDropTarget()
java.awt.Component.getFocusCycleRootAncestor()
java.awt.Component.getFocusListeners()
java.awt.Component.getFocusTraversalKeysEnabled()
java.awt.Component.getFont()
java.awt.Component.getForeground()
java.awt.Component.getGraphicsConfiguration()
java.awt.Component.getHierarchyBoundsListeners()
java.awt.Component.getHierarchyListeners()
java.awt.Component.getIgnoreRepaint()
java.awt.Component.getInputContext()
java.awt.Component.getInputMethodListeners()
java.awt.Component.getInputMethodRequests()
java.awt.Component.getKeyListeners()
java.awt.Component.getLocale()
java.awt.Component.getLocation()
java.awt.Component.getLocationOnScreen()
java.awt.Component.getMouseListeners()
java.awt.Component.getMouseMotionListeners()
java.awt.Component.getMousePosition()
java.awt.Component.getMouseWheelListeners()
java.awt.Component.getName()
java.awt.Component.getParent()
java.awt.Component.getPeer()
java.awt.Component.getPropertyChangeListeners()
java.awt.Component.getPropertyChangeListeners(java.lang.String)
java.awt.Component.getSize()
java.awt.Component.getToolkit()
java.awt.Component.getTreeLock()
java.awt.Component.gotFocus(java.awt.Event,java.lang.Object)
java.awt.Component.handleEvent(java.awt.Event)
java.awt.Component.hasFocus()
java.awt.Component.hide()
java.awt.Component.inside(int,int)
java.awt.Component.isBackgroundSet()
java.awt.Component.isCursorSet()
java.awt.Component.isDisplayable()
java.awt.Component.isEnabled()
java.awt.Component.isFocusOwner()
java.awt.Component.isFocusTraversable()
java.awt.Component.isFocusable()
java.awt.Component.isFontSet()
java.awt.Component.isForegroundSet()
java.awt.Component.isLightweight()
java.awt.Component.isMaximumSizeSet()
java.awt.Component.isMinimumSizeSet()
java.awt.Component.isPreferredSizeSet()
java.awt.Component.isShowing()
java.awt.Component.isValid()
java.awt.Component.isVisible()
java.awt.Component.keyDown(java.awt.Event,int)
java.awt.Component.keyUp(java.awt.Event,int)
java.awt.Component.list()
java.awt.Component.list(java.io.PrintStream)
java.awt.Component.list(java.io.PrintWriter)
java.awt.Component.location()
java.awt.Component.lostFocus(java.awt.Event,java.lang.Object)
java.awt.Component.mouseDown(java.awt.Event,int,int)
java.awt.Component.mouseDrag(java.awt.Event,int,int)
java.awt.Component.mouseEnter(java.awt.Event,int,int)
java.awt.Component.mouseExit(java.awt.Event,int,int)
java.awt.Component.mouseMove(java.awt.Event,int,int)
java.awt.Component.mouseUp(java.awt.Event,int,int)
java.awt.Component.move(int,int)
java.awt.Component.nextFocus()
java.awt.Component.paintAll(java.awt.Graphics)
java.awt.Component.postEvent(java.awt.Event)
java.awt.Component.prepareImage(java.awt.Image,int,int,java.awt.image.ImageObserver)
java.awt.Component.prepareImage(java.awt.Image,java.awt.image.ImageObserver)
java.awt.Component.remove(java.awt.MenuComponent)
java.awt.Component.removeComponentListener(java.awt.event.ComponentListener)
java.awt.Component.removeFocusListener(java.awt.event.FocusListener)
java.awt.Component.removeHierarchyBoundsListener(java.awt.event.HierarchyBoundsListener)
java.awt.Component.removeHierarchyListener(java.awt.event.HierarchyListener)
java.awt.Component.removeInputMethodListener(java.awt.event.InputMethodListener)
java.awt.Component.removeKeyListener(java.awt.event.KeyListener)
java.awt.Component.removeMouseListener(java.awt.event.MouseListener)
java.awt.Component.removeMouseMotionListener(java.awt.event.MouseMotionListener)
java.awt.Component.removeMouseWheelListener(java.awt.event.MouseWheelListener)
java.awt.Component.removePropertyChangeListener(java.beans.PropertyChangeListener)
java.awt.Component.removePropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
java.awt.Component.repaint()
java.awt.Component.repaint(int,int,int,int)
java.awt.Component.repaint(long)
java.awt.Component.resize(int,int)
java.awt.Component.resize(java.awt.Dimension)
java.awt.Component.setBounds(int,int,int,int)
java.awt.Component.setBounds(java.awt.Rectangle)
java.awt.Component.setCursor(java.awt.Cursor)
java.awt.Component.setDropTarget(java.awt.dnd.DropTarget)
java.awt.Component.setFocusTraversalKeysEnabled(boolean)
java.awt.Component.setFocusable(boolean)
java.awt.Component.setIgnoreRepaint(boolean)
java.awt.Component.setLocale(java.util.Locale)
java.awt.Component.setLocation(int,int)
java.awt.Component.setLocation(java.awt.Point)
java.awt.Component.setName(java.lang.String)
java.awt.Component.setSize(int,int)
java.awt.Component.setSize(java.awt.Dimension)
java.awt.Component.show()
java.awt.Component.show(boolean)
java.awt.Component.size()
java.awt.Component.toString()
java.awt.Component.transferFocus()
java.awt.Component.transferFocusUpCycle()
java.awt.Container.add(java.awt.Component,java.lang.Object)
java.awt.Container.add(java.awt.Component,java.lang.Object,int)
java.awt.Container.add(java.lang.String,java.awt.Component)
java.awt.Container.addContainerListener(java.awt.event.ContainerListener)
java.awt.Container.addPropertyChangeListener(java.beans.PropertyChangeListener)
java.awt.Container.addPropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener)
java.awt.Container.areFocusTraversalKeysSet(int)
java.awt.Container.countComponents()
java.awt.Container.deliverEvent(java.awt.Event)
java.awt.Container.doLayout()
java.awt.Container.findComponentAt(int,int)
java.awt.Container.findComponentAt(java.awt.Point)
java.awt.Container.getComponent(int)
java.awt.Container.getComponentAt(int,int)
java.awt.Container.getComponentAt(java.awt.Point)
java.awt.Container.getComponentCount()
java.awt.Container.getComponentZOrder(java.awt.Component)
java.awt.Container.getComponents()
java.awt.Container.getContainerListeners()
java.awt.Container.getFocusTraversalKeys(int)
java.awt.Container.getFocusTraversalPolicy()
java.awt.Container.getLayout()
java.awt.Container.getMousePosition(boolean)
java.awt.Container.insets()
java.awt.Container.invalidate()
java.awt.Container.isAncestorOf(java.awt.Component)
java.awt.Container.isFocusCycleRoot()
java.awt.Container.isFocusCycleRoot(java.awt.Container)
java.awt.Container.isFocusTraversalPolicyProvider()
java.awt.Container.isFocusTraversalPolicySet()
java.awt.Container.layout()
java.awt.Container.list(java.io.PrintStream,int)
java.awt.Container.list(java.io.PrintWriter,int)
java.awt.Container.locate(int,int)
java.awt.Container.minimumSize()
java.awt.Container.paintComponents(java.awt.Graphics)
java.awt.Container.preferredSize()
java.awt.Container.printComponents(java.awt.Graphics)
java.awt.Container.removeContainerListener(java.awt.event.ContainerListener)
java.awt.Container.setComponentZOrder(java.awt.Component,int)
java.awt.Container.setFocusCycleRoot(boolean)
java.awt.Container.setFocusTraversalPolicy(java.awt.FocusTraversalPolicy)
java.awt.Container.setFocusTraversalPolicyProvider(boolean)
java.awt.Container.transferFocusBackward()
java.awt.Container.transferFocusDownCycle()
java.awt.Container.validate()
java.lang.Object.equals(java.lang.Object)
java.lang.Object.getClass()
java.lang.Object.hashCode()
java.lang.Object.notify()
java.lang.Object.notifyAll()
java.lang.Object.wait()
java.lang.Object.wait(long)
java.lang.Object.wait(long,int)
javax.swing.AbstractButton.addActionListener(java.awt.event.ActionListener)
javax.swing.AbstractButton.addChangeListener(javax.swing.event.ChangeListener)
javax.swing.AbstractButton.addItemListener(java.awt.event.ItemListener)
javax.swing.AbstractButton.doClick()
javax.swing.AbstractButton.getAction()
javax.swing.AbstractButton.getActionCommand()
javax.swing.AbstractButton.getActionListeners()
javax.swing.AbstractButton.getChangeListeners()
javax.swing.AbstractButton.getDisabledIcon()
javax.swing.AbstractButton.getDisabledSelectedIcon()
javax.swing.AbstractButton.getDisplayedMnemonicIndex()
javax.swing.AbstractButton.getHideActionText()
javax.swing.AbstractButton.getHorizontalAlignment()
javax.swing.AbstractButton.getHorizontalTextPosition()
javax.swing.AbstractButton.getIcon()
javax.swing.AbstractButton.getIconTextGap()
javax.swing.AbstractButton.getItemListeners()
javax.swing.AbstractButton.getLabel()
javax.swing.AbstractButton.getMargin()
javax.swing.AbstractButton.getMnemonic()
javax.swing.AbstractButton.getModel()
javax.swing.AbstractButton.getMultiClickThreshhold()
javax.swing.AbstractButton.getPressedIcon()
javax.swing.AbstractButton.getRolloverIcon()
javax.swing.AbstractButton.getRolloverSelectedIcon()
javax.swing.AbstractButton.getSelectedIcon()
javax.swing.AbstractButton.getSelectedObjects()
javax.swing.AbstractButton.getText()
javax.swing.AbstractButton.getUI()
javax.swing.AbstractButton.getVerticalAlignment()
javax.swing.AbstractButton.getVerticalTextPosition()
javax.swing.AbstractButton.imageUpdate(java.awt.Image,int,int,int,int,int)
javax.swing.AbstractButton.isBorderPainted()
javax.swing.AbstractButton.isContentAreaFilled()
javax.swing.AbstractButton.isFocusPainted()
javax.swing.AbstractButton.isRolloverEnabled()
javax.swing.AbstractButton.removeActionListener(java.awt.event.ActionListener)
javax.swing.AbstractButton.removeChangeListener(javax.swing.event.ChangeListener)
javax.swing.AbstractButton.removeItemListener(java.awt.event.ItemListener)
javax.swing.AbstractButton.removeNotify()
javax.swing.AbstractButton.setAction(javax.swing.Action)
javax.swing.AbstractButton.setActionCommand(java.lang.String)
javax.swing.AbstractButton.setBorderPainted(boolean)
javax.swing.AbstractButton.setContentAreaFilled(boolean)
javax.swing.AbstractButton.setDisabledIcon(javax.swing.Icon)
javax.swing.AbstractButton.setDisabledSelectedIcon(javax.swing.Icon)
javax.swing.AbstractButton.setDisplayedMnemonicIndex(int)
javax.swing.AbstractButton.setFocusPainted(boolean)
javax.swing.AbstractButton.setHideActionText(boolean)
javax.swing.AbstractButton.setHorizontalAlignment(int)
javax.swing.AbstractButton.setHorizontalTextPosition(int)
javax.swing.AbstractButton.setIcon(javax.swing.Icon)
javax.swing.AbstractButton.setIconTextGap(int)
javax.swing.AbstractButton.setLabel(java.lang.String)
javax.swing.AbstractButton.setLayout(java.awt.LayoutManager)
javax.swing.AbstractButton.setMargin(java.awt.Insets)
javax.swing.AbstractButton.setMnemonic(char)
javax.swing.AbstractButton.setMnemonic(int)
javax.swing.AbstractButton.setMultiClickThreshhold(long)
javax.swing.AbstractButton.setPressedIcon(javax.swing.Icon)
javax.swing.AbstractButton.setRolloverEnabled(boolean)
javax.swing.AbstractButton.setRolloverIcon(javax.swing.Icon)
javax.swing.AbstractButton.setRolloverSelectedIcon(javax.swing.Icon)
javax.swing.AbstractButton.setSelectedIcon(javax.swing.Icon)
javax.swing.AbstractButton.setText(java.lang.String)
javax.swing.AbstractButton.setUI(javax.swing.plaf.ButtonUI)
javax.swing.AbstractButton.setVerticalAlignment(int)
javax.swing.AbstractButton.setVerticalTextPosition(int)
javax.swing.JComponent.addAncestorListener(javax.swing.event.AncestorListener)
javax.swing.JComponent.addNotify()
javax.swing.JComponent.addVetoableChangeListener(java.beans.VetoableChangeListener)
javax.swing.JComponent.computeVisibleRect(java.awt.Rectangle)
javax.swing.JComponent.contains(int,int)
javax.swing.JComponent.createToolTip()
javax.swing.JComponent.disable()
javax.swing.JComponent.enable()
javax.swing.JComponent.firePropertyChange(java.lang.String,boolean,boolean)
javax.swing.JComponent.firePropertyChange(java.lang.String,char,char)
javax.swing.JComponent.firePropertyChange(java.lang.String,int,int)
javax.swing.JComponent.getActionForKeyStroke(javax.swing.KeyStroke)
javax.swing.JComponent.getActionMap()
javax.swing.JComponent.getAlignmentX()
javax.swing.JComponent.getAlignmentY()
javax.swing.JComponent.getAncestorListeners()
javax.swing.JComponent.getAutoscrolls()
javax.swing.JComponent.getBaseline(int,int)
javax.swing.JComponent.getBaselineResizeBehavior()
javax.swing.JComponent.getBorder()
javax.swing.JComponent.getBounds(java.awt.Rectangle)
javax.swing.JComponent.getClientProperty(java.lang.Object)
javax.swing.JComponent.getComponentPopupMenu()
javax.swing.JComponent.getConditionForKeyStroke(javax.swing.KeyStroke)
javax.swing.JComponent.getDebugGraphicsOptions()
javax.swing.JComponent.getDefaultLocale()
javax.swing.JComponent.getFontMetrics(java.awt.Font)
javax.swing.JComponent.getGraphics()
javax.swing.JComponent.getHeight()
javax.swing.JComponent.getInheritsPopupMenu()
javax.swing.JComponent.getInputMap()
javax.swing.JComponent.getInputMap(int)
javax.swing.JComponent.getInputVerifier()
javax.swing.JComponent.getInsets()
javax.swing.JComponent.getInsets(java.awt.Insets)
javax.swing.JComponent.getListeners(java.lang.Class)
javax.swing.JComponent.getLocation(java.awt.Point)
javax.swing.JComponent.getMaximumSize()
javax.swing.JComponent.getMinimumSize()
javax.swing.JComponent.getNextFocusableComponent()
javax.swing.JComponent.getPopupLocation(java.awt.event.MouseEvent)
javax.swing.JComponent.getPreferredSize()
javax.swing.JComponent.getRegisteredKeyStrokes()
javax.swing.JComponent.getRootPane()
javax.swing.JComponent.getSize(java.awt.Dimension)
javax.swing.JComponent.getToolTipLocation(java.awt.event.MouseEvent)
javax.swing.JComponent.getToolTipText()
javax.swing.JComponent.getToolTipText(java.awt.event.MouseEvent)
javax.swing.JComponent.getTopLevelAncestor()
javax.swing.JComponent.getTransferHandler()
javax.swing.JComponent.getVerifyInputWhenFocusTarget()
javax.swing.JComponent.getVetoableChangeListeners()
javax.swing.JComponent.getVisibleRect()
javax.swing.JComponent.getWidth()
javax.swing.JComponent.getX()
javax.swing.JComponent.getY()
javax.swing.JComponent.grabFocus()
javax.swing.JComponent.isDoubleBuffered()
javax.swing.JComponent.isLightweightComponent(java.awt.Component)
javax.swing.JComponent.isManagingFocus()
javax.swing.JComponent.isOpaque()
javax.swing.JComponent.isOptimizedDrawingEnabled()
javax.swing.JComponent.isPaintingForPrint()
javax.swing.JComponent.isPaintingTile()
javax.swing.JComponent.isRequestFocusEnabled()
javax.swing.JComponent.isValidateRoot()
javax.swing.JComponent.paint(java.awt.Graphics)
javax.swing.JComponent.paintImmediately(int,int,int,int)
javax.swing.JComponent.paintImmediately(java.awt.Rectangle)
javax.swing.JComponent.print(java.awt.Graphics)
javax.swing.JComponent.printAll(java.awt.Graphics)
javax.swing.JComponent.putClientProperty(java.lang.Object,java.lang.Object)
javax.swing.JComponent.registerKeyboardAction(java.awt.event.ActionListener,java.lang.String,javax.swing.KeyStroke,int)
javax.swing.JComponent.registerKeyboardAction(java.awt.event.ActionListener,javax.swing.KeyStroke,int)
javax.swing.JComponent.removeAncestorListener(javax.swing.event.AncestorListener)
javax.swing.JComponent.removeVetoableChangeListener(java.beans.VetoableChangeListener)
javax.swing.JComponent.repaint(java.awt.Rectangle)
javax.swing.JComponent.repaint(long,int,int,int,int)
javax.swing.JComponent.requestDefaultFocus()
javax.swing.JComponent.requestFocus()
javax.swing.JComponent.requestFocus(boolean)
javax.swing.JComponent.requestFocusInWindow()
javax.swing.JComponent.resetKeyboardActions()
javax.swing.JComponent.reshape(int,int,int,int)
javax.swing.JComponent.revalidate()
javax.swing.JComponent.scrollRectToVisible(java.awt.Rectangle)
javax.swing.JComponent.setActionMap(javax.swing.ActionMap)
javax.swing.JComponent.setAlignmentX(float)
javax.swing.JComponent.setAlignmentY(float)
javax.swing.JComponent.setAutoscrolls(boolean)
javax.swing.JComponent.setBackground(java.awt.Color)
javax.swing.JComponent.setBorder(javax.swing.border.Border)
javax.swing.JComponent.setComponentPopupMenu(javax.swing.JPopupMenu)
javax.swing.JComponent.setDebugGraphicsOptions(int)
javax.swing.JComponent.setDefaultLocale(java.util.Locale)
javax.swing.JComponent.setDoubleBuffered(boolean)
javax.swing.JComponent.setFocusTraversalKeys(int,java.util.Set)
javax.swing.JComponent.setFont(java.awt.Font)
javax.swing.JComponent.setForeground(java.awt.Color)
javax.swing.JComponent.setInheritsPopupMenu(boolean)
javax.swing.JComponent.setInputMap(int,javax.swing.InputMap)
javax.swing.JComponent.setInputVerifier(javax.swing.InputVerifier)
javax.swing.JComponent.setMaximumSize(java.awt.Dimension)
javax.swing.JComponent.setMinimumSize(java.awt.Dimension)
javax.swing.JComponent.setNextFocusableComponent(java.awt.Component)
javax.swing.JComponent.setOpaque(boolean)
javax.swing.JComponent.setPreferredSize(java.awt.Dimension)
javax.swing.JComponent.setRequestFocusEnabled(boolean)
javax.swing.JComponent.setToolTipText(java.lang.String)
javax.swing.JComponent.setTransferHandler(javax.swing.TransferHandler)
javax.swing.JComponent.setVerifyInputWhenFocusTarget(boolean)
javax.swing.JComponent.setVisible(boolean)
javax.swing.JComponent.unregisterKeyboardAction(javax.swing.KeyStroke)
javax.swing.JComponent.update(java.awt.Graphics)
javax.swing.JMenu.add(java.awt.Component)
javax.swing.JMenu.add(java.awt.Component,int)
javax.swing.JMenu.add(java.lang.String)
javax.swing.JMenu.add(javax.swing.Action)
javax.swing.JMenu.add(javax.swing.JMenuItem)
javax.swing.JMenu.addMenuListener(javax.swing.event.MenuListener)
javax.swing.JMenu.addSeparator()
javax.swing.JMenu.applyComponentOrientation(java.awt.ComponentOrientation)
javax.swing.JMenu.doClick(int)
javax.swing.JMenu.getAccessibleContext()
javax.swing.JMenu.getComponent()
javax.swing.JMenu.getDelay()
javax.swing.JMenu.getItem(int)
javax.swing.JMenu.getItemCount()
javax.swing.JMenu.getMenuComponent(int)
javax.swing.JMenu.getMenuComponentCount()
javax.swing.JMenu.getMenuComponents()
javax.swing.JMenu.getMenuListeners()
javax.swing.JMenu.getPopupMenu()
javax.swing.JMenu.getSubElements()
javax.swing.JMenu.getUIClassID()
javax.swing.JMenu.insert(java.lang.String,int)
javax.swing.JMenu.insert(javax.swing.Action,int)
javax.swing.JMenu.insert(javax.swing.JMenuItem,int)
javax.swing.JMenu.insertSeparator(int)
javax.swing.JMenu.isMenuComponent(java.awt.Component)
javax.swing.JMenu.isPopupMenuVisible()
javax.swing.JMenu.isSelected()
javax.swing.JMenu.isTearOff()
javax.swing.JMenu.isTopLevelMenu()
javax.swing.JMenu.menuSelectionChanged(boolean)
javax.swing.JMenu.remove(int)
javax.swing.JMenu.remove(java.awt.Component)
javax.swing.JMenu.remove(javax.swing.JMenuItem)
javax.swing.JMenu.removeAll()
javax.swing.JMenu.removeMenuListener(javax.swing.event.MenuListener)
javax.swing.JMenu.setAccelerator(javax.swing.KeyStroke)
javax.swing.JMenu.setComponentOrientation(java.awt.ComponentOrientation)
javax.swing.JMenu.setDelay(int)
javax.swing.JMenu.setMenuLocation(int,int)
javax.swing.JMenu.setModel(javax.swing.ButtonModel)
javax.swing.JMenu.setPopupMenuVisible(boolean)
javax.swing.JMenu.setSelected(boolean)
javax.swing.JMenu.updateUI()
javax.swing.JMenuItem.addMenuDragMouseListener(javax.swing.event.MenuDragMouseListener)
javax.swing.JMenuItem.addMenuKeyListener(javax.swing.event.MenuKeyListener)
javax.swing.JMenuItem.getAccelerator()
javax.swing.JMenuItem.getMenuDragMouseListeners()
javax.swing.JMenuItem.getMenuKeyListeners()
javax.swing.JMenuItem.isArmed()
javax.swing.JMenuItem.processKeyEvent(java.awt.event.KeyEvent,javax.swing.MenuElement[],javax.swing.MenuSelectionManager)
javax.swing.JMenuItem.processMenuDragMouseEvent(javax.swing.event.MenuDragMouseEvent)
javax.swing.JMenuItem.processMenuKeyEvent(javax.swing.event.MenuKeyEvent)
javax.swing.JMenuItem.processMouseEvent(java.awt.event.MouseEvent,javax.swing.MenuElement[],javax.swing.MenuSelectionManager)
javax.swing.JMenuItem.removeMenuDragMouseListener(javax.swing.event.MenuDragMouseListener)
javax.swing.JMenuItem.removeMenuKeyListener(javax.swing.event.MenuKeyListener)
javax.swing.JMenuItem.setArmed(boolean)
javax.swing.JMenuItem.setEnabled(boolean)
javax.swing.JMenuItem.setUI(javax.swing.plaf.MenuItemUI)


How This List Was Generated
I ran the following lines of JavaScript in my Firebug console:


jmenu = new Packages.javax.swing.JMenu( );

methods = jmenu.getClass( ).getMethods( );

r = /j[^( ]+\([^)]*\)/; // match just the method

for (var i = 0,
jsArray=[],
name = ""; i < methods.length; i++ ) {

name = methods[ i ].toString( );
jsArray.push( name.match( r )[ 0 ] );
}

markup = jsArray.sort( ).join( "<br/>" );
document.body.innerHTML = markup;


The key thing to understand is that you can call Java from JavaScript, in Firefox, using the Packages syntax (as shown above). Security restrictions will keep you from doing anything too interesting with scripted Java, but it's noteworthy that you can at least instantiate Java objects, including Swing objects, this way.

BTW, if you find a Java class that has more than 433 methods (clue: I do know of one more Swing class that has > 433 methods), let me know what it is. I'll credit you here.
reade more... Résuméabuiyad

Google Map of Google Data Centers

reade more... Résuméabuiyad

JavaScript needs Elvis

I submitted an enhancement request to the Mozilla folks yesterday. My request? Add an Elvis operator to JavaScript.

If you program in Groovy, you already know what I'm talking about, and it has nothing to do with impersonators or Las Vegas.

If you're not familiar with the Elvis operator, here's the text of my enhancement request to Mozilla:
An Elvis operator similar to Groovy's (which is also being considered for
Scala, and is in the vein of C#'s null-coalescence operator) would add
significant value to JavaScript by letting coders write safer scripts with very
little added effort.

Please see
http://groovy.codehaus.org/Operators#Operators-ElvisOperator%28%3F%3A%29 for a
description.

Basically, Elvis is a collapsed version of the Java/C ternary operator:

return user ?: "Anonymous"; // if user is null, use "Anonymous"

(Allows a function that's supposed to return a String to always return a String
and never return undefined or null.)

function cat(b,c) { return (b?:"") + (c?:"") ; }


Calling cat() with zero or one args still produces a safe return value; caller
needn't check for null or undefined; function needn't contain arg-sanity
checks.

In short, the availability of an Elvis operator makes sanity-injection easy and
will improve the robustness of scripts in the wild as people start to use it.
Alas, Brendan Eich summarily dismissed my suggestion, saying that "idiomatic JS already uses || for the same purposes, but admitting other 'falsy' values than null and undefined."

Eich offered the following illustration:

function cat(b,c) { return (b || "") + (c || ""); }


To which I say: Yes, of course, that sort of kludgy thing works and people use it all the time. But is it right?

While I can appreciate Eich not wanting to "junk up" JavaScript with new operators, I think using the logical-OR operator in the foregoing hacky way does nothing to make code more readable or preserve ||'s original semantics, IMHO. That's the whole point of having a separate operator. The semantics are unambiguous (to a human being, which is what counts; never mind the interpreter).

I'm not alone in this opinion. See Scala Elvis discussion. See also the discussion of null convenience operators for the Fan OO language. See also Stephen Colebourne's excellent discussion of a proposed Elvis syntax for null handling in Java. See also the C# null-coaslescence operator.

I respect Brendan Eich more than apple pie itself, but I think it's significant that others have already considered his argument and found it wanting.

There's still much to recommend Elvis. Java could certainly benefit from it. How many lines of sanity-checking code have people written at the start of a method to to see if arguments are null? More important: How many lines of such code have not been written (through sheer oversight), resulting in mayhem later? (Let he who is without sin throw the first NullPointerException.)

While we're at it, I think Java could use a safe property accessor (a la Groovy):

theName = user?.name; // gives null, not NPE, if name is null


Colebourne has published data (acquired at Devoxx) showing that better null handling is the No. 1 most requested feature by Java programmers. The actual whiteboard photo from the data-gathering session is here (warning: large image).

When programmers beg for a simple syntax feature that makes the language safer and easier to read (while eliminating tedious sanity-checking boilerplate), why not put the feature into the language? What justification could there be for not doing so? Who benefits by keeping a feature out of the language that would cut down on null pointer exceptions?

Does JavaScript (and Java) need Elvis? I'm convinced it does. What do you think?

Thank you . . . Thank you very much.
reade more... Résuméabuiyad

Programmer Personas

I came across an interesting (and short) paper by Microsoft user experience guru Steven Clarke called "What Is an End User Software Engineer?" It discusses the idea of programmer personas and how Microsoft has leveraged that concept to (re)design Visual Studio and various APIs for better usability.

A persona captures assumptions around work styles and motivations. Not all programmers are motivated by the same things or have the same goals. A sales engineer might have a different set of problems to solve than a senior developer in R&D, and might be accustomed to working in quite a different way. Yet both may have to code against the same libraries using the same tools. Is it possible to satisfy both groups of programmer-users? Are there API-design or tool-design best practices that apply across the board regardless of persona type? What do we know about the things that work for one programmer persona but not another?

The formulation of persona types is obviously somewhat arbitrary, but it's interesting that Microsoft did go to the trouble to observe programmers working not only in usability labs but in their "natural habitats" over a period of 12 months in order to arrive at three main personas:
  • THE SYSTEMATIC DEVELOPER: Writes code defensively. Does everything he or she can to protect code from unstable and untrustworthy processes running in parallel with their code. Develops a deep understanding of a technology before using it. Prides himself or herself on building elegant solutions.
  • THE PRAGMATIC DEVELOPER: Writes code methodically. Develops sufficient understanding of a technology to enable competent use of it. Prides himself or herself on building robust applications.
  • THE OPPORTUNISTIC DEVELOPER: Writes code in an exploratory fashion. Develops a sufficient understanding of a technology to understand how it can solve a business problem. Prides himself/herself on solving business problems.
Clarke discusses Microsoft's usability philosophy in greater detail in a 2005 Dr Dobbs Journal article that I think is still quite relevant today. Check it out when you get a chance.

For people in the tooling and API-design business, there's a lot to think about here. Ask yourself: Do you know what the personas of your users might be like? Are you taking that information into account in your API, SDK, and tool designs? Do you do serious usability testing of your APIs and development tools before putting them in the hands of customers? If not, why not?

Giving programmers usable tools, it seems to me, is the first step to making programmers more productive. And that benefits everyone.
reade more... Résuméabuiyad

Why do we still have vendor lock-in?

There's a common myth that one of the main reasons enterprise customers get locked in to a particular vendor's technology is the huge investment (of time and money) that goes into specifying, procuring, rolling out, and maintaining a large system.

I was talking to a financial analyst the other day about this very phenomenon. The name of a well-known CMS vendor came up. My financial-analyst friend -- somewhat new to the software biz -- asked whether the huge cost of rolling out, training for, and maintaining a large system didn't pose an enormous disincentive for customers considering moving to another system. I said no, that's a myth.

"That's the amazing thing about this business," I said. "People walk away from million-dollar systems all the time."

It's not hard to understand. If an expensive system is draining you dry, you have to stop the bleeding. Sometimes the best way to do that is to stop throwing money at a bad solution and move on.

"But how do you walk away from an investment of X-million dollars?" my financial-analyst friend wanted to know.

First of all, understand that capital expenditures are depreciated over time. From an accounting point of view, investments in software are "walked away from" routinely; it's a given. The real question isn't whether you can afford to write off a bad investment, but what it will cost (in current dollars) to move to a new system.

The impediments to moving to a new system can be many, but typically, lock-in occurs because data is "interred" in proprietary formats (making migration to a new system costly), or because large amounts of custom-written application code will need to be ported (at great cost) to the new system. Or both.

Data lock-in happens in funny ways. You can have all your content in standard industry formats (XML, JPG, PDF) and still be locked into a content management system very tightly by virtue of the system's metadata mappings or database schemas, or by virtue of the system's use of a template structure or dynamic page language that's proprietary.

The existence of large amounts of custom-written application code is also a serious problem. It may not even be possible (even in theory) to port code from the old system to a new one, if the APIs and abstraction levels are far enough apart. You may well end up having to rewrite some or all of your custom apps from scratch. And that can get very expensive very quickly.

In sum: The high cost of data and code migration remain serious impediments to moving off of existing systems. Which presents an opportunity, of sorts, for vendors.

If you're a vendor and you want to convince someone to buy a new system, make it attractive for them to move off their old system. At a bare minimum:

1. Provide good data migration utilities. Take the pain out of migration.

2. Since customers will be rewriting and/or walking away from large amounts of legacy code, provide rapid application development tools -- including powerful code libraries and easy-to-learn APIs -- that enable new customers to put custom apps together quickly. (This is a hugely important topic that deserves much more attention than I can give it here.)

3. Give customers a licensing option that doesn't lead to high first-year costs. Offer a pay-as-you-go option. Customers don't like to write large checks in Year One.

4. Make your software less hardware-intensive than the incumbent's, so that your customer can get by on fewer CPUs, less RAM, less disk storage, etc. If you can save your customer a few hardware-budget dollars, he or she may be more likely to reallocate some of those dollars to software.

5. Make the administration experience easy. If you can prove that your system entails less administrative burden (and you can document the cost savings in terms of headcount reduction), it can help make the case for moving to a new system.

One thing is certain: Now is not the time to be selling big, old-fashioned middleware systems the old-fashioned way. People aren't willing (or able, in this economy) to spend a million dollars to be vendor-locked to a "solution" that's hard to migrate data and applications into or out of. As I said last October, the days of the million-dollar whITe elephant are drawing to a close. After this recession is over, there will be fewer species than before. I think we all know that.
reade more... Résuméabuiyad

Cuil not so cool any more

There's a graph of declining Cuil traffic numbers at Alexa.com that you'd think would have Cuil's investors jumping off the top of the nearest tall building. (Be sure to check out all 3 tabs: Reach, Rank, and Page Views. They're all terrifying.)

The Internet-surfing public has voted with their feet on this one, I'd say. What's odd is that the downtrend has been in progress for quite some time, yet Cuil's designers have done nothing to try to stem the exodus. Have they not heard of A/B testing? Does anyone at Cuil know anything about analytics? Maybe they've been trying like heck to stop the bleeding and we just don't know it.

Whatever. The kid in The Sixth Sense can now say "I see abandoned search engines..."
reade more... Résuméabuiyad