From 32bb0e9c211961fbade190535b8041ece5df772c Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Sat, 12 Aug 2006 13:27:52 +0000 Subject: 2006-08-12 Andrew John Hughes * Merge of HEAD --> generics-branch for release 0.92 to 2006/08/12. --- .classpath | 2 +- ChangeLog | 989 +++++++++- INSTALL | 9 + NEWS | 8 + configure.ac | 70 +- gnu/CORBA/Connected_objects.java | 10 + gnu/CORBA/OrbFunctional.java | 10 + .../awt/dnd/peer/gtk/GtkDragSourceContextPeer.java | 12 +- .../awt/dnd/peer/gtk/GtkDropTargetContextPeer.java | 6 +- gnu/java/awt/peer/GLightweightPeer.java | 221 ++- gnu/java/awt/peer/gtk/BufferedImageGraphics.java | 9 +- gnu/java/awt/peer/gtk/CairoGraphics2D.java | 10 +- gnu/java/awt/peer/gtk/CairoSurface.java | 74 +- gnu/java/awt/peer/gtk/ComponentGraphics.java | 52 +- gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java | 8 +- gnu/java/awt/peer/gtk/GtkChoicePeer.java | 101 +- gnu/java/awt/peer/gtk/GtkComponentPeer.java | 4 +- gnu/java/awt/peer/gtk/GtkMainThread.java | 97 + gnu/java/awt/peer/gtk/GtkToolkit.java | 30 +- gnu/java/awt/peer/gtk/GtkWindowPeer.java | 6 + gnu/java/lang/management/BeanImpl.java | 444 ++++- gnu/java/net/protocol/http/Request.java | 15 +- gnu/javax/naming/giop/ContextContinuation.java | 956 ++++++++++ gnu/javax/naming/giop/CorbalocParser.java | 439 +++++ gnu/javax/naming/giop/GiopNamingEnumeration.java | 187 ++ .../naming/giop/GiopNamingServiceFactory.java | 177 ++ .../naming/giop/GiopNamingServiceURLContext.java | 840 +++++++++ gnu/javax/naming/giop/ListBindingsEnumeration.java | 116 ++ gnu/javax/naming/giop/ListEnumeration.java | 116 ++ gnu/javax/naming/ictxImpl/trans/GnuName.java | 467 +++++ .../url/corbaname/corbanameURLContextFactory.java | 53 + .../naming/jndi/url/rmi/ContextContinuation.java | 597 ++++++ .../jndi/url/rmi/ListBindingsEnumeration.java | 97 + gnu/javax/naming/jndi/url/rmi/ListEnumeration.java | 80 + gnu/javax/naming/jndi/url/rmi/RmiContinuation.java | 594 ++++++ .../naming/jndi/url/rmi/RmiNamingEnumeration.java | 130 ++ gnu/javax/naming/jndi/url/rmi/rmiURLContext.java | 637 +++++++ .../naming/jndi/url/rmi/rmiURLContextFactory.java | 66 + include/GtkDragSourceContextPeer.h | 2 +- include/gnu_java_awt_peer_gtk_ComponentGraphics.h | 2 +- include/gnu_java_awt_peer_gtk_GtkChoicePeer.h | 3 +- include/gnu_java_awt_peer_gtk_GtkToolkit.h | 1 + java/awt/BasicStroke.java | 154 +- java/awt/CardLayout.java | 18 +- java/awt/Choice.java | 717 ++++---- java/awt/Component.java | 383 +++- java/awt/Container.java | 76 +- java/awt/List.java | 100 +- java/awt/Toolkit.java | 9 +- java/awt/dnd/DragGestureRecognizer.java | 1 + java/awt/dnd/DragSource.java | 11 +- java/awt/dnd/DropTarget.java | 19 +- java/awt/font/FontRenderContext.java | 8 +- java/awt/geom/AffineTransform.java | 16 +- java/awt/image/BufferedImage.java | 337 ++-- java/io/ObjectInputStream.java | 9 +- java/io/ObjectStreamField.java | 24 +- java/lang/StrictMath.java | 226 ++- java/nio/DirectByteBufferImpl.java | 2 +- java/security/AccessControlContext.java | 22 +- java/text/SimpleDateFormat.java | 20 +- .../management/BadAttributeValueExpException.java | 91 + javax/management/BadStringOperationException.java | 92 + .../management/InstanceAlreadyExistsException.java | 76 + javax/management/InstanceNotFoundException.java | 76 + javax/management/InvalidApplicationException.java | 92 + javax/management/MBeanConstructorInfo.java | 10 +- javax/management/MBeanFeatureInfo.java | 2 +- javax/management/MBeanInfo.java | 23 +- javax/management/MBeanOperationInfo.java | 8 +- javax/management/MBeanRegistrationException.java | 84 + javax/management/MalformedObjectNameException.java | 76 + javax/management/RuntimeErrorException.java | 115 ++ javax/management/RuntimeMBeanException.java | 114 ++ javax/management/ServiceNotFoundException.java | 75 + javax/management/StandardMBean.java | 32 +- .../openmbean/InvalidOpenTypeException.java | 76 + .../openmbean/KeyAlreadyExistsException.java | 77 + .../openmbean/OpenMBeanAttributeInfo.java | 120 ++ .../openmbean/OpenMBeanAttributeInfoSupport.java | 546 ++++++ .../openmbean/OpenMBeanConstructorInfo.java | 112 ++ .../openmbean/OpenMBeanConstructorInfoSupport.java | 174 ++ javax/management/openmbean/OpenMBeanInfo.java | 154 ++ .../management/openmbean/OpenMBeanInfoSupport.java | 191 ++ .../openmbean/OpenMBeanOperationInfo.java | 154 ++ .../openmbean/OpenMBeanOperationInfoSupport.java | 240 +++ .../openmbean/OpenMBeanParameterInfo.java | 190 ++ .../openmbean/OpenMBeanParameterInfoSupport.java | 511 ++++++ javax/management/openmbean/SimpleType.java | 2 +- javax/management/openmbean/TabularData.java | 45 +- javax/management/openmbean/TabularDataSupport.java | 652 +++++++ javax/naming/Name.java | 14 +- javax/naming/spi/NamingManager.java | 32 +- javax/swing/JMenu.java | 97 +- javax/swing/JPopupMenu.java | 9 +- javax/swing/JTree.java | 9 +- javax/swing/Popup.java | 2 +- javax/swing/SwingUtilities.java | 112 +- javax/swing/plaf/basic/BasicButtonListener.java | 6 +- javax/swing/plaf/basic/BasicButtonUI.java | 75 +- javax/swing/plaf/basic/BasicInternalFrameUI.java | 57 +- javax/swing/plaf/basic/BasicMenuItemUI.java | 4 - javax/swing/plaf/basic/BasicMenuUI.java | 207 ++- javax/swing/plaf/metal/MetalBorders.java | 16 +- javax/swing/plaf/metal/MetalMenuBarUI.java | 9 +- javax/swing/text/AbstractDocument.java | 651 ++++++- javax/swing/text/BoxView.java | 22 +- javax/swing/text/DefaultHighlighter.java | 389 ++-- javax/swing/text/DefaultStyledDocument.java | 1893 +++++++++++--------- javax/swing/text/GapContent.java | 189 +- javax/swing/text/GlyphView.java | 29 +- javax/swing/text/JTextComponent.java | 278 ++- javax/swing/text/LabelView.java | 44 +- javax/swing/text/PlainView.java | 138 +- javax/swing/text/Utilities.java | 8 +- javax/swing/text/WrappedPlainView.java | 24 + native/jni/gtk-peer/GtkDragSourceContextPeer.c | 132 +- ...gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c | 4 +- .../gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c | 70 +- .../gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c | 11 + tools/.cvsignore | 1 + tools/Makefile.am | 30 +- tools/gjavah.in | 47 + tools/gnu/classpath/tools/javah/ClassWrapper.java | 341 ++++ .../classpath/tools/javah/CniIncludePrinter.java | 69 + .../gnu/classpath/tools/javah/CniPrintStream.java | 243 +++ .../gnu/classpath/tools/javah/CniStubPrinter.java | 119 ++ tools/gnu/classpath/tools/javah/FieldHelper.java | 97 + tools/gnu/classpath/tools/javah/JniHelper.java | 120 ++ .../classpath/tools/javah/JniIncludePrinter.java | 151 ++ .../gnu/classpath/tools/javah/JniPrintStream.java | 115 ++ .../gnu/classpath/tools/javah/JniStubPrinter.java | 98 + tools/gnu/classpath/tools/javah/Keywords.java | 85 + tools/gnu/classpath/tools/javah/Main.java | 375 ++++ tools/gnu/classpath/tools/javah/MethodHelper.java | 130 ++ .../gnu/classpath/tools/javah/PackageWrapper.java | 54 + .../gnu/classpath/tools/javah/PathOptionGroup.java | 135 ++ tools/gnu/classpath/tools/javah/Printer.java | 55 + tools/gnu/classpath/tools/javah/Text.java | 60 + tools/gnu/classpath/tools/keytool/Command.java | 4 +- tools/gnu/classpath/tools/keytool/GenKeyCmd.java | 1 - tools/gnu/classpath/tools/keytool/ImportCmd.java | 1 - tools/gnu/classpath/tools/keytool/Main.java | 8 - .../java/lang/management/VMMemoryMXBeanImpl.java | 4 +- 144 files changed, 18244 insertions(+), 2739 deletions(-) create mode 100644 gnu/java/awt/peer/gtk/GtkMainThread.java create mode 100644 gnu/javax/naming/giop/ContextContinuation.java create mode 100644 gnu/javax/naming/giop/CorbalocParser.java create mode 100644 gnu/javax/naming/giop/GiopNamingEnumeration.java create mode 100644 gnu/javax/naming/giop/GiopNamingServiceFactory.java create mode 100644 gnu/javax/naming/giop/GiopNamingServiceURLContext.java create mode 100644 gnu/javax/naming/giop/ListBindingsEnumeration.java create mode 100644 gnu/javax/naming/giop/ListEnumeration.java create mode 100644 gnu/javax/naming/ictxImpl/trans/GnuName.java create mode 100644 gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java create mode 100644 gnu/javax/naming/jndi/url/rmi/ContextContinuation.java create mode 100644 gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java create mode 100644 gnu/javax/naming/jndi/url/rmi/ListEnumeration.java create mode 100644 gnu/javax/naming/jndi/url/rmi/RmiContinuation.java create mode 100644 gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java create mode 100644 gnu/javax/naming/jndi/url/rmi/rmiURLContext.java create mode 100644 gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java create mode 100644 javax/management/BadAttributeValueExpException.java create mode 100644 javax/management/BadStringOperationException.java create mode 100644 javax/management/InstanceAlreadyExistsException.java create mode 100644 javax/management/InstanceNotFoundException.java create mode 100644 javax/management/InvalidApplicationException.java create mode 100644 javax/management/MBeanRegistrationException.java create mode 100644 javax/management/MalformedObjectNameException.java create mode 100644 javax/management/RuntimeErrorException.java create mode 100644 javax/management/RuntimeMBeanException.java create mode 100644 javax/management/ServiceNotFoundException.java create mode 100644 javax/management/openmbean/InvalidOpenTypeException.java create mode 100644 javax/management/openmbean/KeyAlreadyExistsException.java create mode 100644 javax/management/openmbean/OpenMBeanAttributeInfo.java create mode 100644 javax/management/openmbean/OpenMBeanAttributeInfoSupport.java create mode 100644 javax/management/openmbean/OpenMBeanConstructorInfo.java create mode 100644 javax/management/openmbean/OpenMBeanConstructorInfoSupport.java create mode 100644 javax/management/openmbean/OpenMBeanInfo.java create mode 100644 javax/management/openmbean/OpenMBeanInfoSupport.java create mode 100644 javax/management/openmbean/OpenMBeanOperationInfo.java create mode 100644 javax/management/openmbean/OpenMBeanOperationInfoSupport.java create mode 100644 javax/management/openmbean/OpenMBeanParameterInfo.java create mode 100644 javax/management/openmbean/OpenMBeanParameterInfoSupport.java create mode 100644 javax/management/openmbean/TabularDataSupport.java create mode 100644 tools/gjavah.in create mode 100644 tools/gnu/classpath/tools/javah/ClassWrapper.java create mode 100644 tools/gnu/classpath/tools/javah/CniIncludePrinter.java create mode 100644 tools/gnu/classpath/tools/javah/CniPrintStream.java create mode 100644 tools/gnu/classpath/tools/javah/CniStubPrinter.java create mode 100644 tools/gnu/classpath/tools/javah/FieldHelper.java create mode 100644 tools/gnu/classpath/tools/javah/JniHelper.java create mode 100644 tools/gnu/classpath/tools/javah/JniIncludePrinter.java create mode 100644 tools/gnu/classpath/tools/javah/JniPrintStream.java create mode 100644 tools/gnu/classpath/tools/javah/JniStubPrinter.java create mode 100644 tools/gnu/classpath/tools/javah/Keywords.java create mode 100644 tools/gnu/classpath/tools/javah/Main.java create mode 100644 tools/gnu/classpath/tools/javah/MethodHelper.java create mode 100644 tools/gnu/classpath/tools/javah/PackageWrapper.java create mode 100644 tools/gnu/classpath/tools/javah/PathOptionGroup.java create mode 100644 tools/gnu/classpath/tools/javah/Printer.java create mode 100644 tools/gnu/classpath/tools/javah/Text.java diff --git a/.classpath b/.classpath index 8d50115d8..c18a06758 100644 --- a/.classpath +++ b/.classpath @@ -3,7 +3,7 @@ - + diff --git a/ChangeLog b/ChangeLog index 3121860c2..04c86c972 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,332 @@ +2006-08-11 Andrew John Hughes + + * vm/reference/gnu/java/lang/management/VMMemoryMXBeanImpl.java: + Fix documentation typos. + +2006-08-11 David Daney + + PR classpath/28580 + * gnu/java/net/protocol/http/Request.java (readResponse): Call + createResponseBodyStream in more cases and with new parameter. + (createResponseBodyStream): Added new parameter mayHaveBody. Handle + HEAD and !mayHaveBody responses specially. + +2006-08-11 Roman Kennke + + * javax/swing/text/GlyphView.java + (DefaultGlyphPainter.modelToView): Fixed model->view mapping. + * javax/swing/text/LabelView.java + (valid): New flag indicating if the text attributes are valid. + (LabelView): Initialize valid field with false. + (setPropertiesFromAttributes): Call setter methods instead + of setting properties directly. Set valid to true. + (changedUpdate): Invalidate attributes. Call super. + (getBackground): Sync attributes if necessary. + (getForeground): Sync attributes if necessary. + (getFont): Sync attributes if necessary. + (isUnderline): Sync attributes if necessary. + (isSuperscript): Sync attributes if necessary. + (isStrikeThrough): Sync attributes if necessary. + (getFontMetrics): Sync attributes if necessary. Fetch font metrics + from toolkit if Container is not available yet. + +2006-08-11 Roman Kennke + + * javax/swing/text/PlainView.java + (tabBase): New field. + (tabSize): New field. + (updateMetrics): Update tabSize. + (lineToRect): Only allocate when really necessary. + (modelToView): Use tabBase for offset calculations. + (paint): Only allocate when really necessary. Update tabBase. + (nextTabStop): Fixed tab calculation. + (viewToModel): Correctly handle multiline text and locations + outside the view's bounds. Set bias. + (getLineLength): Use tabBase. + * javax/swing/text/Utilities.java + (drawTabbedText): Don't special case newlines. The views + must take care of this. + +2006-08-11 Roman Kennke + + * javax/swing/text/GapContent.java + (UndoPosRef): New inner class. Used for resetting positions + after undo/redo operations. + (InsertUndo.positions): New field. + (InsertUndo.undo): Store positions in removed range. + (InsertUndo.redo): Restore positions in re-inserted range. + (UndoRemove.positions): New field. + (UndoRemove.UndoRemove): Store positions in removed range. + (UndoRemove.undo): Restore positions in re-inserted range. + (UndoRemove.redo): Store positions in removed range. + (insertString): Create InsertUndo instance before actually + inserting the string. + (remove): Create UndoRemove instance before actually + removing. + (getPositionsInRange): Don't clear the Vector. Return Vector + of UndoPosRefs. + (updateUndoPositions): Implemented to reset all UndoPosRefs + in the vector. + +2006-08-11 Jeroen Frijters + + * java/io/ObjectInputStream.java (readClassDescriptor): + Use class's class loader to resolve field types. + * java/io/ObjectStreamField.java + (ObjectStreamField(String,String,ClassLoader)): Removed. + (ObjectStreamField(String,String)): Don't try to resolve typename. + (resolveType): New method. + +2006-08-10 Roman Kennke + + * javax/swing/text/BoxView.java + (calculateMajorAxisRequirements): Sum up the preferred and + maximum sizes. + (isAfter): Also add in the rectangle's with/height. + (childAllocation): Don't trigger layout here. + (layoutMinorAxis): Removed debug output. + (getWidth): Consider the insets. + (getHeight): Consider the insets. + (setSize): Consider the insets. + (updateRequirements): Check axis and throw + IllegalArgumentException. + +2006-08-10 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (BidiRootName): New constant field, denotes the element name + for bidi root elements. + (AsyncLoadPriority): New constant field, denotes the property + to store the asynchronousLoadPriority. + (I18N): New constant field, denotes the property for + I18N support. + (bidiRoot): Made field type BidiRootElement. + (AbstractDocument): Build initial element structure for + bidi. + (getAsynchronousLoadPriority): Implemented. Returns the + value stored in the document properties. + (setAsynchronousLoadPriority): Implemented. Sets the + value stored in the document properties. + (getEndPosition): Implemented to use a Position from the + content. + (getStartPosition): Implemented to use a Position from the + content. + (insertStringImpl): Update the I18N setting if necessary. + (insertUpdate): Update the bidi structure if necessary. + (postRemoveUpdate): Update the bidi structure if necessary. + (putProperty): Update the I18N setting and bidi structure + if necessary. + (updateBidi): New helper method for updating the bidi + structure. + (getBidis): New helper method. Fetches the Bidi analysers + for the paragraphs of the range to check. + (dump): Also dump the bidi structure. + (AbstractElement.dump): Indent the '>' correctly. + (AbstractElement.children): Check numChildren rather then + children.length. + (BidiRootElement): New inner class. + (BidiElement): New inner class. + +2006-08-10 Roman Kennke + + * javax/swing/text/GapContent.java + (getChars): Optimized to only copy array when really necessary. + Respect the partialReturn property. + +2006-08-10 Lillian Angel + + * gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java + (getComponentPeer): Added check to prevent NPE. + +2006-08-10 Gary Benson + + * java/security/AccessControlContext.java (): + Avoid a duplicated AccessController.getContext() call. + 2006-08-09 Mark Wielaard * configure.ac (VERSION): Set to 0.92-generics. * NEWS: Add updates for 0.92 release. -2006-08-08 Roman Kennke +2006-08-09 Tom Tromey + + PR classpath/28658: + * java/text/SimpleDateFormat.java (parse): Let an unquoted space in + the pattern match any number of spaces in the text. + +2006-08-09 Sven de Marothy + + * java/awt/image/BufferedImage.java + (BufferedImage): Reimplement predefined-type constructor. + (observers/tileObservers): Field renamed to tileObservers. + (createDefaultIndexedColorModel): New method. + +2006-08-09 Tom Tromey + + PR classpath/28666: + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c + (Java_gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice_nativeGetDisplayModes): + Create a 'short' array. + +2006-08-09 Tom Tromey + + * tools/gnu/classpath/tools/javah/JniHelper.java (getName): Properly + handle arrays. + * tools/gnu/classpath/tools/javah/JniIncludePrinter.java + (writeFields): Print "L" after int constant. Don't mangle the field + name. Only print int/long fields. + +2006-08-09 Tom Tromey + + * tools/gnu/classpath/tools/javah/Main.java (getParser): Name program + "javah". + +2006-08-09 Sven de Marothy + + * javax/swing/JTree.java + (JTree): Default SelectionModel should be DefaultTreeSelectionModel. + (setSelectionModel): Null parameter should create an EmptySelectionM. + +2006-08-09 Roman Kennke + + * javax/swing/text/AbstractDocument.java + (insertString): Perform modifications inside a write lock. + (insertStringImpl): Don't lock here. This is already done + in insertString(). + (replace): Perform modifications inside a write lock. + (AbstractElement.AbstractElement): Call addAttributes() to + add the attributes. + (AbstractElement.getName): Fetch name from the ElementNameAttibute. + (BranchElement.lastIndex): New field. Optimizes getElementIndex(). + (BranchElement.BranchElement): Set lastIndex to -1. + (BranchElement.getElementIndex): Implemented more efficient + search. + +2006-08-09 Roman Kennke + + * javax/swing/text/DefaultStyledDocument.java + (Edit): Moved this inner class into ElementBuffer where it + is actually needed. + (edits): Moved this field into ElementBuffer. + (getEditForParagraphAndIndex): Removed obsolete method. + (insertUpdate): Added some optimizations and fixes. Split + out handling insertion after newlines. + (insertAfterNewline): New helper method. Handles insertions + after a newline. + (ElementBuffer.Edit): New inner class. Moved here from + DefaultStyledDocument. + (ElementBuffer.createdFracture): New field. + (ElementBuffer.documentEvent): Made private. + (ElementBuffer.edits): New field. Moved here from + DefaultStyledDocument. + (ElementBuffer.fracNotCreated): Replaced by createdFracture. + (ElementBuffer.fracturedChild): New field. + (ElementBuffer.fracturedParent): New field. + (ElementBuffer.insertPath): New field. + (ElementBuffer.lastFractured): Removed. Replaced by fracturedChild and + fracturedParent. + (ElementBuffer.offsetLastIndex): New field. + (ElementBuffer.offsetLastIndexReplace): New field. + (ElementBuffer.recreateLeafs): New field. + (ElementBuffer.ElementBuffer): Don't initialize stack here. + (ElementBuffer.canJoin): New helper method. + (ElementBuffer.changeUpdate): Changed to use elementStack with + Edits rather than Elements. Let the split method do the work. + (ElementBuffer.cloneAsNecessary): New helper method. + (ElementBuffer.createFracture): Changed to fracture the bottommost + child in the stack. + (ElementBuffer.finishEdit): New helper method. Moved out + from insertUpdate to perform the actual changes and update + the event. + (fracture): New helper method. + (insertContentTag): Fixed some bugs and changed to use Edit + instances in the stack, rather then Elements. + (insertElement): New helper method. Moved out from insertUpdate() + to process the ElementSpecs. + (insertFirstContentTag): Fixed some problems and changed to use Edit + instances in the stack, rather then Elements. + (insertFracture): Removed. Basically moved into createFracture() + and fracture(). + (insertParagraph): Removed. + (insertUpdate): Split out the ElementSpec processing into + insertElement(). Use Edit instances in the stack. Fixed some + problems. + (insert): Split out the preparation and finishing code into + prepareEdit() and finishEdit(). + (join): New helper method. + (pop): New helper method. + (prepareEdit): New helper method. + (recreateFracturedElement): New helper method. + (recreateLeaves): Removed. + (recreate): New helper method. + (removeElements): New helper method. Split out from removeUpdate(). + (removeUpdate): Split out the actual removal. Use the + Edit stack to perform removal and perform the remove actions + and event updates afterwards, just like in insertImpl(). + (remove): Use prepareEdit() and finishEdit(). + (split): Replaced with more flexible impl. + +2006-08-09 Sven de Marothy + + * gnu/java/awt/peer/gtk/CairoSurface.java + Change class to extend WritableRaster and not DataBuffer. + (CairoDataBuffer): New inner class. + * gnu/java/awt/peer/gtk/BufferedImageGraphics.java + * gnu/java/awt/peer/gtk/CairoGraphics2D.java + * gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java + Accomodate the above change. + +2006-08-09 Sven de Marothy + + * gnu/java/awt/peer/gtk/GtkMainThread.java + New file. + * gnu/java/awt/peer/gtk/GtkChoicePeer.java + * gnu/java/awt/peer/gtk/GtkComponentPeer.java + Replace GtkToolkit.mainThread with GtkMainThread.mainThread. + * gnu/java/awt/peer/gtk/GtkToolkit.java + Minor style fixes; removed unused fields, + set fields to private where possible. + (createDialog, createFrame, createWindow, createEmbeddedWindow): + Call GtkMainThread.createWindow(). + * gnu/java/awt/peer/gtk/GtkWindowPeer.java + (dispose): New method. + * include/gnu_java_awt_peer_gtk_GtkToolkit.h + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c + (gtkQuit): New native method. + +2006-08-08 Lillian Angel + + * java/awt/Component.java + (setDropTarget): Added check. + +2006-08-08 Lillian Angel + + * gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java + (GtkDragSourceContextPeer): Added FIXME. Changed call + to setTarget. + * gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java + (GtkDropTargetContextPeer): Removed target initialization. + * java/awt/Component.java + (setTarget): Removed commented out code. + +2006-08-08 Mark Wielaard + + * javax/swing/text/DefaultHighlighter.java: Qualify + Highlighter.HighlightPainter class name for gcj. + +2006-08-05 Roman Kennke + + * javax/swing/plaf/basic/BasicTableUI.java + (MouseInputHandler.mousePressed): Request focus on list + component. + +2006-08-05 Roman Kennke + + * javax/swing/plaf/basic/BasicListUI.java + (MouseInputHandler.mousePressed): Request focus on list + component. + +2006-08-05 Roman Kennke PR 28650 * javax/swing/plaf/basic/BasicMenuBarUI.java @@ -167,7 +490,7 @@ (getMinimumSize): Added specnote about this method never beeing called in the RI. -2006-08-06 Sven de Marothy +2006-08-03 Sven de Marothy * gnu/java/awt/peer/gtk/ComponentGraphics.java (grab, nativeGrab): New methods. @@ -215,6 +538,138 @@ g_type_init earlier in function to correctly initialize the type system used by the backend. +2006-08-05 Roman Kennke + + * javax/swing/text/DefaultHighlight.java + (DefaultHighlightPainter.paintHighlight): Removed method. + (DefaultHighlightPainter.paintLayer): Implemented. + (DefaultHighlightPainter.paint): Implemented more efficient + painting for multiline-highlights. + (HighlightEntry.p0): Changed to be a Position. + (HighlightEntry.p1): Changed to be a Position. + (HighlightEntry.HighlightEntry): Changed to take Position + arfuments. + (HighlightEntry.getStartOffset): Changed to return p0.getOffset(); + (HighlightEntry.getEndOffset): Changed to return p1.getOffset(); + (LayerHighlightEntry): New inner class. Extends HighlightEntry + and tracks the painted rectangle for efficient repainting. + (addHighlight): Handle layered highlight. + (changeHighlight): Handle layered highlight. + (paintLayeredHighlights): Implemented. + (paint): Paint only non-layered highlights here. + (removeAllHighlights): Trigger correct repaint. + (removeHighlight): Handle layered highlight here for + more efficient repainting. + * javax/swing/text/GlyphView.java + (paint): Handle layered highlights. + * javax/swing/text/PlainView.java + (paint): Handle layered highlights. + * javax/swing/text/WrappedPlainView.java + (WrappedLine.paint): Handle layered highlights. + +2006-08-07 Audrius Meskauskas + + PR 26972 + * NEWS: As suggested by Paul Jennier, added note about the fix of + the InitialContext. + +2006-08-07 Audrius Meskauskas + + * NEWS: Added entry about the context factories for JNDI. + +2006-08-07 Audrius Meskauskas + + PR 27383 + * gnu/CORBA/Connected_objects.java (size): New method. + * gnu/CORBA/OrbFunctional.java (countConnectedObjects): + New method. + * javax/naming/spi/NamingManager.java (getURLContext): + Also search for the URL context factories in + gnu/javax/naming/jndi/url. + * gnu/javax/naming/giop/ContextContinuation.java, + gnu/javax/naming/giop/CorbalocParser.java, + gnu/javax/naming/giop/GiopNamingEnumeration.java, + gnu/javax/naming/giop/GiopNamingServiceFactory.java, + gnu/javax/naming/giop/GiopNamingServiceURLContext.java, + gnu/javax/naming/giop/ListBindingsEnumeration.java, + gnu/javax/naming/giop/ListEnumeration.java, + gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java, + gnu/javax/naming/jndi/url/rmi/ContextContinuation.java, + gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java, + gnu/javax/naming/jndi/url/rmi/ListEnumeration.java, + gnu/javax/naming/jndi/url/rmi/RmiContinuation.java, + gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java, + gnu/javax/naming/jndi/url/rmi/rmiURLContext.java, + gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java: New files. + +2006-08-06 Sven de Marothy + + * gnu/java/awt/peer/gtk/CairoGraphics2D.java + (drawGlyphVector): Synchronize against font object when drawing. + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c + (nativeDrawGlyphVector): Use pango locking when drawing. + (install_font_peer): Use pango locking when creating the cairo face. + +2006-08-06 C. Scott Marshall + + Fixes PR 28608. + * java/nio/DirectByteBufferImpl.java (duplicate): only reset if + the mark has been set. + * native/jni/java-nio/java_nio_VMDirectByteBuffer.c + (Java_java_nio_VMDirectByteBuffer_allocate): zero out the + allocated data. + +2006-08-06 Mark Wielaard + + PR 28555 + Suggested by Matthew Burgess + * gnu/xml/transform/ApplyTemplatesNode.java (clone): Check whether + withParams is null. + * gnu/xml/transform/ForEachNode.java (clone): Check whether + sortKeys is null. + +2006-08-06 Raif S. Naffah + Paul Jenner + + * README: Update bug, patches and cvs instructions plus new URLs of + various external projects. + +2006-08-05 Andrew John Hughes + + * gnu/java/lang/management/BeanImpl.java: + (cacheMBeanInfo(MBeanInfo)): Override given MBeanInfo + with open variant. + (getCachedMBeanInfo()): Return open variant. + (getMBeanInfo()): Likewise. + (getTypeFromClass(Class)): Implemented. + (translateSignature(MBeanParameterInfo)): Likewise. + (translate(String)): Likewise. + * javax/management/StandardMBean.java: + (getMBeanInfo()): Return attribute names with capital letters, + as in docs for java.lang.management.ManagementFactory, and + ensure descriptions are not "". + * javax/management/openmbean/OpenMBeanConstructorInfoSupport.java, + * javax/management/openmbean/OpenMBeanInfoSupport.java, + * javax/management/openmbean/OpenMBeanOperationInfoSupport.java: + (toString()): Use Arrays.toString(). + * javax/management/openmbean/OpenMBeanParameterInfoSupport.java: + (OpenMBeanParameterInfoSupport(String, String, OpenType)): + Set open type here rather than in other constructors. + +2006-08-05 Andrew John Hughes + + * javax/management/MBeanFeatureInfo.java: + Make string variable package-private. + * javax/management/StandardMBean.java: + (getMBeanInterface()): Made final. + * javax/management/openmbean/SimpleType.java: + Made final. + +2006-08-05 Jeroen Frijters + + * java/awt/Component.java (setDropTarget): Commented out GTK specific + code. + 2006-08-05 Andrew John Hughes * examples/gnu/classpath/examples/swing/FillRect.java, @@ -255,13 +710,175 @@ * configdiag.jnlp: Removed. +2006-08-05 Andrew John Hughes + + * gnu/java/lang/management/BeanImpl.java: + (getAttribute(String)): Implemented. + +2006-08-05 Roman Kennke + + * javax/swing/text/JTextComponent.java + (AccessibleJTextComponent.dot): Renamed field into caretDot. + (AccessibleJTextComponent.textComp): Removed field + and replace with JTextComponent.this construct. + (AccessibleJTextComponent.AccessibleJTextComponent): + Fetch caret position. + (caretUpdate): Implemented. Fires property change events and + updates the caretDot field. + (changedUpdate): Implemented. Fires property change events. + (insertUpdate): Implemented. Fires property change events. + (removeUpdate): Implemented. Fires property change events. + (cut): Replaced textComp with JTextComponent.this construct. + (paste): Replaced textComp with JTextComponent.this construct. + (replaceText): Replaced textComp with JTextComponent.this construct. + (selectText): Replaced textComp with JTextComponent.this construct. + (getCaretPosition): Replaced textComp with JTextComponent.this + construct. + (getCharCount): Replaced textComp with JTextComponent.this construct. + (getSelectedText): Replaced textComp with JTextComponent.this + construct. + (getSelectionEnd): Replaced textComp with JTextComponent.this + construct. + (getSelectionStart): Replaced textComp with JTextComponent.this + construct. + (getTextRange): Replaced textComp with JTextComponent.this + construct. + (doAccessibleAction): Implemented. + (getAccessibleActionCount): Implemented. + (getAccessibleActionDescription): Implemented. + (getAccessibleStateSet): Implemented. + (getAfterIndex): Implemented. + (getBeforeIndex): Implemented. + (getAtIndex): Implemented. + (getAtIndexImpl): New helper method. + (getCharacterAttribute): Implemented. + (getCharacterBounds): Implemented. + (getIndexAtPoint): Implemented. + (insertTextAtIndex): Implemented. + (setAttributes): Implemented. + (setTextContents): Implemented. + +2006-08-05 Raif S. Naffah + + * configure.ac: Better handling of default-preferences-peer option. + +2006-08-04 Andreas Tobler + + * java/awt/BasicStroke.java (dashedStroke): Cast coords.clone to + double[]. + +2006-08-04 Andrew John Hughes + + * javax/management/openmbean/TabularData.java: + Documentation corrections. + * javax/management/openmbean/TabularDataSupport.java: + New file. + +2006-08-04 Francis Kung + + * java/awt/BasicStroke.java + (dashedStroke): Implemented. + +2006-08-04 Andrew John Hughes + + * javax/management/BadAttributeValueExpException.java, + * javax/management/BadStringOperationException.java, + * javax/management/InstanceAlreadyExistsException.java, + * javax/management/InstanceNotFoundException.java, + * javax/management/InvalidApplicationException.java, + * javax/management/MBeanRegistrationException.java, + * javax/management/MalformedObjectNameException.java, + * javax/management/RuntimeErrorException.java, + * javax/management/RuntimeMBeanException.java, + * javax/management/ServiceNotFoundException.java: + New files. + +2006-08-04 Roman Kennke + + * javax/swing/SwingUtilities.java + (layoutCompoundLabel(JComponent,FontMetrics,String,Icon,int,int,int, + int,Rectangle,Rectangle,Rectangle,int)): Delegate to new + layoutCompoundLabelImpl(). + (layoutCompoundLabel(FontMetrics,String,Icon,int,int,int,int, + Rectangle,Rectangle,Rectangle,int)): Delegate to new + layoutCompoundLabelImpl(). + (layoutCompoundLabelImpl): New helper method. Moved impl from + layoutCompoundLabel() to here and added handling of HTML. + * javax/swing/plaf/basic/BasicButtonUI.java + (installUI): Update HTML view if appropriate. + (uninstallUI): New method. Do the usual uninstallUI things + and uninstall HTML view. + (getMinimumSize): New method. Adjusts the minimum size + by the HTML view minimum size. + (getMaximumSize): New method. Adjusts the maximum size + by the HTML view maximum size. + (getPreferredSize): Pass the button's iconTextGap to the + BasicGraphicsUtils method. + (paint): Let HTML view paint the text, if present. + * javax/swing/plaf/basic/BasicButtonListener.java + (propertyChange): Update the HTML view when the button's + text is changed. + +2006-08-04 Mario Torre + + Reported by Raif S. Naffah + * native/jni/gconf-peer/GConfNativePeer.c (init_gconf_client): + g_type_init earlier in function to correctly initialize the + type system used by the backend. + +2006-08-04 Audrius Meskauskas + + PR 26972 + * javax/naming/Name.java (addAll, getPrefix, getSuffix): + Documented. + * gnu/javax/naming/ictxImpl/trans/GnuName.java: New file. + 2006-08-04 Robert Schuster Reported by Henrik Gulbrandsen - Fixes PR27864. - * gnu/xml/dom/DomIterator.java: - (successor): Added if-statement. + Fixes PR27864. + * gnu/xml/dom/DomIterator.java: + (successor): Added if-statement. + +2006-08-04 Mark Wielaard + + * scripts/Makefile.am (EXTRA_DIST): Add import-cacerts.sh. + +2006-08-04 Robert Schuster + + * javax/swing/plaf/metal/MetalMenuBarUI.java: + (update): Check size and paint smaller gradient. + * javax/swing/plaf/metal/MetalBorders.java: + (MenuBarBorder): Removed borderColor field. + (MenuBarBorder.paintBorder): Added note, fetch color from UIManager or + MetalLookAndFeel. + +2006-08-03 Roman Kennke + + PR 27637 + * javax/swing/plaf/basic/BasicInternalFrameUI.java + (ComponentHandler.componentResized): Reimplemented to handle + arbitrary parents. + (InternalFramePropertyChangeHandler.propertyChange): (Un)install + component listener on changed ancestor. + (installListeners): Install componentListener. + (uninstallListeners): Uninstall componentListener. + +2006-08-03 Carsten Neumann + * StrictMath.java (cbrt): Return argument if it is a NaN. + (cosh): Likewise. + (expm1): Likewise. + (sinh): Likewise. + +2006-08-03 Carsten Neumann + + * java/lang/StrictMath.java (tanh): New method. + +2006-08-03 Raif S. Naffah + + * scripts/import-cacerts.sh: Batch CA certificates import script. + 2006-08-03 Roman Kennke PR 27606 @@ -276,7 +893,63 @@ Handle indentation. (IndentIcon): New class. Wraps and indents another icon. -2006-08-03 Roman Kennke +2006-08-02 Andrew John Hughes + + * javax/management/MBeanConstructorInfo.java: + (MBeanConstructorInfo(String,String,MBeanParameterInfo[]): + Copy array rather than directly assigning. + * javax/management/MBeanInfo.java: + (MBeanInfo(String,String,MBeanAttributeInfo[], + MBeanConstructorInfo[], MBeanOperationInfo[], + MBeanNotificationInfo[])): Likewise. + * javax/management/MBeanOperationInfo.java: + (MBeanOperationInfo(String,String,MBeanParameterInfo[],String,int)): + Likewise. + * javax/management/openmbean/OpenMBeanAttributeInfoSupport.java, + * javax/management/openmbean/OpenMBeanConstructorInfoSupport.java: + New files. + * javax/management/openmbean/OpenMBeanInfo.java: + Corrected documentation. + * javax/management/openmbean/OpenMBeanInfoSupport.java: + New file. + * javax/management/openmbean/OpenMBeanOperationInfo.java: + Corrected documentation. + * javax/management/openmbean/OpenMBeanOperationInfoSupport.java: + New file. + * javax/management/openmbean/OpenMBeanParameterInfoSupport.java: + (MBeanParameterInfo(String,String,OpenType,Object,Object[])): + Call other constructor rather than reimplementing. + +2006-08-02 Lillian Angel + + * java/awt/dnd/DragSource.java + (isDragImageSupported): Implemented. + (getDragThreshold): Changed default value. + * java/awt/dnd/DropTarget.java + (DropTarget): Default action is changed to ACTION_COPY_OR_MOVE. + (DropTarget): Likewise. + (DropTarget): If FlavorMap passed in is null, we should use the system default. + (addDropTargetListener): Added check to determine if new DropTargetListener + is this class. If so, an IllegalArgumentException is thrown. If the + new listener is null, nothing happens. + +2006-08-02 Thomas Fitzsimmons + + * configure.ac (MOZILLA_FOUND): Fall back to + mozilla-firefox-plugin. + +2006-08-02 Sven de Marothy + + * java/awt/geom/AffineTransform.java + (hashCode): Tweak impl. + * java/awt/font/FontRenderContext.java + (hashCode): Implement. + +2006-08-02 Carsten Neumann + + * java/lang/StrictMath.java (sinh): New method. + +2006-08-02 Roman Kennke PR 27605 * javax/swing/JComboBox.java @@ -302,7 +975,70 @@ (createPropertyChangeListener): Return null just like the RI. -2006-08-03 Roman Kennke +2006-08-02 Sven de Marothy + + * gnu/java/awt/peer/gtk/GtkChoicePeer.java + (remove): Force event on removing item 0 when it's selected. + (handleEvent): Always call Choice.selected(). + * java/awt/Choice.java: + (remove): Simplify and correct. + +2006-08-02 Mark Wielaard + + PR 28535 + * configure.ac (gconf-peer): Check for gdk-2.0. + * native/jni/gconf-peer/Makefile.am + (AM_LDFLAGS): Use GDK_LIBS. + (AM_CFLAGS): Use GDK_CFLAGS. + +2006-08-02 Thomas Minor <1nocentrabidlamb@sexMagnet.com> + + * java/net/URL.java (getContent(Class[])): Implement. + +2006-08-02 Roman Kennke + + PR 27624 + * javax/swing/JMenu.java + (JMenu()): Removed setting of delay. + (JMenu(String)): Removed setting of delay. + (JMenu(Action)): Removed setting of delay. + (JMenu(String,boolean)): Removed setting of delay. + (setSelectedHelper): Removed unneeded method. + (setSelected): Simply set the model state. + (setPopupMenuVisible): Recognize the popup location + determined by getPopupMenuOrigin(). + (getPopupMenuOrigin): Recognize the UI properties for + X and Y offset. + (menuSelectionChanged): Call setSelected() directly. + * javax/swing/JPopupMenu.java + (menuSelectionChanged): If invoker is a JMenu, then delegate + to that to get the position right. + * javax/swing/Popup.java + (LightweightPopup.show): Insert the popup as first component + in the layer, so that it overlaps it's caller. + * javax/swing/plaf/basic/BasicMenuItemUI.java + (getPath): Don't include the popup. + * javax/swing/plaf/basic/BasicMenuUI.java + (SelectMenuAction): New class. This invokes the popup when + a menu is selected. + (installDefaults): Install delay of 200 ms. + (setupPostTimer): Implemented. + (MouseInputHandler.mouseClicked): Do nothing here. + (MouseInputHandler.mouseEntered): Use MenuSelectionManager + magic to handle the selection. Open the menu via a timer. + (MouseInputHandler.mousePressed): Use MenuSelectionManager + magic to handle the selection. Open the menu via a timer. + (MenuDragMouseHandler.menuMouseDragged): Probably use + timer. + (menuDragMouseEntered): Do nothing here. + +2006-08-02 Andrew John Hughes + + * javax/management/openmbean/InvalidOpenTypeException.java, + * javax/management/openmbean/KeyAlreadyExistsException.java: + New files. + +2006-08-02 Roman Kennke PR 27604 * javax/swing/plaf/basic/BasicChooserUI.java @@ -351,72 +1087,102 @@ Set renderer to a default handler when the current renderer in the JTree is null. -2006-08-03 Mark Wielaard - - * scripts/Makefile.am (EXTRA_DIST): Add import-cacerts.sh. - -2006-08-03 Raif S. Naffah +2006-08-02 Raif S. Naffah - * scripts/import-cacerts.sh: Batch CA certificates import script. + PR Classpath/23899 + * java/security/SecureRandom.java (next): Call nextBytes as per specs. -2006-08-03 Raif S. Naffah +2006-08-02 Raif S. Naffah PR Classpath/28556 - * gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java - (encodePrivateKey): Updated documentation to clarify that RFC-2459 - states that the parameters field of the AlgorithmIdentifier element - MUST be NULL if present. Amended the code to reflect the specs. + * gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java (encodePrivateKey): + Updated documentation to clarify that RFC-2459 states that the parameters + field of the AlgorithmIdentifier element MUST be NULL if present. + Amended the code to reflect the specs. (decodePrivateKey): Handle case of NULL AlgorithmIdentifier.parameters. -2006-08-03 Raif S. Naffah +2006-08-01 Andrew John Hughes - PR Classpath/23899 - * java/security/SecureRandom.java (next): Call nextBytes as per specs. + * javax/management/openmbean/OpenMBeanParameterInfoSupport.java: + Call parameter 'defaultValue' not 'defValue'. -2006-08-03 Thomas Fitzsimmons +2006-08-01 Andrew John Hughes - * native/jawt/Makefile.am (libjawt_la_LDFLAGS): Add - -avoid-version. - * native/jni/gtk-peer/Makefile.am (libgtkpeer_la_LDFLAGS): - Likewise. - * native/jni/midi-alsa/Makefile.am (libgjsmalsa_la_LDFLAGS): - Likewise. - * native/jni/midi-dssi/Makefile.am (libgjsmdssi_la_LDFLAGS): - Likewise. + * javax/management/openmbean/OpenMBeanParameterInfoSupport.java: + New file. -2006-08-03 Thomas Fitzsimmons +2006-08-01 Roman Kennke + + PR 28562 + * javax/swing/plaf/basic/BasicOptionPaneUI.java + (PropertyChangeHandler.propertyChange): Cleanly reinstall + components when visual property chanegs. + +2006-08-01 Andrew John Hughes - * native/jni/qt-peer/Makefile.am (libqtpeer_la_LDFLAGS): Add - -avoid-version. + * javax/management/openmbean/OpenMBeanAttributeInfo.java: + (toString()): Corrected documentation. + * javax/management/openmbean/OpenMBeanConstructorInfo.java, + * javax/management/openmbean/OpenMBeanInfo.java, + * javax/management/openmbean/OpenMBeanOperationInfo.java: + New files. + * javax/management/openmbean/OpenMBeanParameterInfo.java: + (toString()): Corrected documentation. + +2006-08-01 Tania Bento -2006-08-03 Andrew John Hughes + * java/awt/Choice.java + (remove(int)): Added documentation. - * examples/gnu/classpath/examples/management/TestBeans.java: - New file. - * javax/management/MBeanAttributeInfo.java: - (toString()): Implemented. - * javax/management/MBeanConstructorInfo.java: - (toString()): Implemented. - * javax/management/MBeanFeatureInfo.java: - (toString()): Implemented. - * javax/management/MBeanInfo.java: - (toString()): Implemented. - * javax/management/MBeanNotificationInfo.java: - (toString()): Implemented. - * javax/management/MBeanOperationInfo.java: - (toString()): Implemented. - * javax/management/MBeanParameterInfo.java: - (toString()): Implemented. - * javax/management/StandardMBean.java: - (getMBeanInfo()): Fix attribute naming. +2006-08-01 Tania Bento + + * java/awt/Choice.java + (remove(int)): An IllegalArgumentException should not be thrown + if int is invalid. Update selectedIndex and peer selection. -2006-08-02 Mark Wielaard +2006-08-01 Tania Bento - PR 28535 - * configure.ac (gconf-peer): Check for gdk-2.0. - * native/jni/gconf-peer/Makefile.am - (AM_LDFLAGS): Use GDK_LIBS. - (AM_CFLAGS): Use GDK_CFLAGS. + * java/awt/CardLayout.java + (toString): Changed format of string outputted. + (goToComponent): Changed the order of the if-clause. + +2006-07-31 Tom Tromey + + * INSTALL: Updated for ASM. + +2006-07-31 Tom Tromey + + PR libgcj/23682: + * java/nio/channels/SelectionKey.java (attach): Now synchronized. + (attachment): Likewise. + * java/nio/channels/spi/AbstractSelectionKey.java (cancel): Now + synchronized. + (isValid): Likewise. + * gnu/java/nio/SelectionKeyImpl.java (impl): Now final + (ch): Likewise. + (interestOps): Synchronize. + (readyOps): Likewise. + * gnu/java/nio/SelectorImpl.java (register): Synchronize around + interestOps call. + +2006-07-31 Roman Kennke + + * NEWS: Added note about the X peers. + * INSTALL: Added install notes about the X peers. + +2006-07-31 Carsten Neumann + + * StrictMath.java (getLowDWord): Return long instead of int. + (getHighDWord): Likewise. + (buildDouble): Take two long arguments. + (cbrt): Adapted to int -> long change. + (expm1): Likewise. + (cosh): Likewise. + +2006-07-31 Thomas Fitzsimmons + + * native/jni/qt-peer/Makefile.am (libqtpeer_la_LDFLAGS): Add + -avoid-version. 2006-07-31 Raif S. Naffah @@ -455,12 +1221,66 @@ 6 weeks. (nonLeniencyCheck): weeks is either 5 or 6. +2006-07-30 Andrew John Hughes + + * javax/management/openmbean/OpenMBeanAttributeInfo.java, + * javax/management/openmbean/OpenMBeanParameterInfo.java: + New files. + +2006-07-30 Matt Wringe + + * gnu/java/security/Engine.java + (getInstance): Ignore self referencing aliases. + +2006-07-30 Sven de Marothy + + * java/awt/Choice.java: + (accessibleAction): Call select() directly. + (add, insert, remove): Reimplement. + (dispatchEventImpl): Always call super. + (processItemEvent): Does not set the index. + * include/gnu_java_awt_peer_gtk_GtkChoicePeer.h + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c + (append): removed. + (nativeAdd): Name changed to add. + (selection_changed_cb): Simplify callback. + * gnu/java/awt/peer/gtk/GtkChoicePeer.java + (selected): New field. + (add): Replaced with native impl. + (handleEvent): New method. + +2006-07-30 Sven de Marothy + + * java/awt/Choice.java: + Reformat, fix copyright year. + 2006-07-29 Mark Wielaard * javax/swing/JComponent.java (paintingDoubleBuffered): Renamed static field isPaintingDoubleBuffered to not have the same name as a method. +2006-07-29 Andrew John Hughes + + * examples/gnu/classpath/examples/management/TestBeans.java: + New file. + * javax/management/MBeanAttributeInfo.java: + (toString()): Implemented. + * javax/management/MBeanConstructorInfo.java: + (toString()): Implemented. + * javax/management/MBeanFeatureInfo.java: + (toString()): Implemented. + * javax/management/MBeanInfo.java: + (toString()): Implemented. + * javax/management/MBeanNotificationInfo.java: + (toString()): Implemented. + * javax/management/MBeanOperationInfo.java: + (toString()): Implemented. + * javax/management/MBeanParameterInfo.java: + (toString()): Implemented. + * javax/management/StandardMBean.java: + (getMBeanInfo()): Fix attribute naming. + 2006-07-29 Andrew John Hughes * gnu/java/lang/management/BeanImpl.java: @@ -560,6 +1380,51 @@ (joinSegments): Refactored some code into joinOuterSegments. (solidStroke): Connect segments together properly. +2006-07-28 Thomas Fitzsimmons + + * native/jawt/Makefile.am (libjawt_la_LDFLAGS): Add + -avoid-version. + * native/jni/gtk-peer/Makefile.am (libgtkpeer_la_LDFLAGS): + Likewise. + * native/jni/midi-alsa/Makefile.am (libgjsmalsa_la_LDFLAGS): + Likewise. + * native/jni/midi-dssi/Makefile.am (libgjsmdssi_la_LDFLAGS): + Likewise. + +2006-07-28 Tom Tromey + + * configure.ac: Enable -Werror by default on Linux-with-gcc. + +2006-07-28 Lillian Angel + + * native/jni/gtk-peer/GtkDragSourceContextPeer.c: + Removed function declarations. + (connect_signals_for_widget): Removed implementation because + stub functions have been removed. + (drag_begin_cb): Removed function. + (drag_motion_cb): Likewise. + (drag_data_get_cb): Likewise. + (drag_data_delete_cb): Likewise. + (drag_drop_cb): Likewise. + (drag_end_cb): Likewise. + (drag_data_received_cb): Likewise. + +2006-07-28 Mark Wielaard + + * configure.ac: Set version to 0.93-pre. + +2006-07-29 Raif S. Naffah + + * tools/Makefile.am: Added source 1.4 compliance option when ECJ is used. + +2006-07-29 Raif S. Naffah + + * tools/gnu/classpath/tools/keytool/Command.java: Removed unused import. + (getCallbackHandler): Fully qualify linked class in javadoc. + * tools/gnu/classpath/tools/keytool/GenKeyCmd.java (cmdOptionsParser): Removed. + * tools/gnu/classpath/tools/keytool/ImportCmd.java (imported): Likewise. + * tools/gnu/classpath/tools/keytool/Main.java (printHelp): Likewise. + 2006-07-27 Tom Tromey PR classpath/28486: @@ -2659,10 +3524,10 @@ 2006-07-10 Mario Torre - * java/awt/BasicStroke.java: Removed unused import. - * gnu/java/awt/java2d/CubicSegment.java (clone): Fixed. - * gnu/java/awt/java2d/LineSegment.java (clone): Fixed. - * gnu/java/awt/java2d/QuadSegment.java (clone): Fixed. + * java/awt/BasicStroke.java: Removed unused import. + * gnu/java/awt/java2d/CubicSegment.java (clone): Fixed. + * gnu/java/awt/java2d/LineSegment.java (clone): Fixed. + * gnu/java/awt/java2d/QuadSegment.java (clone): Fixed. 2006-07-10 Matt Wringe diff --git a/INSTALL b/INSTALL index dae909eff..d2bb26621 100644 --- a/INSTALL +++ b/INSTALL @@ -80,6 +80,13 @@ Suggested Software http://www.xmlsoft.org/XSLT/ Minimum version of libxslt required: 1.1.11 + For building the javah tool, you will need the ASM library. + Current version 2.2.1 is needed (other 2.2.x versions should + be ok; 3.x is not ok). You can get ASM from + http://asm.objectweb.org/ + You will need to pass the --with-asm option to configure + and point it at your ASM jar file. + For building the documentation you will need - texinfo 4.2 or higher. @@ -125,6 +132,8 @@ gives a complete list. --enable-xmlj compile native libxml/xslt library default=no --enable-load-library enable to use JNI native methods default=yes --enable-local-sockets enable build of local Unix sockets + --with-asm=/path/to/asm.jar + the ASM jar to use for javah --with-jikes to compile the class library using jikes the default is to use gcj --with-glibj define what to install (zip|flat|both|none) diff --git a/NEWS b/NEWS index 4241f3877..4c81863cf 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +New in release 0.93 (UNRELEASED) + +* The 'javah' tool has been added. It requires the ASM library + (see asm.objectweb.org); it can be enabled with the --with-asm + option to configure +* Added the rmi and corbaname URL context factories for JNDI. +* Fixes in the JNDI InitialContext now allows to plug-in user implementation. + New in release 0.92 (Aug 9, 2006) * libjawtgnu.so has been renamed libjawt.so for binary compatibility. diff --git a/configure.ac b/configure.ac index e4cf75c4d..93a42659b 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ dnl ----------------------------------------------------------- dnl define([AC_CACHE_LOAD], )dnl dnl define([AC_CACHE_SAVE], )dnl -AC_INIT([GNU Classpath],[0.92-generics],[classpath@gnu.org],[classpath]) +AC_INIT([GNU Classpath],[0.93-generics-pre],[classpath@gnu.org],[classpath]) AC_CONFIG_SRCDIR(java/lang/System.java) AC_CANONICAL_TARGET @@ -85,13 +85,17 @@ AM_CONDITIONAL(CREATE_CORE_JNI_LIBRARIES, test "x${COMPILE_CORE_JNI}" = xyes) dnl ----------------------------------------------------------- dnl Default Preference Backend dnl ----------------------------------------------------------- -AC_ARG_ENABLE(default-preferences-peer, - AS_HELP_STRING([--enable-default-preferences-peer], - [fully qualified class name of default Preferences API Backend])) -DEFAULT_PREFS_PEER=$enable_default_preferences_peer -if test "$DEFAULT_PREFS_PEER" = ""; then - DEFAULT_PREFS_PEER=gnu.java.util.prefs.FileBasedFactory -fi +AC_ARG_ENABLE([default-preferences-peer], + [AS_HELP_STRING([--enable-default-preferences-peer@<:@=peer type or class name@:>@], + [specify one of: "gconf" [default] for a GConf based backend, "file" for a file based one, "memory" for a transient one, or a fully qualified class name implementing java.util.prefs.PreferencesFactory])], + [case "${enableval}" in + file) DEFAULT_PREFS_PEER=gnu.java.util.prefs.FileBasedFactory ;; + gconf|yes|true) DEFAULT_PREFS_PEER=gnu.java.util.prefs.GConfBasedFactory ;; + memory) DEFAULT_PREFS_PEER=gnu.java.util.prefs.MemoryBasedFactory ;; + no|false) AC_MSG_ERROR(bad value '${enableval}' for --enable-default-preferences-peer) ;; + *) DEFAULT_PREFS_PEER=${enableval} ;; + esac], + [DEFAULT_PREFS_PEER=gnu.java.util.prefs.GConfBasedFactory]) dnl AC_SUBST(DEFAULT_PREFS_PEER) dnl ----------------------------------------------------------- @@ -120,9 +124,9 @@ AC_ARG_ENABLE([Werror], [case "${enableval}" in yes) ENABLE_WERROR=yes ;; no) ENABLE_WERROR=no ;; - *) ENABLE_WERROR=no ;; + *) ENABLE_WERROR=default ;; esac], - [ENABLE_WERROR=no]) + [ENABLE_WERROR=default]) dnl ----------------------------------------------------------- dnl Default AWT toolkit @@ -305,6 +309,17 @@ dnl AC_PROG_AWK AC_PROG_CC AC_PROG_CPP +# Handle -Werror default case. +if test "$ENABLE_WERROR" = default; then + case "$host_os" in + *linux*) + if test "$GCC" = yes; then + ENABLE_WERROR=yes + fi + ;; + esac +fi + if test "x${COMPILE_COLLECTIONS}" = xyes; then AC_PATH_PROG(PERL, [perl]) AC_SUBST(PERL) @@ -737,17 +752,42 @@ case "$with_escher" in use_escher=false ;; "yes") - AC_MSG_ERROR([Please suply an absolute path to Escher library]) + AC_MSG_ERROR([Please supply an absolute path to Escher library]) ;; *) use_escher=true PATH_TO_ESCHER=$with_escher ;; -esac; +esac AM_CONDITIONAL(USE_ESCHER, test x$use_escher = xtrue) AC_SUBST(PATH_TO_ESCHER) +dnl ----------------------------------------------------------- +dnl Build javah using ASM library +dnl ----------------------------------------------------------- +AC_ARG_WITH([asm], + AS_HELP_STRING([--with-asm=ABS.PATH], + [specify path to ASM jar for javah])) +case "$with_asm" in +"") + use_asm=false + ;; +"no") + use_asm=false + ;; +"yes") + AC_MSG_ERROR([Please supply an absolute path to ASM jar]) + ;; +*) + use_asm=true + PATH_TO_ASM=$with_asm + ;; +esac + +AM_CONDITIONAL(USE_ASM, test x$use_asm = xtrue) +AC_SUBST(PATH_TO_ASM) + dnl ----------------------------------------------------------- dnl Check if local socket support should be included. dnl ----------------------------------------------------------- @@ -836,6 +876,11 @@ AC_CONFIG_COMMANDS([gkeytool],[chmod 755 tools/gkeytool]) AC_CONFIG_COMMANDS([gjar],[chmod 755 tools/gjar]) AC_CONFIG_COMMANDS([gnative2ascii],[chmod 755 tools/gnative2ascii]) AC_CONFIG_COMMANDS([gserialver],[chmod 755 tools/gserialver]) + + if test "$use_asm" = true; then + AC_CONFIG_FILES([tools/gjavah]) + AC_CONFIG_COMMANDS([gjavah], [chmod 755 tools/gjavah]) + fi fi AC_CONFIG_COMMANDS([gen-classlist],[chmod 755 lib/gen-classlist.sh]) @@ -847,4 +892,3 @@ cat ${srcdir}/lib/standard.omit.in > lib/standard.omit if test x$use_escher != xtrue; then echo gnu/java/awt/peer/x/.*java$ >> lib/standard.omit fi - diff --git a/gnu/CORBA/Connected_objects.java b/gnu/CORBA/Connected_objects.java index ce5761007..53ef2dd17 100644 --- a/gnu/CORBA/Connected_objects.java +++ b/gnu/CORBA/Connected_objects.java @@ -242,4 +242,14 @@ public class Connected_objects free_object_number++; return instance_number; } + + /** + * Get the number of the connected objects. + * + * @return the size of the internal map. + */ + public int size() + { + return objects.size(); + } } \ No newline at end of file diff --git a/gnu/CORBA/OrbFunctional.java b/gnu/CORBA/OrbFunctional.java index 7b9c34ada..9695fdc82 100644 --- a/gnu/CORBA/OrbFunctional.java +++ b/gnu/CORBA/OrbFunctional.java @@ -1775,4 +1775,14 @@ public class OrbFunctional extends OrbRestricted running = false; super.finalize(); } + + /** + * Get the number of objects that are connected to this ORB. + * + * @return the number of objects, connected to this ORB. + */ + public int countConnectedObjects() + { + return connected_objects.size(); + } } \ No newline at end of file diff --git a/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java b/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java index 4f9229822..b68fa1058 100644 --- a/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java +++ b/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java @@ -61,11 +61,13 @@ public class GtkDragSourceContextPeer private ComponentPeer peer; private Cursor cursor; private DragSourceContext context; + public static Component target; native void nativeStartDrag(Image i, int x, int y, int action, String target); native void connectSignals(ComponentPeer comp); native void create(ComponentPeer comp); native void nativeSetCursor(int cursor); + native void setTarget(GtkDropTargetContextPeer target); public GtkDragSourceContextPeer(DragGestureEvent e) { @@ -76,10 +78,18 @@ public class GtkDragSourceContextPeer create(peer); connectSignals(peer); cursor = comp.getCursor(); + + // FIXME: Where do we set the target? + + if ((target != null)) + setTarget(new GtkDropTargetContextPeer(target)); } ComponentPeer getComponentPeer(Component c) { + if (c == null) + return null; + Component curr = c; while (curr.getPeer() instanceof LightweightPeer) curr = curr.getParent(); @@ -93,7 +103,7 @@ public class GtkDragSourceContextPeer throws InvalidDnDOperationException { this.context = context; - + if (p == null) p = new Point(); diff --git a/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java b/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java index 50cd95d41..f24b3f39b 100644 --- a/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java +++ b/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java @@ -50,10 +50,10 @@ public class GtkDropTargetContextPeer extends GtkGenericPeer implements DropTargetContextPeer { - - public GtkDropTargetContextPeer() + + public GtkDropTargetContextPeer(Object obj) { - super(null); + super(obj); } public void setTargetActions(int actions) diff --git a/gnu/java/awt/peer/GLightweightPeer.java b/gnu/java/awt/peer/GLightweightPeer.java index 88733b92f..3029502ff 100644 --- a/gnu/java/awt/peer/GLightweightPeer.java +++ b/gnu/java/awt/peer/GLightweightPeer.java @@ -54,25 +54,14 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.awt.event.PaintEvent; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.VolatileImage; -import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; import java.awt.peer.LightweightPeer; -/* - * Another possible implementation strategy for lightweight peers is - * to make GLightweightPeer a placeholder class that implements - * LightweightPeer. Then the Component and Container classes could - * identify a peer as lightweight and handle it specially. The - * current approach is probably more clear but less efficient. - */ - /** * A stub class that implements the ComponentPeer and ContainerPeer * interfaces using callbacks into the Component and Container @@ -85,47 +74,48 @@ import java.awt.peer.LightweightPeer; public class GLightweightPeer implements LightweightPeer, ContainerPeer { - private Component comp; - - private Insets containerInsets; - - public GLightweightPeer(Component comp) + public GLightweightPeer() { - this.comp = comp; + // Nothing to do here. } // -------- java.awt.peer.ContainerPeer implementation: public Insets insets() { - return getInsets (); + // Nothing to do here for lightweights. + return null; } public Insets getInsets() { - if (containerInsets == null) - containerInsets = new Insets (0,0,0,0); - return containerInsets; + // Nothing to do here for lightweights. + return null; } public void beginValidate() { + // Nothing to do here for lightweights. } public void endValidate() { + // Nothing to do here for lightweights. } public void beginLayout() { + // Nothing to do here for lightweights. } public void endLayout() { + // Nothing to do here for lightweights. } public boolean isPaintPending() { + // Nothing to do here for lightweights. return false; } @@ -133,122 +123,162 @@ public class GLightweightPeer public int checkImage(Image img, int width, int height, ImageObserver o) { - return comp.getToolkit().checkImage(img, width, height, o); + // Nothing to do here for lightweights. + return -1; } public Image createImage(ImageProducer prod) { - return comp.getToolkit().createImage(prod); + // Nothing to do here for lightweights. + return null; } /* This method is not called. */ public Image createImage(int width, int height) { + // Nothing to do here for lightweights. return null; } - public void disable() {} + public void disable() + { + // Nothing to do here for lightweights. + } - public void dispose() {} + public void dispose() + { + // Nothing to do here for lightweights. + } - public void enable() {} + public void enable() + { + // Nothing to do here for lightweights. + } public GraphicsConfiguration getGraphicsConfiguration() { + // Nothing to do here for lightweights. return null; } public FontMetrics getFontMetrics(Font f) { - return comp.getToolkit().getFontMetrics(f); + // Nothing to do here for lightweights. + return null; } /* Returning null here tells the Component object that called us to * use its parent's Graphics. */ public Graphics getGraphics() { + // Nothing to do here for lightweights. return null; } public Point getLocationOnScreen() { - Point parentLocation = comp.getParent().getLocationOnScreen(); - return new Point (parentLocation.x + comp.getX(), - parentLocation.y + comp.getY()); + // Nothing to do here for lightweights. + return null; } public Dimension getMinimumSize() { - return new Dimension(comp.getWidth(), comp.getHeight()); + return minimumSize(); } - /* A lightweight component's preferred size is equivalent to its - * Component width and height values. */ public Dimension getPreferredSize() { - return new Dimension(comp.getWidth(), comp.getHeight()); + return preferredSize(); } /* Returning null here tells the Component object that called us to * use its parent's Toolkit. */ public Toolkit getToolkit() { + // Nothing to do here for lightweights. return null; } - public void handleEvent(AWTEvent e) {} + public void handleEvent(AWTEvent e) + { + // Nothing to do here for lightweights. + } - public void hide() {} + public void hide() + { + // Nothing to do here for lightweights. + } public boolean isFocusable() { + // Nothing to do here for lightweights. return false; } public boolean isFocusTraversable() { + // Nothing to do here for lightweights. return false; } public Dimension minimumSize() { - return getMinimumSize(); + return new Dimension(0, 0); } public Dimension preferredSize() { - return getPreferredSize(); + return new Dimension(0, 0); } - public void paint(Graphics graphics) {} + public void paint(Graphics graphics) + { + // Nothing to do here for lightweights. + } public boolean prepareImage(Image img, int width, int height, ImageObserver o) { - return comp.getToolkit().prepareImage(img, width, height, o); + // Nothing to do here for lightweights. + return false; } - public void print(Graphics graphics) {} + public void print(Graphics graphics) + { + // Nothing to do here for lightweights. + } public void repaint(long tm, int x, int y, int width, int height) { - Component p = comp.getParent(); - if (p != null) - p.repaint(tm, x + comp.getX(), y + comp.getY(), width, height); + // Nothing to do here for lightweights. } - public void requestFocus() {} + public void requestFocus() + { + // Nothing to do here for lightweights. + } - public boolean requestFocus(Component source, boolean bool1, boolean bool2, long x) + public boolean requestFocus(Component source, boolean bool1, boolean bool2, + long x) { + // Nothing to do here for lightweights. return false; } - public void reshape(int x, int y, int width, int height) {} + public void reshape(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } - public void setBackground(Color color) {} + public void setBackground(Color color) + { + // Nothing to do here for lightweights. + } - public void setBounds(int x, int y, int width, int height) {} + public void setBounds(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } /** * Sets the cursor on the heavy-weight parent peer. @@ -256,110 +286,141 @@ public class GLightweightPeer */ public void setCursor(Cursor cursor) { - Component p = comp.getParent(); - while (p != null && p.isLightweight()) - p = p.getParent(); - - if (p != null) - { - // Don't actually change the cursor of the component - // otherwise other childs inherit this cursor. - ComponentPeer peer = p.getPeer(); - if (peer != null) - peer.setCursor(cursor); - } + // Nothing to do here for lightweights. } - public void setEnabled(boolean enabled) {} + public void setEnabled(boolean enabled) + { + // Nothing to do here for lightweights. + } - public void setEventMask(long eventMask) {} + public void setEventMask(long eventMask) + { + // Nothing to do here for lightweights. + } - public void setFont(Font font) {} + public void setFont(Font font) + { + // Nothing to do here for lightweights. + } - public void setForeground(Color color) {} + public void setForeground(Color color) + { + // Nothing to do here for lightweights. + } - public void setVisible(boolean visible) {} + public void setVisible(boolean visible) + { + // Nothing to do here for lightweights. + } - public void show() {} + public void show() + { + // Nothing to do here for lightweights. + } - public ColorModel getColorModel () + public ColorModel getColorModel() { - return comp.getColorModel (); + // Nothing to do here for lightweights. + return null; } public boolean isObscured() { + // Nothing to do here for lightweights. return false; } public boolean canDetermineObscurity() { + // Nothing to do here for lightweights. return false; } - public void coalescePaintEvent(PaintEvent e) { } + public void coalescePaintEvent(PaintEvent e) + { + // Nothing to do here for lightweights. + } - public void updateCursorImmediately() { } + public void updateCursorImmediately() + { + // Nothing to do here for lightweights. + } public VolatileImage createVolatileImage(int width, int height) { + // Nothing to do here for lightweights. return null; } public boolean handlesWheelScrolling() { + // Nothing to do here for lightweights. return false; } public void createBuffers(int x, BufferCapabilities capabilities) - throws AWTException { } + throws AWTException + { + // Nothing to do here for lightweights. + } public Image getBackBuffer() { + // Nothing to do here for lightweights. return null; } - public void flip(BufferCapabilities.FlipContents contents) { } + public void flip(BufferCapabilities.FlipContents contents) + { + // Nothing to do here for lightweights. + } - public void destroyBuffers() { } + public void destroyBuffers() + { + // Nothing to do here for lightweights. + } public boolean isRestackSupported() { + // Nothing to do here for lightweights. return false; } public void cancelPendingPaint(int x, int y, int width, int height) { - + // Nothing to do here for lightweights. } public void restack() { - + // Nothing to do here for lightweights. } public Rectangle getBounds() { + // Nothing to do here for lightweights. return null; } public void reparent(ContainerPeer parent) { - + // Nothing to do here for lightweights. } public void setBounds(int x, int y, int z, int width, int height) { - + // Nothing to do here for lightweights. } public boolean isReparentSupported() { - return false; + // Nothing to do here for lightweights. + return true; } public void layout() { - + // Nothing to do here for lightweights. } } diff --git a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java index 6a74eabc5..5412cbea9 100644 --- a/gnu/java/awt/peer/gtk/BufferedImageGraphics.java +++ b/gnu/java/awt/peer/gtk/BufferedImageGraphics.java @@ -48,6 +48,7 @@ import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.Raster; import java.awt.image.DataBuffer; import java.awt.image.DataBufferInt; import java.awt.image.ColorModel; @@ -128,17 +129,17 @@ public class BufferedImageGraphics extends CairoGraphics2D cairo_t = surface.newCairoContext(); - DataBuffer db = bi.getRaster().getDataBuffer(); + Raster raster = bi.getRaster(); int[] pixels; // get pixels - if(db instanceof CairoSurface) - pixels = ((CairoSurface)db).getPixels(imageWidth * imageHeight); + if(raster instanceof CairoSurface) + pixels = ((CairoSurface)raster).getPixels(imageWidth * imageHeight); else { if( hasFastCM ) { - pixels = ((DataBufferInt)db).getData(); + pixels = ((DataBufferInt)raster.getDataBuffer()).getData(); if( !hasAlpha ) for(int i = 0; i < pixels.length; i++) pixels[i] &= 0xFFFFFFFF; diff --git a/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/gnu/java/awt/peer/gtk/CairoGraphics2D.java index b665f562e..8fe04fe77 100644 --- a/gnu/java/awt/peer/gtk/CairoGraphics2D.java +++ b/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -1269,7 +1269,7 @@ public abstract class CairoGraphics2D extends Graphics2D } BufferedImage b = (BufferedImage) img; - DataBuffer db; + Raster raster; double[] i2u = new double[6]; int width = b.getWidth(); int height = b.getHeight(); @@ -1278,9 +1278,9 @@ public abstract class CairoGraphics2D extends Graphics2D // use the cached CairoSurface that BIG is drawing onto if( BufferedImageGraphics.bufferedImages.get( b ) != null ) - db = (DataBuffer)BufferedImageGraphics.bufferedImages.get( b ); + raster = (Raster)BufferedImageGraphics.bufferedImages.get( b ); else - db = b.getRaster().getDataBuffer(); + raster = b.getRaster(); invertedXform.getMatrix(i2u); @@ -1288,9 +1288,9 @@ public abstract class CairoGraphics2D extends Graphics2D if (comp instanceof AlphaComposite) alpha = ((AlphaComposite) comp).getAlpha(); - if(db instanceof CairoSurface) + if(raster instanceof CairoSurface) { - ((CairoSurface)db).drawSurface(nativePointer, i2u, alpha); + ((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha); updateColor(); return true; } diff --git a/gnu/java/awt/peer/gtk/CairoSurface.java b/gnu/java/awt/peer/gtk/CairoSurface.java index 78bc1e02d..3bf9a9ccf 100644 --- a/gnu/java/awt/peer/gtk/CairoSurface.java +++ b/gnu/java/awt/peer/gtk/CairoSurface.java @@ -46,6 +46,7 @@ import java.awt.image.WritableRaster; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; +import java.awt.image.SinglePixelPackedSampleModel; import java.nio.ByteOrder; import java.util.Hashtable; @@ -54,7 +55,7 @@ import java.util.Hashtable; * * @author Sven de Marothy */ -public class CairoSurface extends DataBuffer +public class CairoSurface extends WritableRaster { int width = -1, height = -1; @@ -68,7 +69,6 @@ public class CairoSurface extends DataBuffer */ long bufferPointer; - static ColorModel nativeModel = new DirectColorModel(32, 0x00FF0000, 0x0000FF00, @@ -138,18 +138,22 @@ public class CairoSurface extends DataBuffer */ public CairoSurface(int width, int height) { - super(DataBuffer.TYPE_INT, width * height); + super( new SinglePixelPackedSampleModel + (DataBuffer.TYPE_INT, width, height, + new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }), + null, new Point(0, 0) ); if(width <= 0 || height <= 0) throw new IllegalArgumentException("Image must be at least 1x1 pixels."); - + this.width = width; this.height = height; - create(width, height, width); if(surfacePointer == 0 || bufferPointer == 0) throw new Error("Could not allocate bitmap."); + + dataBuffer = new CairoDataBuffer(); } /** @@ -158,18 +162,7 @@ public class CairoSurface extends DataBuffer */ CairoSurface(GtkImage image) { - super(DataBuffer.TYPE_INT, image.width * image.height); - - if(image.width <= 0 || image.height <= 0) - throw new IllegalArgumentException("Image must be at least 1x1 pixels."); - - width = image.width; - height = image.height; - - create(width, height, width); - - if(surfacePointer == 0 || bufferPointer == 0) - throw new Error("Could not allocate bitmap."); + this(image.width, image.height); // Copy the pixel data from the GtkImage. int[] data = image.getPixels(); @@ -260,32 +253,35 @@ public class CairoSurface extends DataBuffer */ public static BufferedImage getBufferedImage(CairoSurface surface) { - WritableRaster raster = Raster.createPackedRaster - (surface, surface.width, surface.height, surface.width, - new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 }, - new Point(0,0)); - - return new BufferedImage(nativeModel, raster, true, new Hashtable()); + return new BufferedImage(nativeModel, surface, true, new Hashtable()); } - /** - * DataBank.getElem implementation - */ - public int getElem(int bank, int i) + private class CairoDataBuffer extends DataBuffer { - if(bank != 0 || i < 0 || i >= width*height) - throw new IndexOutOfBoundsException(i+" size: "+width*height); - return nativeGetElem(bufferPointer, i); - } + public CairoDataBuffer() + { + super(DataBuffer.TYPE_INT, width * height); + } + + /** + * DataBuffer.getElem implementation + */ + public int getElem(int bank, int i) + { + if(bank != 0 || i < 0 || i >= width * height) + throw new IndexOutOfBoundsException(i+" size: "+width * height); + return nativeGetElem(bufferPointer, i); + } - /** - * DataBank.setElem implementation - */ - public void setElem(int bank, int i, int val) - { - if(bank != 0 || i < 0 || i >= width*height) - throw new IndexOutOfBoundsException(i+" size: "+width*height); - nativeSetElem(bufferPointer, i, val); + /** + * DataBuffer.setElem implementation + */ + public void setElem(int bank, int i, int val) + { + if(bank != 0 || i < 0 || i >= width*height) + throw new IndexOutOfBoundsException(i+" size: "+width * height); + nativeSetElem(bufferPointer, i, val); + } } /** diff --git a/gnu/java/awt/peer/gtk/ComponentGraphics.java b/gnu/java/awt/peer/gtk/ComponentGraphics.java index ffa78e9c9..d9d173118 100644 --- a/gnu/java/awt/peer/gtk/ComponentGraphics.java +++ b/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -71,32 +71,6 @@ public class ComponentGraphics extends CairoGraphics2D private static ThreadLocal hasLock = new ThreadLocal(); private static Integer ONE = Integer.valueOf(1); - private void lock() - { - Integer i = (Integer) hasLock.get(); - if (i == null) - { - start_gdk_drawing(); - hasLock.set(ONE); - } - else - hasLock.set(Integer.valueOf(i.intValue() + 1)); - } - - private void unlock() - { - Integer i = (Integer) hasLock.get(); - if (i == null) - throw new IllegalStateException(); - if (i == ONE) - { - hasLock.set(null); - end_gdk_drawing(); - } - else - hasLock.set(Integer.valueOf(i.intValue() - 1)); - } - ComponentGraphics() { } @@ -128,6 +102,32 @@ public class ComponentGraphics extends CairoGraphics2D */ private native long initState(GtkComponentPeer component); + private void lock() + { + Integer i = (Integer) hasLock.get(); + if (i == null) + { + start_gdk_drawing(); + hasLock.set(ONE); + } + else + hasLock.set(Integer.valueOf(i.intValue() + 1)); + } + + private void unlock() + { + Integer i = (Integer) hasLock.get(); + if (i == null) + throw new IllegalStateException(); + if (i == ONE) + { + hasLock.set(null); + end_gdk_drawing(); + } + else + hasLock.set(Integer.valueOf(i.intValue() - 1)); + } + /** * Destroys the component surface and calls dispose on the cairo * graphics2d to destroy any super class resources. diff --git a/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java index e095c7dad..db725b697 100644 --- a/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java +++ b/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -44,7 +44,7 @@ import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; +import java.awt.image.Raster; import java.util.Locale; public class GdkGraphicsEnvironment extends GraphicsEnvironment @@ -103,9 +103,9 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment public Graphics2D createGraphics (BufferedImage image) { - DataBuffer db = image.getRaster().getDataBuffer(); - if(db instanceof CairoSurface) - return ((CairoSurface)db).getGraphics(); + Raster raster = image.getRaster(); + if(raster instanceof CairoSurface) + return ((CairoSurface)raster).getGraphics(); return new BufferedImageGraphics( image ); } diff --git a/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/gnu/java/awt/peer/gtk/GtkChoicePeer.java index ed7dc74d2..d866cefd3 100644 --- a/gnu/java/awt/peer/gtk/GtkChoicePeer.java +++ b/gnu/java/awt/peer/gtk/GtkChoicePeer.java @@ -39,12 +39,15 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; import java.awt.Choice; +import java.awt.AWTEvent; import java.awt.event.ItemEvent; import java.awt.peer.ChoicePeer; public class GtkChoicePeer extends GtkComponentPeer implements ChoicePeer { + private int selected; + public GtkChoicePeer (Choice c) { super (c); @@ -52,75 +55,53 @@ public class GtkChoicePeer extends GtkComponentPeer int count = c.getItemCount (); if (count > 0) { - String items[] = new String[count]; for (int i = 0; i < count; i++) - items[i] = c.getItem (i); - - append (items); - } + add( c.getItem(i), i ); - int selected = c.getSelectedIndex(); - if (selected >= 0) - select(selected); + selected = c.getSelectedIndex(); + if( selected >= 0 ) + select( selected ); + } + else + selected = -1; } native void create (); - native void append (String items[]); native int nativeGetSelected (); - native void nativeAdd (String item, int index); - native void nativeRemove (int index); - native void nativeRemoveAll (); native void connectSignals (); native void selectNative (int position); + native void selectNativeUnlocked (int position); + public native void add (String item, int index); + + native void nativeRemove(int index); + + native void nativeRemoveAll(); + public void select (int position) { - if (Thread.currentThread() == GtkToolkit.mainThread) + if (Thread.currentThread() == GtkMainThread.mainThread) selectNativeUnlocked (position); else selectNative (position); } - public void add (String item, int index) + public void remove( int index ) { - int before = nativeGetSelected(); - - nativeAdd (item, index); - - /* Generate an ItemEvent if we added the first one or - if we inserted at or before the currently selected item. */ - if ((before < 0) || (before >= index)) - { - // Must set our state before notifying listeners - ((Choice) awtComponent).select (((Choice) awtComponent).getItem (0)); - postItemEvent (((Choice) awtComponent).getItem (0), ItemEvent.SELECTED); - } + // Ensure the triggering of an event when removing item zero if zero is the + // selected item, even though the selected index doesn't change. + if( index == 0 && selected == 0 ) + selected = -1; + nativeRemove( index ); } - public void remove (int index) - { - int before = nativeGetSelected(); - int after; - - nativeRemove (index); - after = nativeGetSelected(); - - /* Generate an ItemEvent if we are removing the currently selected item - and there are at least one item left. */ - if ((before == index) && (after >= 0)) - { - // Must set our state before notifying listeners - ((Choice) awtComponent).select (((Choice) awtComponent).getItem (0)); - postItemEvent (((Choice) awtComponent).getItem (0), ItemEvent.SELECTED); - } - } - - public void removeAll () + public void removeAll() { + selected = -1; // we do not want to trigger a select event here. nativeRemoveAll(); } @@ -129,8 +110,34 @@ public class GtkChoicePeer extends GtkComponentPeer add (item, position); } - protected void postChoiceItemEvent (String label, int stateChange) + /** + * Callback from the native side on an item-select event, + * which posts an event. The event is only posted if it represents an actual + * change. Selected is set to the peer's state initially, so that the + * first call to select(int) from the constructor will not trigger an event. + * (it should not) + */ + protected void postChoiceItemEvent ( int index ) + { + if( selected != index ) + { + selected = index; + postItemEvent (((Choice) awtComponent).getItem( selected ), + ItemEvent.SELECTED); + } + } + + /** + * Catches the event and calls Choice.select() if the component state + * needs updating. + */ + public void handleEvent (AWTEvent event) { - postItemEvent (label, stateChange); + super.handleEvent( event ); + if( event instanceof ItemEvent ) + if( ((ItemEvent)event).getItemSelectable() == awtComponent && + ((ItemEvent)event).getStateChange() == ItemEvent.SELECTED ) + ((Choice)awtComponent).select( selected ); } } + diff --git a/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/gnu/java/awt/peer/gtk/GtkComponentPeer.java index c11c45e20..f96033e56 100644 --- a/gnu/java/awt/peer/gtk/GtkComponentPeer.java +++ b/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -514,7 +514,7 @@ public class GtkComponentPeer extends GtkGenericPeer y = 0; } - if (Thread.currentThread() == GtkToolkit.mainThread) + if (Thread.currentThread() == GtkMainThread.mainThread) gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y); else gtkWidgetSetCursor(cursor.getType(), image, x, y); @@ -562,7 +562,7 @@ public class GtkComponentPeer extends GtkGenericPeer b = (bounds.width > 0) && (bounds.height > 0); } - if (Thread.currentThread() == GtkToolkit.mainThread) + if (Thread.currentThread() == GtkMainThread.mainThread) setVisibleNativeUnlocked (b); else setVisibleNative (b); diff --git a/gnu/java/awt/peer/gtk/GtkMainThread.java b/gnu/java/awt/peer/gtk/GtkMainThread.java new file mode 100644 index 000000000..19d3f1d0b --- /dev/null +++ b/gnu/java/awt/peer/gtk/GtkMainThread.java @@ -0,0 +1,97 @@ +/* GtkMainThread.java -- Wrapper for the GTK main thread, and some utilities. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +public class GtkMainThread extends Thread +{ + /** Count of the number of open windows */ + private static int numberOfWindows = 0; + + /** Lock for the above */ + private static Object nWindowsLock = new Object(); + + /** The main thread instance (singleton) */ + public static GtkMainThread mainThread; + + /** Constructs a main thread */ + private GtkMainThread() + { + super("GTK main thread"); + } + + public void run () + { + GtkToolkit.gtkMain (); + } + + private static void startMainThread() + { + if( mainThread == null ) + { + mainThread = new GtkMainThread(); + mainThread.start(); + } + } + + private static void endMainThread() + { + if( mainThread != null ) + GtkToolkit.gtkQuit(); + } + + public static void createWindow() + { + synchronized( nWindowsLock ) + { + if( numberOfWindows == 0 ) + startMainThread(); + numberOfWindows++; + } + } + + public static void destroyWindow() + { + synchronized( nWindowsLock ) + { + numberOfWindows--; + if( numberOfWindows == 0 ) + endMainThread(); + } + } +} \ No newline at end of file diff --git a/gnu/java/awt/peer/gtk/GtkToolkit.java b/gnu/java/awt/peer/gtk/GtkToolkit.java index 6aa87fc2e..3f87ca6e6 100644 --- a/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -131,37 +131,30 @@ import javax.imageio.spi.IIORegistry; public class GtkToolkit extends gnu.java.awt.ClasspathToolkit { - Hashtable containers = new Hashtable(); - static EventQueue q; - static Thread mainThread; + private static EventQueue q; static native void gtkInit(int portableNativeSync); + static native void gtkMain(); + + static native void gtkQuit(); + static { System.loadLibrary("gtkpeer"); - + int portableNativeSync; String portNatSyncProp = System.getProperty("gnu.classpath.awt.gtk.portable.native.sync"); - + if (portNatSyncProp == null) portableNativeSync = -1; // unset else if (Boolean.valueOf(portNatSyncProp).booleanValue()) portableNativeSync = 1; // true else portableNativeSync = 0; // false - + gtkInit(portableNativeSync); - - mainThread = new Thread ("GTK main thread") - { - public void run () - { - gtkMain (); - } - }; - mainThread.start (); } public GtkToolkit () @@ -169,6 +162,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit } public native void beep(); + private native void getScreenSizeDimensions(int[] xy); public int checkImage (Image image, int width, int height, @@ -462,6 +456,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit protected DialogPeer createDialog (Dialog d) { + GtkMainThread.createWindow(); return new GtkDialogPeer (d); } @@ -472,6 +467,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit protected FramePeer createFrame (Frame f) { + GtkMainThread.createWindow(); return new GtkFramePeer (f); } @@ -532,11 +528,13 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit protected WindowPeer createWindow (Window w) { + GtkMainThread.createWindow(); return new GtkWindowPeer (w); } public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w) { + GtkMainThread.createWindow(); return new GtkEmbeddedWindowPeer (w); } @@ -661,8 +659,6 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit GdkPixbufDecoder.registerSpis(reg); } - public static native void gtkMain(); - protected MouseInfoPeer getMouseInfoPeer() { return new GtkMouseInfoPeer(); diff --git a/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/gnu/java/awt/peer/gtk/GtkWindowPeer.java index 866d9c881..1f340611e 100644 --- a/gnu/java/awt/peer/gtk/GtkWindowPeer.java +++ b/gnu/java/awt/peer/gtk/GtkWindowPeer.java @@ -75,6 +75,12 @@ public class GtkWindowPeer extends GtkContainerPeer native boolean gtkWindowHasFocus(); native void realize (); + public void dispose() + { + super.dispose(); + GtkMainThread.destroyWindow(); + } + /** Returns the cached width of the AWT window component. */ int getX () { diff --git a/gnu/java/lang/management/BeanImpl.java b/gnu/java/lang/management/BeanImpl.java index 24572a25d..529ee5896 100644 --- a/gnu/java/lang/management/BeanImpl.java +++ b/gnu/java/lang/management/BeanImpl.java @@ -39,9 +39,50 @@ package gnu.java.lang.management; import java.lang.management.ManagementPermission; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.TypeVariable; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.AttributeNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanInfo; import javax.management.NotCompliantMBeanException; +import javax.management.ReflectionException; import javax.management.StandardMBean; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenMBeanAttributeInfo; +import javax.management.openmbean.OpenMBeanAttributeInfoSupport; +import javax.management.openmbean.OpenMBeanConstructorInfo; +import javax.management.openmbean.OpenMBeanConstructorInfoSupport; +import javax.management.openmbean.OpenMBeanInfo; +import javax.management.openmbean.OpenMBeanInfoSupport; +import javax.management.openmbean.OpenMBeanOperationInfo; +import javax.management.openmbean.OpenMBeanOperationInfoSupport; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + /** * A common superclass for bean implementations. * @@ -51,7 +92,12 @@ import javax.management.StandardMBean; public class BeanImpl extends StandardMBean { - + + /** + * Cached open bean information. + */ + private OpenMBeanInfo openInfo; + /** * Constructs a new BeanImpl. * @@ -67,6 +113,71 @@ public class BeanImpl super(iface); } + protected void cacheMBeanInfo(MBeanInfo info) + { + if (info == null) + return; + try + { + MBeanAttributeInfo[] oldA = info.getAttributes(); + OpenMBeanAttributeInfo[] attribs = + new OpenMBeanAttributeInfoSupport[oldA.length]; + for (int a = 0; a < oldA.length; ++a) + { + OpenMBeanParameterInfo param = translate(oldA[a].getType()); + if (param.getMinValue() == null) + { + Object[] lv; + if (param.getLegalValues() == null) + lv = null; + else + lv = param.getLegalValues().toArray(); + attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), + oldA[a].getDescription(), + param.getOpenType(), + oldA[a].isReadable(), + oldA[a].isWritable(), + oldA[a].isIs(), + param.getDefaultValue(), + lv); + } + else + attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), + oldA[a].getDescription(), + param.getOpenType(), + oldA[a].isReadable(), + oldA[a].isWritable(), + oldA[a].isIs(), + param.getDefaultValue(), + param.getMinValue(), + param.getMaxValue()); + } + MBeanConstructorInfo[] oldC = info.getConstructors(); + OpenMBeanConstructorInfo[] cons = new OpenMBeanConstructorInfoSupport[oldC.length]; + for (int a = 0; a < oldC.length; ++a) + cons[a] = + new OpenMBeanConstructorInfoSupport(oldC[a].getName(), + oldC[a].getDescription(), + translateSignature(oldC[a].getSignature())); + MBeanOperationInfo[] oldO = info.getOperations(); + OpenMBeanOperationInfo[] ops = new OpenMBeanOperationInfoSupport[oldO.length]; + for (int a = 0; a < oldO.length; ++a) + ops[a] = + new OpenMBeanOperationInfoSupport(oldO[a].getName(), + oldO[a].getDescription(), + translateSignature(oldO[a].getSignature()), + translate(oldO[a].getReturnType()).getOpenType(), + oldO[a].getImpact()); + openInfo = new OpenMBeanInfoSupport(info.getClassName(), info.getDescription(), + attribs, cons, ops, info.getNotifications()); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred creating the open type " + + "descriptors.").initCause(e)); + } + } + protected void checkMonitorPermissions() { SecurityManager sm = System.getSecurityManager(); @@ -81,4 +192,335 @@ public class BeanImpl sm.checkPermission(new ManagementPermission("control")); } + public Object getAttribute(String attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException + { + Object value = super.getAttribute(attribute); + if (value instanceof Enum) + return ((Enum) value).name(); + Class vClass = value.getClass(); + if (vClass.isArray()) + return value; + String cName = vClass.getName(); + String[] allowedTypes = OpenType.ALLOWED_CLASSNAMES; + for (int a = 0; a < allowedTypes.length; ++a) + if (cName.equals(allowedTypes[a])) + return value; + if (value instanceof List) + { + List l = (List) value; + Class e = null; + TypeVariable[] vars = vClass.getTypeParameters(); + for (int a = 0; a < vars.length; ++a) + if (vars[a].getName().equals("E")) + e = (Class) vars[a].getGenericDeclaration(); + if (e == null) + e = Object.class; + Object[] array = (Object[]) Array.newInstance(e, l.size()); + return l.toArray(array); + } + OpenMBeanInfo info = (OpenMBeanInfo) getMBeanInfo(); + OpenMBeanAttributeInfo[] attribs = + (OpenMBeanAttributeInfo[]) info.getAttributes(); + OpenType type = null; + for (int a = 0; a < attribs.length; ++a) + if (attribs[a].getName().equals("attribute")) + type = attribs[a].getOpenType(); + if (value instanceof Map) + { + TabularType ttype = (TabularType) type; + TabularData data = new TabularDataSupport(ttype); + Iterator it = ((Map) value).entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + try + { + data.put(new CompositeDataSupport(ttype.getRowType(), + new String[] { + "key", + "value" + }, + new Object[] { + entry.getKey(), + entry.getValue() + })); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the map " + + "to a composite data " + + "structure.").initCause(e)); + } + } + return data; + } + CompositeType cType = (CompositeType) type; + Set names = cType.keySet(); + Iterator it = names.iterator(); + List values = new ArrayList(names.size()); + while (it.hasNext()) + { + String field = (String) it.next(); + Method getter = null; + try + { + getter = vClass.getMethod("get" + field, null); + } + catch (NoSuchMethodException e) + { + /* Ignored; the type tells us it's there. */ + } + try + { + values.add(getter.invoke(value, null)); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to retrieve " + field); + } + catch (IllegalArgumentException e) + { + throw new ReflectionException(e, "Failed to retrieve " + field); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), + "The getter of " + field + + " threw an exception"); + } + } + try + { + return new CompositeDataSupport(cType, + (String[]) + names.toArray(new String[names.size()]), + values.toArray()); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the value " + + "to a composite data " + + "structure.").initCause(e)); + } + } + + protected MBeanInfo getCachedMBeanInfo() + { + return (MBeanInfo) openInfo; + } + + public MBeanInfo getMBeanInfo() + { + super.getMBeanInfo(); + return getCachedMBeanInfo(); + } + + private OpenType getTypeFromClass(Class c) + throws OpenDataException + { + return translate(c.getName()).getOpenType(); + } + + private OpenMBeanParameterInfo[] translateSignature(MBeanParameterInfo[] oldS) + throws OpenDataException + { + OpenMBeanParameterInfo[] sig = new OpenMBeanParameterInfoSupport[oldS.length]; + for (int a = 0; a < oldS.length; ++a) + { + OpenMBeanParameterInfo param = translate(oldS[a].getType()); + if (param.getMinValue() == null) + { + Object[] lv; + if (param.getLegalValues() == null) + lv = null; + else + lv = param.getLegalValues().toArray(); + sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), + oldS[a].getDescription(), + param.getOpenType(), + param.getDefaultValue(), + lv); + } + else + sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), + oldS[a].getDescription(), + param.getOpenType(), + param.getDefaultValue(), + param.getMinValue(), + param.getMaxValue()); + } + return sig; + } + + private OpenMBeanParameterInfo translate(String type) + throws OpenDataException + { + if (type.equals("boolean") || type.equals(Boolean.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BOOLEAN, + null, + new Object[] { + Boolean.TRUE, + Boolean.FALSE + }); + if (type.equals("byte") || type.equals(Byte.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BYTE, + null, + Byte.valueOf(Byte.MIN_VALUE), + Byte.valueOf(Byte.MAX_VALUE)); + if (type.equals("char") || type.equals(Character.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.CHARACTER, + null, + Character.valueOf(Character.MIN_VALUE), + Character.valueOf(Character.MAX_VALUE)); + if (type.equals("double") || type.equals(Double.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.DOUBLE, + null, + Double.valueOf(Double.MIN_VALUE), + Double.valueOf(Double.MAX_VALUE)); + if (type.equals("float") || type.equals(Float.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.FLOAT, + null, + Float.valueOf(Float.MIN_VALUE), + Float.valueOf(Float.MAX_VALUE)); + if (type.equals("int") || type.equals(Integer.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.INTEGER, + null, + Integer.valueOf(Integer.MIN_VALUE), + Integer.valueOf(Integer.MAX_VALUE)); + if (type.equals("long") || type.equals(Long.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.LONG, + null, + Long.valueOf(Long.MIN_VALUE), + Long.valueOf(Long.MAX_VALUE)); + if (type.equals("short") || type.equals(Short.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.SHORT, + null, + Short.valueOf(Short.MIN_VALUE), + Short.valueOf(Short.MAX_VALUE)); + if (type.equals(String.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING); + if (type.equals("void")) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.VOID); + Class c; + try + { + c = Class.forName(type); + } + catch (ClassNotFoundException e) + { + throw new InternalError("The class for a type used in a management bean " + + "could not be loaded."); + } + if (c.isEnum()) + { + Object[] values = c.getEnumConstants(); + String[] names = new String[values.length]; + for (int a = 0; a < values.length; ++a) + names[a] = values[a].toString(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING, + null, + (Object[]) names); + } + try + { + c.getMethod("from", new Class[] { CompositeData.class }); + Method[] methods = c.getMethods(); + List names = new ArrayList(); + List types = new ArrayList(); + for (int a = 0; a < methods.length; ++a) + { + String name = methods[a].getName(); + if (name.startsWith("get")) + { + names.add(name.substring(3)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + } + String[] fields = (String[]) names.toArray(); + CompositeType ctype = new CompositeType(c.getName(), c.getName(), + fields, fields, + (OpenType[]) types.toArray()); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ctype); + } + catch (NoSuchMethodException e) + { + /* Ignored; we expect this if this isn't a from(CompositeData) class */ + } + if (Map.class.isAssignableFrom(c)) + { + OpenType k = SimpleType.VOID; + OpenType v = SimpleType.VOID; + TypeVariable[] vars = c.getTypeParameters(); + for (int a = 0; a < vars.length; ++a) + { + if (vars[a].getName().equals("K")) + k = getTypeFromClass((Class) vars[a].getGenericDeclaration()); + if (vars[a].getName().equals("V")) + v = getTypeFromClass((Class) vars[a].getGenericDeclaration()); + } + CompositeType ctype = new CompositeType(Map.class.getName(), Map.class.getName(), + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] { k, v}); + TabularType ttype = new TabularType(c.getName(), c.getName(), ctype, + new String[] { "key" }); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ttype); + } + if (List.class.isAssignableFrom(c)) + { + OpenType e = SimpleType.VOID; + TypeVariable[] vars = c.getTypeParameters(); + for (int a = 0; a < vars.length; ++a) + { + if (vars[a].getName().equals("E")) + e = getTypeFromClass((Class) vars[a].getGenericDeclaration()); + } + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType(1, e) + ); + } + if (c.isArray()) + { + int depth; + for (depth = 0; c.getName().charAt(depth) == '['; ++depth); + OpenType ot = getTypeFromClass(c.getComponentType()); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType(depth, ot) + ); + } + throw new InternalError("The type used does not have an open type translation."); + } + } diff --git a/gnu/java/net/protocol/http/Request.java b/gnu/java/net/protocol/http/Request.java index e15ec4182..cd9d7ea44 100644 --- a/gnu/java/net/protocol/http/Request.java +++ b/gnu/java/net/protocol/http/Request.java @@ -419,13 +419,16 @@ public class Request switch (code) { case 100: + break; case 204: case 205: case 304: + body = createResponseBodyStream(responseHeaders, majorVersion, + minorVersion, in, false); break; default: body = createResponseBodyStream(responseHeaders, majorVersion, - minorVersion, in); + minorVersion, in, true); } // Construct response @@ -453,7 +456,8 @@ public class Request private InputStream createResponseBodyStream(Headers responseHeaders, int majorVersion, int minorVersion, - InputStream in) + InputStream in, + boolean mayHaveBody) throws IOException { long contentLength = -1; @@ -466,7 +470,12 @@ public class Request (majorVersion == 1 && minorVersion == 0); String transferCoding = responseHeaders.getValue("Transfer-Encoding"); - if ("chunked".equalsIgnoreCase(transferCoding)) + if ("HEAD".equals(method) || !mayHaveBody) + { + // Special case no body. + in = new LimitedLengthInputStream(in, 0, true, connection, doClose); + } + else if ("chunked".equalsIgnoreCase(transferCoding)) { in = new LimitedLengthInputStream(in, -1, false, connection, doClose); diff --git a/gnu/javax/naming/giop/ContextContinuation.java b/gnu/javax/naming/giop/ContextContinuation.java new file mode 100644 index 000000000..7d7a785fd --- /dev/null +++ b/gnu/javax/naming/giop/ContextContinuation.java @@ -0,0 +1,956 @@ +/* ContextContinuation.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.giop; + +import gnu.CORBA.NamingService.Ext; +import gnu.CORBA.NamingService.NameTransformer; + +import java.util.Hashtable; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.InvalidAttributesException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming._NamingContextExtStub; +import org.omg.CosNaming._NamingContextStub; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * The context to represent the corba naming service. Being the naming service, + * the returned context supports creating the subcontexts, forwarding this task + * to the existing naming service. When listing bindings, it uses the + * {@link Context#BATCHSIZE} property to determine, how many bindings should + * be returned at once (the process is transparend) + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class ContextContinuation implements Context +{ + /** + * This number of bindings will be requested from the naming server at once, + * while the subsequent bindings will be requested via binding iterator one by + * one. Use {@link Context#BATCHSIZE} to override the value of this constant. + */ + public int DEFAULT_BATCH_SIZE = 20; + + /** + * The actual CORBA naming service. + */ + NamingContextExt service; + + /** + * The object request broker, used to access the naming service. This field + * is only initialised when the context is constructed from the URL. + */ + ORB orb; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The parent factory. + */ + GiopNamingServiceFactory factory; + + /** + * The name transformer to obtain the name from its string representation. The + * to_name method of the naming service is avoided as it may be remote and + * hence expensive. The conversion rules are standard and cannot be service + * specific. + */ + static NameTransformer transformer = new NameTransformer(); + + /** + * The batch size for list operations - how many to return at once. + */ + public final int howMany; + + /** + * Creates a new naming context that uses naming service, represented by the + * given CORBA object. + * + * @param namingService + * the naming service object. It must be possible to narrow it into + * the NamingContextExt. + * @param props + * the environment table. + * @param orb + * the associated ORB. This reference is used during cleanup. + * @param the + * parent factory. This reference is used during cleanup. + */ + public ContextContinuation(org.omg.CORBA.Object nsObject, + Hashtable props, ORB anOrb, + GiopNamingServiceFactory aFactory) + { + factory = aFactory; + orb = anOrb; + + Delegate delegate = ((ObjectImpl) nsObject)._get_delegate(); + + // If the IOR provides the IDL ID, we can check if our name + // service is old NamingContext or new NamingContextExt. + // Not all forms of the URL always provide the IDL id. + if (!nsObject._is_a(NamingContextExtHelper.id()) + && nsObject._is_a(NamingContextHelper.id())) + { + // We are surely working with the old version. + _NamingContextStub stub = new _NamingContextStub(); + stub._set_delegate(delegate); + // The Ext object will add the necessary extensions. + service = new Ext(stub); + } + else + { + // We expecte the service to be the NamingContextExt (this is true + // for both Sun's and our implementations). There is no easy way + // to check the version. + _NamingContextExtStub stub = new _NamingContextExtStub(); + stub._set_delegate(delegate); + service = stub; + } + properties = props; + howMany = getBatchSize(); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. The components of the name are + * mapped into the components of the CORBA name. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(Name name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.bind(toGiop(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.bind(transformer.toName(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Releases all resources, associated with this context. The close() method + * can be called several times, but after it has been once invoked, it is not + * allowed to call any other method of this context. This method destroys + * the ORB, if we have one. + * + * @throws NamingException + */ + public void close() throws NamingException + { + if (orb != null && factory !=null) + { + factory.checkIfReferenced(orb); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported + */ + public String composeName(String name1, String name2) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param name + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(Name subContext) throws NamingException + { + try + { + org.omg.CORBA.Object subcontext = service.bind_new_context( + toGiop(subContext)); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param name + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(String subContext) throws NamingException + { + try + { + org.omg.CORBA.Object subcontext = + service.bind_new_context(transformer.toName(subContext)); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, + null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(subContext); + } + catch (InvalidName e) + { + throw new InvalidNameException(subContext); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param name + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(Name subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param name + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(String subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Returs the full name of this naming context. The returned string is not a + * JNDI composite name and should not be passed directly to the methods of the + * naming context. This implementation returns the IOR. + * + * @return the full name of this naming context, in its own namespace. + * @throws OperationNotSupportedException + * if the naming system, represented by this context, does not + * support the notation of the full name. + * @throws NamingException + */ + public String getNameInNamespace() throws NamingException + { + if (orb != null) + return orb.object_to_string(service); + else + { + try + { + ObjectImpl impl = (ObjectImpl) service; + return impl._orb().object_to_string(impl); + } + catch (ClassCastException e) + { + throw new UnsupportedOperationException(); + } + } + } + + /** + * Not supported. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(Name name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.size() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name)))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(name))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.size() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name)))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(name))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NameNotFountException + * if the name is not found + */ + public Object lookup(Name name) throws NamingException + { + try + { + return service.resolve(toGiop(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NamingException + * if the naming fails. + */ + public Object lookup(String name) throws NamingException + { + try + { + return service.resolve_str(name); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(Name name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(toGiop(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(transformer.toName(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(String oldName, String newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(Name name) throws NamingException + { + try + { + service.unbind(toGiop(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(String name) throws NamingException + { + try + { + service.unbind(transformer.toName(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(name); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(name); + } + catch (InvalidName e) + { + throw new InvalidNameException(name); + } + } + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. + * + * @param propName + * the name of the new property + * @param propVal + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + * @throws NamingException + */ + public Object addToEnvironment(String key, Object value) + throws NamingException + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller. Use {@link #addToEnvironment} + * and {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Convert the {@link Name} into array of the name components, required to the + * CORBA naming service. First the string representation is obtained, then + * it is converted using parsing rules of the CORBA name. + * + * @param name + * then name to convert + * @return the converted array of components. + */ + public NameComponent[] toGiop(Name name) throws InvalidName + { + return transformer.toName(name.toString()); + } + + /** + * Get the batch size from the environment properties. The batch size is used + * for listing operations. + * + * @return the batch size, or some default value if not specified. + */ + public int getBatchSize() + { + int batchSize = DEFAULT_BATCH_SIZE; + Object bs = properties.get(Context.BATCHSIZE); + if (bs != null) + { + try + { + int b = Integer.parseInt(bs.toString()); + if (b >= 0) + batchSize = b; + } + catch (NumberFormatException e) + { + // OK, use default value. + } + } + return batchSize; + } + + +} diff --git a/gnu/javax/naming/giop/CorbalocParser.java b/gnu/javax/naming/giop/CorbalocParser.java new file mode 100644 index 000000000..397b1c7d9 --- /dev/null +++ b/gnu/javax/naming/giop/CorbalocParser.java @@ -0,0 +1,439 @@ +/* CorbalocParser.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.giop; + +import gnu.CORBA.IOR; +import gnu.CORBA.Minor; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Version; +import gnu.CORBA.NamingService.NameTransformer; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.StringTokenizer; + +import javax.naming.InvalidNameException; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.DATA_CONVERSION; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.ORBPackage.InvalidName; + +/** + * Parses the alternative IOR representations into our IOR structure. + * + * TODO This parser currently supports only one address per target string. A + * string with the multiple addresses will be accepted, but only the last + * address will be taken into consideration. The fault tolerance is not yet + * implemented. + * + * The key string is filtered using {@link java.net.URLDecoder} that replaces + * the agreed escape sequences by the corresponding non alphanumeric characters. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CorbalocParser + extends NameTransformer +{ + /** + * The corbaloc prefix. + */ + public static final String pxCORBALOC = "corbaloc"; + + /** + * The corbaname prefix. + */ + public static final String pxCORBANAME = "corbaname"; + + /** + * The IOR prefix. + */ + public static final String pxIOR = "ior"; + + /** + * The file:// prefix. + */ + public static final String pxFILE = "file://"; + + /** + * The ftp:// prefix. + */ + public static final String pxFTP = "ftp://"; + + /** + * The http:// prefix. + */ + public static final String pxHTTP = "http://"; + + /** + * Marks iiop protocol. + */ + public static final String IIOP = "iiop"; + + /** + * Marks rir protocol. + */ + public static final String RIR = "rir"; + + /** + * The default port value, as specified in OMG documentation. + */ + public static final int DEFAULT_PORT = 2809; + + /** + * The default name. + */ + public static final String DEFAULT_NAME = "NameService"; + + /** + * The string to name converter, initialized on demand. + */ + static NameTransformer converter; + + /** + * The current position. + */ + int p; + + /** + * The address being parsed, splitted into tokens. + */ + String[] t; + + /** + * Parse CORBALOC. + * + * The expected format is:
+ * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key
+ * 2. corbaloc:rir:[/key]
+ * 3. corbaname:[iiop][version.subversion@]:host[:port]/key
+ * 4. corbaname:rir:[/key]
+ * 5. file://[file name]
+ * 6. http://[url]
+ * 7. ftp://[url]
+ * + * Protocol defaults to IOP, the object key defaults to the NameService. + * + * @param corbaloc the string to parse. + * @param orb the ORB, needed to create IORs and resolve rir references. + * + * @return the arrey of strings, first member being the IOR of the + * naming service, second member the name in the naming service. + */ + public synchronized String[] corbaloc(String corbaloc, + ORB orb) + throws InvalidNameException + { + return corbaloc(corbaloc, orb, 0); + } + + /** + * Parse controlling against the infinite recursion loop. + */ + private String[] corbaloc(String corbaloc, + ORB orb, int recursion) throws InvalidNameException + { + // The used CORBA specification does not state how many times we should to + //redirect, but the infinite loop may be used to knock out the system. + // by malicious attempt. + if (recursion > 10) + throw new DATA_CONVERSION("More than 10 redirections"); + + if (corbaloc.startsWith(pxFILE)) + return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1); + else if (corbaloc.startsWith(pxHTTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + else if (corbaloc.startsWith(pxFTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + + // The version numbers with default values. + int major = 1; + int minor = 0; + + // The host address. + String host; + + // The port. + int port = DEFAULT_PORT; + + // The object key as string. + String key; + + StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true); + + t = new String[st.countTokens()]; + + for (int i = 0; i < t.length; i++) + { + t[i] = st.nextToken(); + } + + p = 0; + + if (!t[p].startsWith(pxCORBANAME)) + throw new InvalidNameException(corbaloc+" must start with "+pxCORBANAME); + + p++; + + if (!t[p++].equals(":")) + throw new BAD_PARAM("Syntax (':' expected after name prefix)"); + + // Check for rir: + if (t[p].equals(RIR)) + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'rir'"); + + key = readKey("/"); + + Object object; + try + { + object = orb.resolve_initial_references(key); + return resolve(orb.object_to_string(object)); + } + catch (InvalidName e) + { + throw new BAD_PARAM("Unknown initial reference '" + key + "'"); + } + } + else + // Check for iiop. + if (t[p].equals(IIOP) || t[p].equals(":")) + { + IOR ior = new IOR(); + + Addresses: do + { // Read addresses. + if (t[p].equals(":")) + { + p++; + } + else + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'iiop'"); + // Check if version is present. + if (t[p + 1].equals(".")) + if (t[p + 3].equals("@")) + { + // Version info present. + try + { + major = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '.' at this point. + try + { + minor = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '@' at this point. + } + } + + ior.Internet.version = new Version(major, minor); + + // Then host data goes till '/' or ':'. + StringBuffer bhost = new StringBuffer(corbaloc.length()); + while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(",")) + bhost.append(t[p++]); + + host = bhost.toString(); + + ior.Internet.host = host; + + if (t[p].equals(":")) + { + // Port specified. + p++; + try + { + port = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'"); + } + } + + ior.Internet.port = port; + + // Id is not listed. + ior.Id = ""; + + if (t[p].equals(",")) + p++; + else + break Addresses; + } + while (true); + + key = readKey("/"); + ior.key = key.getBytes(); + + return resolve(ior.toStringifiedReference()); + } + + else + throw new InvalidNameException("Unsupported protocol '" + t[p] + + "' (iiop expected)"); + } + + /** + * Read IOR from the file in the local file system. + */ + String readFile(String file) + { + File f = new File(file); + if (!f.exists()) + { + DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath() + + " does not exist."); + err.minor = Minor.Missing_IOR; + } + try + { + char[] c = new char[(int) f.length()]; + FileReader fr = new FileReader(f); + fr.read(c); + fr.close(); + return new String(c).trim(); + } + catch (IOException ex) + { + DATA_CONVERSION d = new DATA_CONVERSION(); + d.initCause(ex); + d.minor = Minor.Missing_IOR; + throw (d); + } + } + + /** + * Read IOR from the remote URL. + */ + String readUrl(String url) + { + URL u; + try + { + u = new URL(url); + } + catch (MalformedURLException mex) + { + throw new BAD_PARAM("Malformed URL: '" + url + "'"); + } + + try + { + InputStreamReader r = new InputStreamReader(u.openStream()); + + StringBuffer b = new StringBuffer(); + int c; + + while ((c = r.read()) > 0) + b.append((char) c); + + return b.toString().trim(); + } + catch (Exception exc) + { + DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed."); + d.minor = Minor.Missing_IOR; + throw d; + } + } + + private String[] resolve(String nsIor) + { + String [] n = new String[2]; + n[0] = nsIor; + n[1] = readKey("#"); + return n; + } + + private String readKey(String delimiter) + throws BAD_PARAM + { + if (p < t.length) + if (!t[p].equals(delimiter)) + { + if (t[p].equals("#")) + return DEFAULT_NAME; + else + throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p] + + "' found"); + } + + StringBuffer bKey = new StringBuffer(); + p++; + + while (p < t.length && !t[p].equals("#")) + bKey.append(t[p++]); + + if (bKey.length() == 0) + return DEFAULT_NAME; + + try + { + return URLDecoder.decode(bKey.toString(), "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new Unexpected("URLDecoder does not support UTF-8", e); + } + } +} diff --git a/gnu/javax/naming/giop/GiopNamingEnumeration.java b/gnu/javax/naming/giop/GiopNamingEnumeration.java new file mode 100644 index 000000000..9b93f8bb6 --- /dev/null +++ b/gnu/javax/naming/giop/GiopNamingEnumeration.java @@ -0,0 +1,187 @@ +/* GiopNamingEnumeration.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import java.util.NoSuchElementException; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIterator; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public abstract class GiopNamingEnumeration implements NamingEnumeration +{ + /** + * The array of bindings, returned at once. + */ + Binding[] list; + + /** + * The binding iterator to obtain the subsequent bindings. May be null, + * if all values are stored in the list. + */ + BindingIterator iterator; + + /** + * The batch size. + */ + int batch; + + /** + * The position of the element in the binding list, that must be returned + * during the subsequent call of the next(). If this field is grater or equal + * to the lenght of the list, the subsequent values must be requested from the + * iterator. + */ + int p; + + GiopNamingEnumeration(BindingListHolder bh, BindingIteratorHolder bih, int batchSize) + { + list = bh.value; + iterator = bih.value; + batch = batchSize; + } + + /** + * Convert from the CORBA binding into that this enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public abstract Object convert(Binding binding); + + public void close() throws NamingException + { + if (iterator != null) + { + iterator.destroy(); + iterator = null; + } + } + + /** + * Checks if there are more elements to return. + * + * @throws NamingException + * never + */ + public boolean hasMore() throws NamingException + { + return hasMoreElements(); + } + + /** + * Returns the next element. + * + * @throws NamingException + * never + */ + public Object next() throws NamingException + { + return nextElement(); + } + + /** + * Checks if there are more elements to return. + */ + public boolean hasMoreElements() + { + if (p < 0) + return false; + else if (p < list.length) + return true; + else + return getMore(); + } + + /** + * Returns the next element. + */ + public Object nextElement() + { + if (p < 0) + throw new NoSuchElementException(); + else if (p < list.length) + return convert(list[p++]); + else if (getMore()) + // getMore updates p + return convert(list[p++]); + else + throw new NoSuchElementException(); + } + + /** + * Tries to obtain more elements, return true on success. Updates the fields + * accordingly. + */ + boolean getMore() + { + if (iterator != null) + { + BindingListHolder holder = new BindingListHolder(); + boolean rt = iterator.next_n(batch, holder); + if (rt) + { + // The new pack of the bindings arrived. + p = 0; + list = holder.value; + return true; + } + else + { + iterator.destroy(); + iterator = null; + p = -1; + return false; + } + } + else + return false; + } +} diff --git a/gnu/javax/naming/giop/GiopNamingServiceFactory.java b/gnu/javax/naming/giop/GiopNamingServiceFactory.java new file mode 100644 index 000000000..84aa32413 --- /dev/null +++ b/gnu/javax/naming/giop/GiopNamingServiceFactory.java @@ -0,0 +1,177 @@ +/* GiopNamingServiceFactory.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.CORBA.OrbFunctional; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +import javax.naming.Context; +import javax.naming.Name; + +import org.omg.CORBA.ORB; + +/** + * The context factory to represent the corbaname: style urls. Such URL states + * that the CORBA naming service exists on the given host. This service can + * return the required object, finding it by the given name. The names are + * parsed using the specification of the corbaname urls. Being the naming + * service, the returned context supports creating the subcontexts, forwarding + * this task to the existing naming service. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class GiopNamingServiceFactory +{ + /** + * The default naming service provider. It is assumed, that the naming service + * is running on the port 900 of the local host, using the GIOP version 1.2 + */ + public static final String DEFAULT_PROVIDER = + "corbaloc:iiop:1.2@127.0.0.1:900/NameService"; + + /** + * The table of all instantiated ORB's that are found by they ORB + * properties signatures. If all ORB related properties are the same, + * the ORB's are shared. + */ + public static Hashtable orbs = new Hashtable(); + + + /** + * Create a new instance of the corbaname URL context. + */ + public Object getObjectInstance(Object refObj, Name name, Context nameCtx, + Hashtable environment) + { + String provider = (String) environment.get(Context.PROVIDER_URL); + if (provider == null) + provider = DEFAULT_PROVIDER; + + String orbSignature = getOrbSignature(environment); + + ORB orb; + synchronized (orbs) + { + orb = (ORB) orbs.get(orbSignature); + if (orb == null) + { + Properties props = new Properties(); + props.putAll(environment); + orb = ORB.init(new String[0], props); + orbs.put(orbSignature, orb); + final ORB runIt = orb; + new Thread() + { + public void run() + { + runIt.run(); + } + }.start(); + } + } + + return new GiopNamingServiceURLContext(environment, this, orb); + } + + /** + * Check if this ORB is still in use (maybe it is time to shutdown it). This + * method only works when the Classpath CORBA implementation is used + * (otherwise it return without action). The method is called from the close() + * method of the created context. + * + * @param orb + * the ORB that maybe is no longer referenced. + */ + public void checkIfReferenced(ORB orb) + { + synchronized (orbs) + { + // We can only do this with the Classpath implementation. + if (orb instanceof OrbFunctional) + { + OrbFunctional cOrb = (OrbFunctional) orb; + // If there are no connected objects, we can destroy the orb. + if (cOrb.countConnectedObjects() == 0) + { + cOrb.shutdown(false); + cOrb.destroy(); + + Enumeration keys = orbs.keys(); + Object key; + Remove: while (keys.hasMoreElements()) + { + key = keys.nextElement(); + if (orbs.get(key) == orb) + { + orbs.remove(key); + break Remove; + } + } + } + } + } + } + + /** + * Get all properties. + */ + public String getOrbSignature(Map props) + { + TreeMap map = new TreeMap(); + map.putAll(props); + StringBuffer b = new StringBuffer(50*props.size()); + + Iterator iter = map.entrySet().iterator(); + Map.Entry m; + while (iter.hasNext()) + { + m = (Map.Entry) iter.next(); + b.append(m.getKey()); + b.append('='); + b.append(m.getValue()); + } + return b.toString(); + } +} diff --git a/gnu/javax/naming/giop/GiopNamingServiceURLContext.java b/gnu/javax/naming/giop/GiopNamingServiceURLContext.java new file mode 100644 index 000000000..50446ac7e --- /dev/null +++ b/gnu/javax/naming/giop/GiopNamingServiceURLContext.java @@ -0,0 +1,840 @@ +/* GiopNamingServiceURLContext.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.CORBA.NamingService.Ext; +import gnu.CORBA.NamingService.NameTransformer; + +import java.util.Hashtable; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.InvalidAttributesException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming._NamingContextExtStub; +import org.omg.CosNaming._NamingContextStub; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * The context to represent the corba naming service. Being the naming service, + * the returned context supports creating the subcontexts, forwarding this task + * to the existing naming service. When listing bindings, it uses the + * {@link Context#BATCHSIZE} property to determine, how many bindings should + * be returned at once (the process is transparend) + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class GiopNamingServiceURLContext extends CorbalocParser implements + Context +{ + /** + * This number of bindings will be requested from the naming server at once, + * while the subsequent bindings will be requested via binding iterator one by + * one. Use {@link Context#BATCHSIZE} to override the value of this constant. + */ + public int DEFAULT_BATCH_SIZE = 20; + + /** + * The object request broker, used to access the naming service. This field + * is only initialised when the context is constructed from the URL. + */ + ORB orb; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The parent factory. + */ + GiopNamingServiceFactory factory; + + /** + * The name transformer to obtain the name from its string representation. The + * to_name method of the naming service is avoided as it may be remote and + * hence expensive. The conversion rules are standard and cannot be service + * specific. + */ + static NameTransformer transformer = new NameTransformer(); + + /** + * The batch size for list operations - how many to return at once. + */ + public final int howMany; + + /** + * Creates a new naming context that uses naming service, represented by the + * given CORBA object. + * + * @param props + * the environment table. + * @param aFactory + * parent factory. This reference is used during cleanup. + * @param anOrb + * the associated ORB. This reference is used during cleanup. + */ + public GiopNamingServiceURLContext(Hashtable props, + GiopNamingServiceFactory aFactory, + ORB anOrb) + { + factory = aFactory; + orb = anOrb; + + properties = props; + howMany = getBatchSize(); + } + + public NamingContextExt getService(String address) + { + org.omg.CORBA.Object nsObject = orb.string_to_object(address); + Delegate delegate = ((ObjectImpl) nsObject)._get_delegate(); + + // If the IOR provides the IDL ID, we can check if our name + // service is old NamingContext or new NamingContextExt. + // Not all forms of the URL always provide the IDL id. + if (!nsObject._is_a(NamingContextExtHelper.id()) + && nsObject._is_a(NamingContextHelper.id())) + { + // We are surely working with the old version. + _NamingContextStub stub = new _NamingContextStub(); + stub._set_delegate(delegate); + // The Ext object will add the necessary extensions. + return new Ext(stub); + } + else + { + // We expecte the service to be the NamingContextExt (this is true + // for both Sun's and our implementations). There is no easy way + // to check the version. + _NamingContextExtStub stub = new _NamingContextExtStub(); + stub._set_delegate(delegate); + return stub; + } + } + + /** + * Split the corbaname name into the address of the naming service (first + * part) and the name of the object in the naming service (second part) + */ + public String[] split(String corbaloc) throws InvalidNameException + { + if (corbaloc.endsWith("#")) + corbaloc = corbaloc.substring(0, corbaloc.length() - 1); + + // No name part - parse as corbaname. + if (corbaloc.indexOf('#') < 0) + { + if (!corbaloc.regionMatches(true, 0, pxCORBANAME, 0, + pxCORBANAME.length())) + throw new InvalidNameException(corbaloc + " must start with " + + pxCORBANAME); + corbaloc = pxCORBALOC + corbaloc.substring(pxCORBANAME.length()); + return new String[] { corbaloc, "" }; + } + + return corbaloc(corbaloc, orb); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. The components of the name are + * mapped into the components of the CORBA name. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + String[] n = split(name); + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + getService(n[0]).bind(transformer.toName(n[1]), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Releases all resources, associated with this context. The close() method + * can be called several times, but after it has been once invoked, it is not + * allowed to call any other method of this context. This method destroys + * the ORB, if we have one. + * + * @throws NamingException + */ + public void close() throws NamingException + { + if (orb != null && factory != null) + { + factory.checkIfReferenced(orb); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported + */ + public String composeName(String name1, String name2) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(Name subContext) throws NamingException + { + return createSubcontext(subContext.toString()); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(String subContext) throws NamingException + { + try + { + String[] n = split(subContext); + org.omg.CORBA.Object subcontext = getService(n[0]).bind_new_context( + transformer.toName(n[1])); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(subContext); + } + catch (InvalidName e) + { + throw new InvalidNameException(subContext); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(Name subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(String subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Returs the empty string. + */ + public String getNameInNamespace() throws NamingException + { + return ""; + } + + /** + * Not supported. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(Name name) throws NamingException + { + return list(name.toString()); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + String [] n = split(name); + NamingContextExt service = getService(n[0]); + + if (n[1].length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1]))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + return listBindings(name.toString()); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + String [] n = split(name); + NamingContextExt service = getService(n[0]); + + if (n[1].length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1]))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NameNotFoundException + * if the name is not found + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NamingException + * if the naming fails. + */ + public Object lookup(String name) throws NamingException + { + try + { + String [] n = split(name); + NamingContextExt service = getService(n[0]); + return service.resolve_str(n[1]); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + String[] n = split(name); + NamingContextExt service = getService(n[0]); + + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(transformer.toName(n[1]), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(String oldName, String newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(String name) throws NamingException + { + try + { + String[] n = split(name); + NamingContextExt service = getService(n[0]); + + service.unbind(transformer.toName(n[1])); + } + catch (NotFound e) + { + throw new NameNotFoundException(name); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(name); + } + catch (InvalidName e) + { + throw new InvalidNameException(name); + } + } + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + * @throws NamingException + */ + public Object addToEnvironment(String key, Object value) + throws NamingException + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller. Use {@link #addToEnvironment} + * and {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Convert the {@link Name} into array of the name components, required to the + * CORBA naming service. First the string representation is obtained, then + * it is converted using parsing rules of the CORBA name. + * + * @param name + * then name to convert + * @return the converted array of components. + */ + public NameComponent[] toGiop(Name name) throws InvalidName + { + return transformer.toName(name.toString()); + } + + /** + * Get the batch size from the environment properties. The batch size is used + * for listing operations. + * + * @return the batch size, or some default value if not specified. + */ + public int getBatchSize() + { + int batchSize = DEFAULT_BATCH_SIZE; + Object bs = properties.get(Context.BATCHSIZE); + if (bs != null) + { + try + { + int b = Integer.parseInt(bs.toString()); + if (b >= 0) + batchSize = b; + } + catch (NumberFormatException e) + { + // OK, use default value. + } + } + return batchSize; + } + +} diff --git a/gnu/javax/naming/giop/ListBindingsEnumeration.java b/gnu/javax/naming/giop/ListBindingsEnumeration.java new file mode 100644 index 000000000..00f4a0779 --- /dev/null +++ b/gnu/javax/naming/giop/ListBindingsEnumeration.java @@ -0,0 +1,116 @@ +/* ListBindingsEnumeration.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import javax.naming.NamingEnumeration; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NamingContext; + +/** + * Iterates over bindings, obtaining values first from the binding list and then + * from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListBindingsEnumeration extends GiopNamingEnumeration implements + NamingEnumeration +{ + /** + * The naming service, to resolve the objects. + */ + NamingContext service; + + /** + * Create the new enumeration + * + * @param bh + * holder, containing the first portion of the bindings + * @param bih + * the iterator, containing the remaining bindings + * @param batchSize + * the number of bindings the the iterator will be requested to + * return as a single pack + * @param aService + * the naming service, used to obtain the objects, bound to the + * names. + */ + public ListBindingsEnumeration(BindingListHolder bh, + BindingIteratorHolder bih, int batchSize, + NamingContext aService) + { + super(bh, bih, batchSize); + service = aService; + } + + /** + * Convert from the CORBA binding into the javax.naming binding. As the CORBA + * naming service binding does not contain the object itself, this method + * makes the additional calls to the naming service. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(Binding binding) + { + StringBuffer name = new StringBuffer(); + + for (int i = 0; i < binding.binding_name.length; i++) + { + name.append(binding.binding_name[i]); + if (i < binding.binding_name.length - 1) + name.append('/'); + } + + try + { + Object object = service.resolve(binding.binding_name); + return new javax.naming.Binding(name.toString(), object); + } + catch (Exception e) + { + // Probably was removed by the concurent thread. + return null; + } + } + +} diff --git a/gnu/javax/naming/giop/ListEnumeration.java b/gnu/javax/naming/giop/ListEnumeration.java new file mode 100644 index 000000000..2e64e67d3 --- /dev/null +++ b/gnu/javax/naming/giop/ListEnumeration.java @@ -0,0 +1,116 @@ +/* ListEnumeration.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.NamingContext; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListEnumeration extends GiopNamingEnumeration implements + NamingEnumeration +{ + /** + * Create the new enumeration + * + * @param bh + * holder, containing the first portion of the bindings + * @param bih + * the iterator, containing the remaining bindings + * @param batchSize + * the number of bindings the the iterator will be requested to + * return as a single pack + */ + public ListEnumeration(BindingListHolder bh, + BindingIteratorHolder bih, int batchSize) + { + super(bh, bih, batchSize); + } + + /** + * Convert from the CORBA binding into the {@link NameClassPair} that this + * enumeration should return. This method converts into NameClassPair, + * connecting the name components with slashes and setting the class name + * to either NamingContext or GIOP Object. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(Binding binding) + { + StringBuffer name = new StringBuffer(); + + for (int i = 0; i < binding.binding_name.length; i++) + { + name.append(binding.binding_name[i]); + if (i < binding.binding_name.length - 1) + name.append('/'); + } + + String className; + + switch (binding.binding_type.value()) + { + case BindingType._ncontext: + className = NamingContext.class.getName(); + break; + case BindingType._nobject: + className = org.omg.CORBA.Object.class.getName(); + break; + default: + className = Object.class.getName(); + break; + } + + NameClassPair pair = new NameClassPair(name.toString(), className); + return pair; + } + +} diff --git a/gnu/javax/naming/ictxImpl/trans/GnuName.java b/gnu/javax/naming/ictxImpl/trans/GnuName.java new file mode 100644 index 000000000..b20bfa4ea --- /dev/null +++ b/gnu/javax/naming/ictxImpl/trans/GnuName.java @@ -0,0 +1,467 @@ +/* GnuName.java -- implementation of the javax.naming.Name + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.ictxImpl.trans; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import javax.naming.InvalidNameException; +import javax.naming.Name; + +/** + * The implementation of the {@link Name}. + * + * @author Audrius Meskauskas + */ +public class GnuName + implements Name +{ + /** + * The enumeration to traverse over name components. + */ + class GnuNameEnum + implements Enumeration + { + /** + * Get the new enumeration that enumerates from the given position forward + * + * @param position the position of the first name component to enumerate (0 + * means first element) + */ + GnuNameEnum(int position) + { + nxt = from + position; + } + + /** + * The position of the next enumeration component to be returned or -1 if + * the end has been reached. + */ + int nxt; + + /** + * Check if there are more elements in this enumeration. + */ + public boolean hasMoreElements() + { + return nxt >= 0; + } + + /** + * Return the next element or throw a NoSuchElementException if there is no + * any. + */ + public Object nextElement() + { + if (nxt < 0) + throw new NoSuchElementException(); + Object r = content[nxt++]; + + if (nxt - from == length) + nxt = - 1; + + return r; + } + } + + private static final long serialVersionUID = - 3617482732056931635L; + + /** + * The hashcode + */ + int hash; + + /** + * The content buffer of the name. This buffer may be shared, so the array + * member content should never be modified. + */ + String[] content; + + /** + * The place, inclusive, where the name content starts in the content buffer. + */ + int from; + + /** + * The length of the name. + */ + int length; + + /** + * Creates the unitialised name. + */ + protected GnuName() + { + + } + + /** + * Creates the name, containing from the given chain of the atomic components. + * + * @param name the array, containing the name components. + */ + public GnuName(String[] name) + { + this(name, 0, name.length); + } + + /** + * Creates the name that uses the given portion of the array for its + * components. + */ + public GnuName(String[] buffer, int useFrom, int useLength) + { + content = buffer; + from = useFrom; + length = useLength; + } + + /** + * Inserts the given String component to this Name + * at the given index. The method modifies the current Name and + * then returns it. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + * @exception InvalidNameException if the given String is not a + * valid component for this Name. + */ + public Name add(int posn, String comp) throws InvalidNameException + { + String[] nc = new String[content.length + 1]; + System.arraycopy(content, from, nc, 0, posn); + nc[posn] = comp; + System.arraycopy(content, from + posn, nc, posn + 1, length - posn); + + content = nc; + from = 0; + length = content.length; + hash = 0; + return this; + } + + /** + * Adds the given String component to the end of this + * Name. The method modifies the current Name + * and then returns it. + * + * @exception InvalidNameException if the given String is not a + * valid component for this Name. + */ + public Name add(String comp) throws InvalidNameException + { + String[] nc = new String[content.length + 1]; + System.arraycopy(content, from, nc, 0, length); + nc[nc.length - 1] = comp; + + content = nc; + from = 0; + length = content.length; + hash = 0; + return this; + } + + /** + * Inserts all the components of the given Name to this + * Name at the given index. Components after this index (if + * any) are shifted up. The method modifies the current Name + * and then returns it. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + * @exception InvalidNameException if any of the given components is not a + * valid component for this Name. + */ + public Name addAll(int posn, Name n) throws InvalidNameException + { + String[] nc = new String[length + n.size()]; + System.arraycopy(content, from, nc, 0, posn); + + int i = posn; + for (int p = 0; p < n.size(); i++, p++) + nc[i] = n.get(p); + + System.arraycopy(content, from + posn, nc, i, length - posn); + + length = length + n.size(); + hash = 0; + content = nc; + return this; + } + + /** + * Adds all the components of the given Name to the end of this + * Name. The method modifies the current Name + * and then returns it. + * + * @exception InvalidNameException if any of the given components is not a + * valid component for this Name. + */ + public Name addAll(Name suffix) throws InvalidNameException + { + String[] nc = new String[length + suffix.size()]; + System.arraycopy(content, from, nc, 0, length); + + for (int i = length, p = 0; i < nc.length; i++, p++) + nc[i] = suffix.get(p); + + length = length + suffix.size(); + hash = 0; + content = nc; + return this; + } + + /** + * Compares the given object to this Name. Returns a negative + * value if the given Object is smaller then this + * Name, a positive value if the Object is + * bigger, and zero if the are equal. If the Object is not of a + * class that can be compared to the class of this Name then a + * ClassCastException is thrown. Note that it is not guaranteed + * that Names implemented in different classes can be + * compared. The definition of smaller, bigger and equal is up to the actual + * implementing class. + */ + public int compareTo(Object obj) + { + Name n = (Name) obj; + + int l = Math.min(length, n.size()); + int c; + + for (int i = 0; i < l; i++) + { + c = content[from + i].compareTo(n.get(i)); + if (c != 0) + return c; + } + return length - n.size(); + } + + /** + * Returns true if this Name ends with the + * components of the given Name, false + * otherwise. + */ + public boolean endsWith(Name n) + { + if (n.size() > length) + return false; + + int ofs = length - n.size() + from; + + for (int i = 0; i < n.size(); i++, ofs++) + if (! content[ofs].equals(n.get(i))) + return false; + + return true; + } + + /** + * Gets the component at the given index. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public String get(int posn) + { + return content[from + posn]; + } + + /** + * Returns a non-null (but possibly empty) Enumeration of the + * components of the Name as Strings. + */ + public Enumeration getAll() + { + return new GnuNameEnum(0); + } + + /** + * Returns the components till the given index as a Name. The + * returned Name can be modified without changing the original. + * + * @param posn the ending position, exclusive + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public Name getPrefix(int posn) + { + return new GnuName(content, from, posn); + } + + /** + * Returns the components from the given index till the end as a + * Name. The returned Name can be modified + * without changing the original. + * + * @param posn the starting position, inclusive. If it is equal to the size of + * the name, the empty name is returned. + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public Name getSuffix(int posn) + { + return new GnuName(content, from + posn, length - posn); + } + + /** + * Returns true if the number of components of this + * Name is zero, false otherwise. + */ + public boolean isEmpty() + { + return length == 0; + } + + /** + * Removes the component at the given index from this Name. + * The method modifies the current Name and then returns it. + * + * @exception InvalidNameException if the name size reduces below zero. + */ + public Object remove(int posn) throws InvalidNameException + { + if (length == 0) + throw new InvalidNameException("negative size"); + else + { + length--; + if (posn == 0) + from++; + else if (posn < length) + { + String[] nc = new String[length]; + System.arraycopy(content, from, nc, 0, posn); + System.arraycopy(content, from + posn + 1, nc, posn, length - posn); + content = nc; + from = 0; + } + } + hash = 0; + return this; + } + + /** + * Returns the number of components of this Name. The returned + * number can be zero. + */ + public int size() + { + return length; + } + + /** + * Returns true if this Name starts with the + * components of the given Name, false + * otherwise. + */ + public boolean startsWith(Name n) + { + if (n.size() > length) + return false; + + for (int i = 0; i < n.size(); i++) + if (! content[from + i].equals(n.get(i))) + return false; + + return true; + } + + /** + * Returns a clone of this Name. It will be a deep copy of all + * the components of the Name so that changes to components of + * the components does not change the component in this Name. + */ + public Object clone() + { + return new GnuName(content, from, length); + } + + /** + * The name is equal to other name if they contents are equal. + */ + public boolean equals(Object arg0) + { + if (this == arg0) + return true; + else if (arg0 instanceof Name) + { + Name n = (Name) arg0; + if (length != n.size()) + return false; + + for (int i = 0; i < length; i++) + if (! content[from + i].equals(n.get(i))) + return false; + return true; + } + else + return false; + } + + /** + * Overridden to make consistent with equals. + */ + public int hashCode() + { + if (hash == 0 && length > 0) + { + int s = 0; + for (int i = from; i < from + length; i++) + s ^= content[i].hashCode(); + hash = s; + } + return hash; + } + + /** + * Get the string representation, separating the name components by slashes + */ + public String toString() + { + StringBuffer b = new StringBuffer(); + for (int i = 0; i < length; i++) + { + b.append(get(i)); + if (i < length - 1) + b.append('/'); + } + return b.toString(); + } +} diff --git a/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java b/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java new file mode 100644 index 000000000..7fe2e5c8c --- /dev/null +++ b/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java @@ -0,0 +1,53 @@ +/* corbanameURLContextFactory.java -- handles corbaname: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.corbaname; + +import gnu.javax.naming.giop.GiopNamingServiceFactory; + +import javax.naming.spi.ObjectFactory; + +/** + * The GIOP URL context factory. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class corbanameURLContextFactory extends GiopNamingServiceFactory + implements ObjectFactory +{ + // Nothing to override here. +} diff --git a/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java b/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java new file mode 100644 index 000000000..de79b93c3 --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java @@ -0,0 +1,597 @@ +/* ContextContinuation.java -- RMI naming context + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class ContextContinuation implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The local or remote RMI registry, performing the actual work for this + * context. + */ + Registry registry; + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param propName + * the name of the new property + * @param propVal + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + removeRegistry(); + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + removeRegistry(); + return properties.remove(propName); + } + + /** + * Remove the current registry reference. + */ + public void removeRegistry() + { + registry = null; + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry() throws NamingException + { + if (registry == null) + { + String address = properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + + // The format like rmi://localhost:1099 is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException(address); + + String a = address.substring("rmi://".length()); + + // The colon, if present, indicates the start of the port number. + int colon = a.lastIndexOf(':'); + int port; + + try + { + if (colon >=0) + { + port = Integer.parseInt(a.substring(colon+1)); + a = a.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(address); + } + + try + { + registry = LocateRegistry.getRegistry(a, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + * @param initialRegistry + * the initial value of the registry + */ + public ContextContinuation(Map props, Registry initialRegistry) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + registry = initialRegistry; + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + getRegistry().bind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return list(""); + } + + /** + * List existing bindings of this context (the parameter must be empty string, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + return new ListEnumeration(getRegistry().list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return listBindings(""); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + Registry r = getRegistry(); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param the + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param the + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + getRegistry().rebind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + Registry r = getRegistry(); + Remote object = r.lookup(oldName); + r.unbind(oldName); + try + { + r.bind(newName, object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + getRegistry().unbind(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + removeRegistry(); + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + return getRegistry().lookup(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } +} diff --git a/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java b/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java new file mode 100644 index 000000000..757e8bf59 --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java @@ -0,0 +1,97 @@ +/* ListBindingsEnumeration.java -- handles rmi: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.registry.Registry; + +import javax.naming.NamingEnumeration; + +/** + * Iterates over bindings, obtaining values first from the binding list and then + * from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListBindingsEnumeration extends RmiNamingEnumeration implements + NamingEnumeration +{ + /** + * The naming service, to resolve the objects. + */ + Registry service; + + /** + * Create the new enumeration + * + * @param bindings + * the list of the bound names + * @param aService + * the RMI naming service, used to get the bound values. + */ + public ListBindingsEnumeration(String [] bindings, + Registry aService) + { + super(bindings); + service = aService; + } + + /** + * Convert from the CORBA binding into the javax.naming binding. As the CORBA + * naming service binding does not contain the object itself, this method + * makes the additional calls to the naming service. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(String binding) + { + try + { + Object object = service.lookup(binding); + return new javax.naming.Binding(binding, object); + } + catch (Exception e) + { + // Probably was removed by the concurent thread. + return null; + } + } + +} diff --git a/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java b/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java new file mode 100644 index 000000000..b4142c5e3 --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java @@ -0,0 +1,80 @@ +/* ListEnumeration.java -- handles rmi: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.Remote; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListEnumeration extends RmiNamingEnumeration implements + NamingEnumeration +{ + /** + * Create the new enumeration + * + * @param bindings + * the array of the binding names, returned by the RMI registry. + */ + public ListEnumeration(String [] bindings) + { + super(bindings); + } + + /** + * Convert from the binding name into the {@link NameClassPair} that this + * enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(String binding) + { + NameClassPair pair = new NameClassPair(binding, Remote.class.getName()); + return pair; + } + +} diff --git a/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java b/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java new file mode 100644 index 000000000..29eb61b4b --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java @@ -0,0 +1,594 @@ +/* RmiContinuation.java -- RMI naming context + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class RmiContinuation implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The local or remote RMI registry, performing the actual work for this + * context. + */ + Registry registry; + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + removeRegistry(); + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + removeRegistry(); + return properties.remove(propName); + } + + /** + * Remove the current registry reference. + */ + public void removeRegistry() + { + registry = null; + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry() throws NamingException + { + if (registry == null) + { + String address = properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + + // The format like rmi://localhost:1099 is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException(address); + + String a = address.substring("rmi://".length()); + + // The colon, if present, indicates the start of the port number. + int colon = a.lastIndexOf(':'); + int port; + + try + { + if (colon >=0) + { + port = Integer.parseInt(a.substring(colon+1)); + a = a.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(address); + } + + try + { + registry = LocateRegistry.getRegistry(a, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + */ + public RmiContinuation(Map props) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + getRegistry().bind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new RmiContinuation(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new RmiContinuation(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return list(""); + } + + /** + * List existing bindings of this context (the parameter must be empty string, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + return new ListEnumeration(getRegistry().list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return listBindings(""); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + Registry r = getRegistry(); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + getRegistry().rebind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + Registry r = getRegistry(); + Remote object = r.lookup(oldName); + r.unbind(oldName); + try + { + r.bind(newName, object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + getRegistry().unbind(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + removeRegistry(); + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + return getRegistry().lookup(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } +} diff --git a/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java b/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java new file mode 100644 index 000000000..6d88cccef --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java @@ -0,0 +1,130 @@ +/* RmiNamingEnumeration.java -- handles rmi: urls + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.jndi.url.rmi; + +import java.util.NoSuchElementException; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public abstract class RmiNamingEnumeration implements NamingEnumeration +{ + /** + * The array of bindings, returned at once. + */ + String[] list; + + /** + * The position of the element in the binding list, that must be returned + * during the subsequent call of the next(). If this field is grater or equal + * to the lenght of the list, the subsequent values must be requested from the + * iterator. + */ + int p; + + RmiNamingEnumeration(String[] bindingList) + { + list = bindingList; + } + + /** + * Convert from the CORBA binding into that this enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public abstract Object convert(String binding); + + /** + * Checks if there are more elements to return. + * + * @throws NamingException + * never + */ + public boolean hasMore() throws NamingException + { + return hasMoreElements(); + } + + /** + * Returns the next element. + * + * @throws NamingException + * never + */ + public Object next() throws NamingException + { + return nextElement(); + } + + /** + * Checks if there are more elements to return. + */ + public boolean hasMoreElements() + { + return p < list.length; + } + + /** + * Returns the next element. + */ + public Object nextElement() + { + if (p < list.length) + return convert(list[p++]); + else + throw new NoSuchElementException(); + } + + /** + * Nothing to do in this method. + */ + public void close() + { + // Nothing to do here. + } + +} diff --git a/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java b/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java new file mode 100644 index 000000000..a17ce026b --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java @@ -0,0 +1,637 @@ +/* rmiURLContext.java -- RMI naming context + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class rmiURLContext implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The registry cache, maps the registry URL's to they instances. The + * obtained registries are reused, as newly obtaining them may cause the + * resource leak. + */ + static WeakHashMap registryCache = new WeakHashMap(); + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry(String netAddress) throws NamingException + { + Registry registry; + + synchronized (registryCache) + { + registry = (Registry) registryCache.get(netAddress); + } + + if (registry == null) + { + // The colon, if present, indicates the start of the port number. + int colon = netAddress.lastIndexOf(':'); + int port; + + try + { + if (colon >= 0) + { + port = Integer.parseInt(netAddress.substring(colon + 1)); + netAddress = netAddress.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(netAddress); + } + + try + { + registry = LocateRegistry.getRegistry(netAddress, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + + synchronized (registryCache) + { + registryCache.put(netAddress, registry); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + */ + public rmiURLContext(Map props) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).bind(n[1], (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + return list(name); + } + + /** + * List existing bindings of thie given registry.The class name of the + * returned name class pairs is "Remote", as this "quick preview" method + * should probably not call the naming service again. Use listBindings if more + * details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + try + { + String [] n = split(name); + if (n[1].length() > 0) + throw new InvalidNameException(name+", the name part must be empty"); + return new ListEnumeration(getRegistry(n[0]).list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + return listBindings(name.toString()); + } + + /** + * List existing bindings of this context. + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + try + { + String [] n = split(name); + if (n[1].length() > 0) + throw new InvalidNameException(name+", the name part must be empty"); + + Registry r = getRegistry(n[0]); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Returns the naming service context under the given address, wrapped as + * Context. + */ + public Object lookupLink(Name name) throws NamingException + { + return lookupLink(name.toString()); + } + + /** + * Returns the naming service context under the given address, + * wrapped as Context. + */ + public Object lookupLink(String name) throws NamingException + { + return new ContextContinuation(properties, getRegistry(name)); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).rebind(n[1], (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + String [] n = split(oldName); + Registry r = getRegistry(n[0]); + Remote object = r.lookup(n[1]); + r.unbind(oldName); + try + { + String [] n2 = split(newName); + Registry r2 = getRegistry(n2[0]); + r2.bind(n2[1], object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).unbind(n[1]); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + String [] n = split(name); + return getRegistry(n[0]).lookup(n[1]); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } + + /** + * Split the given rmi address into the network address and naming service + * name. + * + * @param address + * the address to split + * @return the two member array, lower being the network address of the naming + * service and upper being the naming service name + * @throws NamingException + * if the name is invalid + */ + public String[] split(String address) throws NamingException + { + // The format like rmi://localhost:1099/name is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException( + address + + " should be like 'rmi://localhost:1099/name'"); + + String a = address.substring("rmi://".length()); + + // The suffix starts after the first slash from the rmi:// + int sfx = a.indexOf('/'); + + // Handle the possible escape + while (sfx > 0 && a.charAt(sfx - 1) == '\\') + sfx = a.indexOf('/', sfx + 1); + + String net; + String name; + if (sfx >= 0) + { + net = a.substring(0, sfx); + name = a.substring(sfx + 1); + } + else + { + net = a; + name = ""; + } + + return new String[] { net, name }; + } +} diff --git a/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java b/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java new file mode 100644 index 000000000..593845327 --- /dev/null +++ b/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java @@ -0,0 +1,66 @@ +/* rmiURLContextFactory.java -- handles RMI naming context + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.naming.jndi.url.rmi; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.spi.ObjectFactory; + +/** + * Find the RMI URL context. This factory checks the Context.PROVIDER_URL + * property for the address of the RMI naming service and creates the + * context that operates talking with this naming service. If such property + * is missing, "rmi://localhost:1099" is assumed. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class rmiURLContextFactory implements ObjectFactory +{ + + /** + * Create a new instance of the context. + */ + public Object getObjectInstance(Object refObj, Name name, Context nameCtx, + Hashtable environment) + { + return new rmiURLContext(environment); + } + +} diff --git a/include/GtkDragSourceContextPeer.h b/include/GtkDragSourceContextPeer.h index 4a43d811a..87606ec1a 100644 --- a/include/GtkDragSourceContextPeer.h +++ b/include/GtkDragSourceContextPeer.h @@ -14,7 +14,7 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_n JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_connectSignals (JNIEnv *env, jobject, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_create (JNIEnv *env, jobject, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_nativeSetCursor (JNIEnv *env, jobject, jint) ; - +JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_setTarget (JNIEnv *env, jobject, jobject); #ifdef __cplusplus } diff --git a/include/gnu_java_awt_peer_gtk_ComponentGraphics.h b/include/gnu_java_awt_peer_gtk_ComponentGraphics.h index fbd5f6a93..0067119f6 100644 --- a/include/gnu_java_awt_peer_gtk_ComponentGraphics.h +++ b/include/gnu_java_awt_peer_gtk_ComponentGraphics.h @@ -15,8 +15,8 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_disposeSurfa JNIEXPORT jlong JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_initFromVolatile (JNIEnv *env, jobject, jlong, jint, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_start_1gdk_1drawing (JNIEnv *env, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_end_1gdk_1drawing (JNIEnv *env, jobject); +JNIEXPORT jobject JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_nativeGrab(JNIEnv *env, jclass, jobject ); JNIEXPORT jboolean JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_hasXRender (JNIEnv *env, jclass); -JNIEXPORT jobject JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_nativeGrab (JNIEnv *env, jclass, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_copyAreaNative (JNIEnv *env, jobject, jobject, jint, jint, jint, jint, jint, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_ComponentGraphics_drawVolatile (JNIEnv *env, jobject, jobject, jlong, jint, jint, jint, jint, jint, jint, jint, jint); diff --git a/include/gnu_java_awt_peer_gtk_GtkChoicePeer.h b/include/gnu_java_awt_peer_gtk_GtkChoicePeer.h index 1d92ed668..5450434d8 100644 --- a/include/gnu_java_awt_peer_gtk_GtkChoicePeer.h +++ b/include/gnu_java_awt_peer_gtk_GtkChoicePeer.h @@ -11,9 +11,8 @@ extern "C" #endif JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_create (JNIEnv *env, jobject); -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_append (JNIEnv *env, jobject, jobjectArray); JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeGetSelected (JNIEnv *env, jobject); -JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeAdd (JNIEnv *env, jobject, jstring, jint); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_add (JNIEnv *env, jobject, jstring, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemove (JNIEnv *env, jobject, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemoveAll (JNIEnv *env, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkChoicePeer_connectSignals (JNIEnv *env, jobject); diff --git a/include/gnu_java_awt_peer_gtk_GtkToolkit.h b/include/gnu_java_awt_peer_gtk_GtkToolkit.h index 6cdcc622a..f1f5326cd 100644 --- a/include/gnu_java_awt_peer_gtk_GtkToolkit.h +++ b/include/gnu_java_awt_peer_gtk_GtkToolkit.h @@ -17,6 +17,7 @@ JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkToolkit_sync (JNIEnv *env, jobject); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors (JNIEnv *env, jobject, jintArray); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkMain (JNIEnv *env, jclass); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkQuit (JNIEnv *env, jclass); JNIEXPORT jint JNICALL Java_gnu_java_awt_peer_gtk_GtkToolkit_getMouseNumberOfButtons (JNIEnv *env, jobject); #ifdef __cplusplus diff --git a/java/awt/BasicStroke.java b/java/awt/BasicStroke.java index 160a3eb0f..e6cb87e34 100644 --- a/java/awt/BasicStroke.java +++ b/java/awt/BasicStroke.java @@ -43,6 +43,7 @@ import gnu.java.awt.java2d.LineSegment; import gnu.java.awt.java2d.QuadSegment; import gnu.java.awt.java2d.Segment; +import java.awt.geom.FlatteningPathIterator; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; @@ -486,8 +487,157 @@ public class BasicStroke implements Stroke private Shape dashedStroke(PathIterator pi) { - GeneralPath out = new GeneralPath(); - return out; + // The choice of (flatnessSq == width / 3) is made to be consistent with + // the flattening in CubicSegment.getDisplacedSegments + FlatteningPathIterator flat = new FlatteningPathIterator(pi, + Math.sqrt(width / 3)); + + // Holds the endpoint of the current segment (or piece of a segment) + double[] coords = new double[2]; + + // Holds end of the last segment + double x, y, x0, y0; + x = x0 = y = y0 = 0; + + // Various useful flags + boolean pathOpen = false; + boolean dashOn = true; + boolean offsetting = (phase != 0); + + // How far we are into the current dash + double distance = 0; + int dashIndex = 0; + + // And variables to hold the final output + GeneralPath output = new GeneralPath(); + Segment[] p; + + // Iterate over the FlatteningPathIterator + while (! flat.isDone()) + { + switch (flat.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + x0 = x = coords[0]; + y0 = y = coords[1]; + + if (pathOpen) + { + capEnds(); + convertPath(output, start); + start = end = null; + pathOpen = false; + } + + break; + + case PathIterator.SEG_LINETO: + boolean segmentConsumed = false; + + while (! segmentConsumed) + { + // Find the total remaining length of this segment + double segLength = Math.sqrt((x - coords[0]) * (x - coords[0]) + + (y - coords[1]) + * (y - coords[1])); + boolean spanBoundary = true; + double[] segmentEnd = null; + + // The current segment fits entirely inside the current dash + if ((offsetting && distance + segLength <= phase) + || distance + segLength <= dash[dashIndex]) + { + spanBoundary = false; + } + + // Otherwise, we need to split the segment in two, as this + // segment spans a dash boundry + else + { + segmentEnd = (double[]) coords.clone(); + + // Calculate the remaining distance in this dash, + // and coordinates of the dash boundary + double reqLength; + if (offsetting) + reqLength = phase - distance; + else + reqLength = dash[dashIndex] - distance; + + coords[0] = x + ((coords[0] - x) * reqLength / segLength); + coords[1] = y + ((coords[1] - y) * reqLength / segLength); + } + + if (offsetting || ! dashOn) + { + // Dash is off, or we are in offset - treat this as a + // moveTo + x0 = x = coords[0]; + y0 = y = coords[1]; + + if (pathOpen) + { + capEnds(); + convertPath(output, start); + start = end = null; + pathOpen = false; + } + } + else + { + // Dash is on - treat this as a lineTo + p = (new LineSegment(x, y, coords[0], coords[1])).getDisplacedSegments(width / 2.0); + + if (! pathOpen) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[0]; + y = coords[1]; + } + + // Update variables depending on whether we spanned a + // dash boundary or not + if (! spanBoundary) + { + distance += segLength; + segmentConsumed = true; + } + else + { + if (offsetting) + offsetting = false; + dashOn = ! dashOn; + distance = 0; + coords = segmentEnd; + + if (dashIndex + 1 == dash.length) + dashIndex = 0; + else + dashIndex++; + + // Since the value of segmentConsumed is still false, + // the next run of the while loop will complete the segment + } + } + break; + + // This is a flattened path, so we don't need to deal with curves + } + flat.next(); + } + + if (pathOpen) + { + capEnds(); + convertPath(output, start); + } + return output; } /** diff --git a/java/awt/CardLayout.java b/java/awt/CardLayout.java index fcb05215a..7b733c821 100644 --- a/java/awt/CardLayout.java +++ b/java/awt/CardLayout.java @@ -361,7 +361,7 @@ public class CardLayout implements LayoutManager2, Serializable */ public String toString () { - return getClass ().getName () + "[" + hgap + "," + vgap + "]"; + return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]"; } /** @@ -401,11 +401,11 @@ public class CardLayout implements LayoutManager2, Serializable { if (comps[i].isVisible ()) { - if (what == NEXT) + if (choice == i) { - choice = i + 1; - if (choice == num) - choice = 0; + // Do nothing if we're already looking at the right + // component. + return; } else if (what == PREV) { @@ -413,11 +413,11 @@ public class CardLayout implements LayoutManager2, Serializable if (choice < 0) choice = num - 1; } - else if (choice == i) + else if (what == NEXT) { - // Do nothing if we're already looking at the right - // component. - return; + choice = i + 1; + if (choice == num) + choice = 0; } comps[i].setVisible (false); diff --git a/java/awt/Choice.java b/java/awt/Choice.java index 73aaeb1db..3113c599c 100644 --- a/java/awt/Choice.java +++ b/java/awt/Choice.java @@ -1,5 +1,5 @@ /* Choice.java -- Java choice button widget. - Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -51,56 +51,47 @@ import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; /** - * This class implements a drop down choice list. - * - * @author Aaron M. Renn (arenn@urbanophile.com) - */ + * This class implements a drop down choice list. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ public class Choice extends Component implements ItemSelectable, Serializable, Accessible { + /** + * The number used to generate the name returned by getName. + */ + private static transient long next_choice_number; -/* - * Static Variables - */ - -/** - * The number used to generate the name returned by getName. - */ -private static transient long next_choice_number; - -// Serialization constant -private static final long serialVersionUID = -4075310674757313071L; - -/*************************************************************************/ + // Serialization constant + private static final long serialVersionUID = -4075310674757313071L; -/* - * Instance Variables - */ - -/** - * @serial A list of items for the choice box, which can be null. - * This is package-private to avoid an accessor method. - */ -Vector pItems = new Vector(); + /** + * @serial A list of items for the choice box, which can be null. + * This is package-private to avoid an accessor method. + */ + Vector pItems = new Vector(); -/** - * @serial The index of the selected item in the choice box. - */ -private int selectedIndex = -1; + /** + * @serial The index of the selected item in the choice box. + */ + private int selectedIndex = -1; -// Listener chain -private ItemListener item_listeners; + /** + * ItemListener chain + */ + private ItemListener item_listeners; -/** - * This class provides accessibility support for the - * combo box. - * - * @author Jerry Quinn (jlquinn@optonline.net) - * @author Andrew John Hughes (gnu_andrew@member.fsf.org) - */ + /** + * This class provides accessibility support for the + * combo box. + * + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ protected class AccessibleAWTChoice - extends AccessibleAWTComponent - implements AccessibleAction + extends AccessibleAWTComponent + implements AccessibleAction { /** @@ -186,19 +177,12 @@ private ItemListener item_listeners; if (i < 0 || i >= pItems.size()) return false; - Choice.this.processItemEvent(new ItemEvent(Choice.this, - ItemEvent.ITEM_STATE_CHANGED, - this, ItemEvent.SELECTED)); + Choice.this.select( i ); + return true; } } -/*************************************************************************/ - -/* - * Constructors - */ - /** * Initializes a new instance of Choice. * @@ -211,397 +195,320 @@ private ItemListener item_listeners; throw new HeadlessException (); } -/*************************************************************************/ - -/* - * Instance Methods - */ - -/** - * Returns the number of items in the list. - * - * @return The number of items in the list. - */ -public int -getItemCount() -{ - return countItems (); -} - -/*************************************************************************/ - -/** - * Returns the number of items in the list. - * - * @return The number of items in the list. - * - * @deprecated This method is deprecated in favor of getItemCount. - */ -public int -countItems() -{ - return(pItems.size()); -} - -/*************************************************************************/ - -/** - * Returns the item at the specified index in the list. - * - * @param index The index into the list to return the item from. - * - * @exception ArrayIndexOutOfBoundsException If the index is invalid. - */ -public String -getItem(int index) -{ - return((String)pItems.elementAt(index)); -} - -/*************************************************************************/ - -/** - * Adds the specified item to this choice box. - * - * @param item The item to add. - * - * @exception NullPointerException If the item's value is null - * - * @since 1.1 - */ -public synchronized void -add(String item) -{ - if (item == null) - throw new NullPointerException ("item must be non-null"); - - pItems.addElement(item); - - int i = pItems.size () - 1; - if (peer != null) - { - ChoicePeer cp = (ChoicePeer) peer; - cp.add (item, i); - } - else if (selectedIndex == -1) - select(0); -} - -/*************************************************************************/ + /** + * Returns the number of items in the list. + * + * @return The number of items in the list. + */ + public int getItemCount() + { + return countItems (); + } -/** - * Adds the specified item to this choice box. - * - * This method is oboslete since Java 2 platform 1.1. Please use @see add - * instead. - * - * @param item The item to add. - * - * @exception NullPointerException If the item's value is equal to null - */ -public synchronized void -addItem(String item) -{ - add(item); -} + /** + * Returns the number of items in the list. + * + * @return The number of items in the list. + * + * @deprecated This method is deprecated in favor of getItemCount. + */ + public int countItems() + { + return pItems.size(); + } -/*************************************************************************/ + /** + * Returns the item at the specified index in the list. + * + * @param index The index into the list to return the item from. + * + * @exception ArrayIndexOutOfBoundsException If the index is invalid. + */ + public String getItem(int index) + { + return (String)pItems.elementAt(index); + } -/** Inserts an item into this Choice. Existing items are shifted - * upwards. If the new item is the only item, then it is selected. - * If the currently selected item is shifted, then the first item is - * selected. If the currently selected item is not shifted, then it - * remains selected. - * - * @param item The item to add. - * @param index The index at which the item should be inserted. - * - * @exception IllegalArgumentException If index is less than 0 - */ -public synchronized void -insert(String item, int index) -{ - if (index < 0) - throw new IllegalArgumentException ("index may not be less then 0"); + /** + * Adds the specified item to this choice box. + * + * @param item The item to add. + * + * @exception NullPointerException If the item's value is null + * + * @since 1.1 + */ + public synchronized void add(String item) + { + if (item == null) + throw new NullPointerException ("item must be non-null"); - if (index > getItemCount ()) - index = getItemCount (); + pItems.addElement(item); - pItems.insertElementAt(item, index); + if (peer != null) + ((ChoicePeer) peer).add(item, getItemCount() - 1); - if (peer != null) - { - ChoicePeer cp = (ChoicePeer) peer; - cp.add (item, index); - } - else if (selectedIndex == -1 || selectedIndex >= index) - select(0); -} + if (selectedIndex == -1) + select( 0 ); + } -/*************************************************************************/ + /** + * Adds the specified item to this choice box. + * + * This method is oboslete since Java 2 platform 1.1. Please use @see add + * instead. + * + * @param item The item to add. + * + * @exception NullPointerException If the item's value is equal to null + */ + public synchronized void addItem(String item) + { + add(item); + } -/** - * Removes the specified item from the choice box. - * - * @param item The item to remove. - * - * @exception IllegalArgumentException If the specified item doesn't exist. - */ -public synchronized void -remove(String item) -{ - int index = pItems.indexOf(item); - if (index == -1) - throw new IllegalArgumentException ("item \"" - + item + "\" not found in Choice"); - remove(index); -} + /** Inserts an item into this Choice. Existing items are shifted + * upwards. If the new item is the only item, then it is selected. + * If the currently selected item is shifted, then the first item is + * selected. If the currently selected item is not shifted, then it + * remains selected. + * + * @param item The item to add. + * @param index The index at which the item should be inserted. + * + * @exception IllegalArgumentException If index is less than 0 + */ + public synchronized void insert(String item, int index) + { + if (index < 0) + throw new IllegalArgumentException ("index may not be less then 0"); -/*************************************************************************/ + if (index > getItemCount ()) + index = getItemCount (); -/** - * Removes the item at the specified index from the choice box. - * - * @param index The index of the item to remove. - * - * @exception IndexOutOfBoundsException If the index is not valid. - */ -public synchronized void -remove(int index) -{ - if ((index < 0) || (index > getItemCount())) - throw new IllegalArgumentException("Bad index: " + index); + pItems.insertElementAt(item, index); - pItems.removeElementAt(index); + if (peer != null) + ((ChoicePeer) peer).add (item, index); - if (peer != null) - { - ChoicePeer cp = (ChoicePeer) peer; - cp.remove (index); - } - else - { - if (getItemCount() == 0) - selectedIndex = -1; - else if (index == selectedIndex) - select(0); - } + if (selectedIndex == -1 || selectedIndex >= index) + select(0); + } - if (selectedIndex > index) - --selectedIndex; -} + /** + * Removes the specified item from the choice box. + * + * @param item The item to remove. + * + * @exception IllegalArgumentException If the specified item doesn't exist. + */ + public synchronized void remove(String item) + { + int index = pItems.indexOf(item); + if (index == -1) + throw new IllegalArgumentException ("item \"" + + item + "\" not found in Choice"); + remove(index); + } -/*************************************************************************/ + /** + * Removes the item at the specified index from the choice box. + * + * @param index The index of the item to remove. + * + * @exception IndexOutOfBoundsException If the index is not valid. + */ + public synchronized void remove(int index) + { + pItems.removeElementAt(index); + + if (peer != null) + ((ChoicePeer) peer).remove( index ); + + if( getItemCount() == 0 ) + selectedIndex = -1; + else + { + if( selectedIndex > index ) + selectedIndex--; + else if( selectedIndex == index ) + selectedIndex = 0; + + if( peer != null ) + ((ChoicePeer)peer).select( selectedIndex ); + } + } -/** - * Removes all of the objects from this choice box. - */ -public synchronized void -removeAll() -{ - if (getItemCount() <= 0) - return; + /** + * Removes all of the objects from this choice box. + */ + public synchronized void removeAll() + { + if (getItemCount() <= 0) + return; - pItems.removeAllElements (); - - if (peer != null) - { - ChoicePeer cp = (ChoicePeer) peer; - cp.removeAll (); - } - - selectedIndex = -1; -} - -/*************************************************************************/ - -/** - * Returns the currently selected item, or null if no item is - * selected. - * - * @return The currently selected item. - */ -public synchronized String -getSelectedItem() -{ - return (selectedIndex == -1 - ? null - : ((String)pItems.elementAt(selectedIndex))); -} - -/*************************************************************************/ - -/** - * Returns an array with one row containing the selected item. - * - * @return An array containing the selected item. - */ -public synchronized Object[] -getSelectedObjects() -{ - if (selectedIndex == -1) - return null; + pItems.removeAllElements (); - Object[] objs = new Object[1]; - objs[0] = pItems.elementAt(selectedIndex); + if (peer != null) + { + ChoicePeer cp = (ChoicePeer) peer; + cp.removeAll (); + } - return(objs); -} + selectedIndex = -1; + } -/*************************************************************************/ + /** + * Returns the currently selected item, or null if no item is + * selected. + * + * @return The currently selected item. + */ + public synchronized String getSelectedItem() + { + return (selectedIndex == -1 + ? null + : ((String)pItems.elementAt(selectedIndex))); + } -/** - * Returns the index of the selected item. - * - * @return The index of the selected item. - */ -public int -getSelectedIndex() -{ - return(selectedIndex); -} + /** + * Returns an array with one row containing the selected item. + * + * @return An array containing the selected item. + */ + public synchronized Object[] getSelectedObjects() + { + if (selectedIndex == -1) + return null; -/*************************************************************************/ + Object[] objs = new Object[1]; + objs[0] = pItems.elementAt(selectedIndex); -/** - * Forces the item at the specified index to be selected. - * - * @param index The index of the row to make selected. - * - * @exception IllegalArgumentException If the specified index is invalid. - */ -public synchronized void -select(int index) -{ - if ((index < 0) || (index >= getItemCount())) - throw new IllegalArgumentException("Bad index: " + index); - - if (pItems.size() > 0) { - selectedIndex = index; - ChoicePeer cp = (ChoicePeer) peer; - if (cp != null) { - cp.select(index); - } + return objs; } -} -/*************************************************************************/ + /** + * Returns the index of the selected item. + * + * @return The index of the selected item. + */ + public int getSelectedIndex() + { + return selectedIndex; + } -/** - * Forces the named item to be selected. - * - * @param item The item to be selected. - * - * @exception IllegalArgumentException If the specified item does not exist. - */ -public synchronized void -select(String item) -{ - int index = pItems.indexOf(item); - if (index >= 0) - select(index); -} + /** + * Forces the item at the specified index to be selected. + * + * @param index The index of the row to make selected. + * + * @exception IllegalArgumentException If the specified index is invalid. + */ + public synchronized void select(int index) + { + if ((index < 0) || (index >= getItemCount())) + throw new IllegalArgumentException("Bad index: " + index); -/*************************************************************************/ + if( selectedIndex == index ) + return; -/** - * Creates the native peer for this object. - */ -public void -addNotify() -{ - if (peer == null) - peer = getToolkit ().createChoice (this); - super.addNotify (); -} + selectedIndex = index; + if( peer != null ) + ((ChoicePeer)peer).select( index ); + } -/*************************************************************************/ + /** + * Forces the named item to be selected. + * + * @param item The item to be selected. + * + * @exception IllegalArgumentException If the specified item does not exist. + */ + public synchronized void select(String item) + { + int index = pItems.indexOf(item); + if( index >= 0 ) + select( index ); + } -/** - * Adds the specified listener to the list of registered listeners for - * this object. - * - * @param listener The listener to add. - */ -public synchronized void -addItemListener(ItemListener listener) -{ - item_listeners = AWTEventMulticaster.add(item_listeners, listener); -} + /** + * Creates the native peer for this object. + */ + public void addNotify() + { + if (peer == null) + peer = getToolkit ().createChoice (this); + super.addNotify (); + } -/*************************************************************************/ + /** + * Adds the specified listener to the list of registered listeners for + * this object. + * + * @param listener The listener to add. + */ + public synchronized void addItemListener(ItemListener listener) + { + item_listeners = AWTEventMulticaster.add(item_listeners, listener); + } -/** - * Removes the specified listener from the list of registered listeners for - * this object. - * - * @param listener The listener to remove. - */ -public synchronized void -removeItemListener(ItemListener listener) -{ - item_listeners = AWTEventMulticaster.remove(item_listeners, listener); -} + /** + * Removes the specified listener from the list of registered listeners for + * this object. + * + * @param listener The listener to remove. + */ + public synchronized void removeItemListener(ItemListener listener) + { + item_listeners = AWTEventMulticaster.remove(item_listeners, listener); + } -/*************************************************************************/ + /** + * Processes this event by invoking processItemEvent() if the + * event is an instance of ItemEvent, otherwise the event + * is passed to the superclass. + * + * @param event The event to process. + */ + protected void processEvent(AWTEvent event) + { + if (event instanceof ItemEvent) + processItemEvent((ItemEvent)event); + else + super.processEvent(event); + } -/** - * Processes this event by invoking processItemEvent() if the - * event is an instance of ItemEvent, otherwise the event - * is passed to the superclass. - * - * @param event The event to process. - */ -protected void -processEvent(AWTEvent event) -{ - if (event instanceof ItemEvent) - processItemEvent((ItemEvent)event); - else - super.processEvent(event); -} - -void -dispatchEventImpl(AWTEvent e) -{ - if (e.id <= ItemEvent.ITEM_LAST - && e.id >= ItemEvent.ITEM_FIRST - && (item_listeners != null || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) - processEvent(e); - else + void dispatchEventImpl(AWTEvent e) + { super.dispatchEventImpl(e); -} -/*************************************************************************/ - -/** - * Processes item event by dispatching to any registered listeners. - * - * @param event The event to process. - */ -protected void -processItemEvent(ItemEvent event) -{ - int index = pItems.indexOf((String) event.getItem()); - // Don't call back into the peers when selecting index here - if (event.getStateChange() == ItemEvent.SELECTED) - this.selectedIndex = index; - if (item_listeners != null) - item_listeners.itemStateChanged(event); -} + if( e.id <= ItemEvent.ITEM_LAST && e.id >= ItemEvent.ITEM_FIRST && + ( item_listeners != null || + ( eventMask & AWTEvent.ITEM_EVENT_MASK ) != 0 ) ) + processEvent(e); + } -/*************************************************************************/ + /** + * Processes item event by dispatching to any registered listeners. + * + * @param event The event to process. + */ + protected void processItemEvent(ItemEvent event) + { + int index = pItems.indexOf((String) event.getItem()); + if (item_listeners != null) + item_listeners.itemStateChanged(event); + } -/** - * Returns a debugging string for this object. - * - * @return A debugging string for this object. - */ -protected String -paramString() -{ - return ("selectedIndex=" + selectedIndex + "," + super.paramString()); -} + /** + * Returns a debugging string for this object. + * + * @return A debugging string for this object. + */ + protected String paramString() + { + return "selectedIndex=" + selectedIndex + "," + super.paramString(); + } /** * Returns an array of all the objects currently registered as FooListeners diff --git a/java/awt/Component.java b/java/awt/Component.java index aac94a0c9..ba669f8ec 100644 --- a/java/awt/Component.java +++ b/java/awt/Component.java @@ -39,6 +39,8 @@ exception statement from your version. */ package java.awt; +//import gnu.java.awt.dnd.peer.gtk.GtkDropTargetContextPeer; + import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.AdjustmentEvent; @@ -698,6 +700,9 @@ public abstract class Component public void setDropTarget(DropTarget dt) { this.dropTarget = dt; + + if (peer != null) + dropTarget.addNotify(peer); } /** @@ -741,16 +746,23 @@ public abstract class Component */ public Toolkit getToolkit() { - if (peer != null) + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) { - Toolkit tk = peer.getToolkit(); - if (tk != null) - return tk; + comp = comp.parent; + p = comp == null ? null : comp.peer; } - // Get toolkit for lightweight component. - if (parent != null) - return parent.getToolkit(); - return Toolkit.getDefaultToolkit(); + + Toolkit tk = null; + if (p != null) + { + tk = peer.getToolkit(); + } + if (tk == null) + tk = Toolkit.getDefaultToolkit(); + return tk; } /** @@ -1033,7 +1045,7 @@ public abstract class Component visible = false; // Avoid NullPointerExceptions by creating a local reference. - ComponentPeer currentPeer=peer; + ComponentPeer currentPeer = peer; if (currentPeer != null) { currentPeer.hide(); @@ -1292,8 +1304,26 @@ public abstract class Component // component. synchronized (getTreeLock()) { - // We know peer != null here. - return peer.getLocationOnScreen(); + // Only a heavyweight peer can answer the question for the screen + // location. So we are going through the hierarchy until we find + // one and add up the offsets while doing so. + int offsX = 0; + int offsY = 0; + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + offsX += comp.x; + offsY += comp.y; + comp = comp.parent; + p = comp == null ? null: comp.peer; + } + // Now we have a heavyweight component. + assert ! (p instanceof LightweightPeer); + Point loc = p.getLocationOnScreen(); + loc.x += offsX; + loc.y += offsY; + return loc; } } @@ -1533,7 +1563,17 @@ public abstract class Component } } - private void notifyReshape(boolean resized, boolean moved) + /** + * Sends notification to interested listeners about resizing and/or moving + * the component. If this component has interested + * component listeners or the corresponding event mask enabled, then + * COMPONENT_MOVED and/or COMPONENT_RESIZED events are posted to the event + * queue. + * + * @param resized true if the component has been resized, false otherwise + * @param moved true if the component has been moved, false otherwise + */ + void notifyReshape(boolean resized, boolean moved) { // Only post an event if this component actually has a listener // or has this event explicitly enabled. @@ -1544,43 +1584,16 @@ public abstract class Component if (moved) { ComponentEvent ce = new ComponentEvent(this, - ComponentEvent.COMPONENT_MOVED); + ComponentEvent.COMPONENT_MOVED); getToolkit().getSystemEventQueue().postEvent(ce); } if (resized) { ComponentEvent ce = new ComponentEvent(this, - ComponentEvent.COMPONENT_RESIZED); + ComponentEvent.COMPONENT_RESIZED); getToolkit().getSystemEventQueue().postEvent(ce); } } - else - { - // Otherwise we might need to notify child components when this is - // a Container. - if (this instanceof Container) - { - Container cont = (Container) this; - if (resized) - { - for (int i = 0; i < cont.getComponentCount(); i++) - { - Component child = cont.getComponent(i); - child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED, - this, parent, 0); - } - } - if (moved) - { - for (int i = 0; i < cont.getComponentCount(); i++) - { - Component child = cont.getComponent(i); - child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED, - this, parent, 0); - } - } - } - } } /** @@ -2063,21 +2076,29 @@ public abstract class Component */ public Graphics getGraphics() { - if (peer != null) + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + int offsX = 0; + int offsY = 0; + while (p instanceof LightweightPeer) { - Graphics gfx = peer.getGraphics(); - // Create peer for lightweights. - if (gfx == null && parent != null) - { - gfx = parent.getGraphics(); - gfx.clipRect(getX(), getY(), getWidth(), getHeight()); - gfx.translate(getX(), getY()); - return gfx; - } + offsX += comp.x; + offsY += comp.y; + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + Graphics gfx = null; + if (p != null) + { + assert ! (p instanceof LightweightPeer); + gfx = p.getGraphics(); + gfx.translate(offsX, offsY); + gfx.clipRect(0, 0, width, height); gfx.setFont(font); - return gfx; } - return null; + return gfx; } /** @@ -2091,8 +2112,16 @@ public abstract class Component */ public FontMetrics getFontMetrics(Font font) { - return peer == null ? getToolkit().getFontMetrics(font) - : peer.getFontMetrics(font); + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + return p == null ? getToolkit().getFontMetrics(font) + : p.getFontMetrics(font); } /** @@ -2111,8 +2140,18 @@ public abstract class Component public void setCursor(Cursor cursor) { this.cursor = cursor; - if (peer != null) - peer.setCursor(cursor); + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setCursor(cursor); } /** @@ -2283,7 +2322,7 @@ public abstract class Component pw = Math.min(pw, par.width); ph = Math.min(ph, par.height); par = par.parent; - p = par.peer; + p = par == null ? null : par.peer; } // Now send an UPDATE event to the heavyweight component that we've found. @@ -2380,11 +2419,22 @@ public abstract class Component */ public Image createImage(ImageProducer producer) { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + // Sun allows producer to be null. - if (peer != null) - return peer.createImage(producer); + Image im; + if (p != null) + im = p.createImage(producer); else - return getToolkit().createImage(producer); + im = getToolkit().createImage(producer); + return im; } /** @@ -2400,10 +2450,16 @@ public abstract class Component Image returnValue = null; if (!GraphicsEnvironment.isHeadless ()) { - if (isLightweight () && parent != null) - returnValue = parent.createImage (width, height); - else if (peer != null) - returnValue = peer.createImage (width, height); + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + returnValue = p.createImage(width, height); } return returnValue; } @@ -2419,9 +2475,19 @@ public abstract class Component */ public VolatileImage createVolatileImage(int width, int height) { - if (peer != null) - return peer.createVolatileImage(width, height); - return null; + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + VolatileImage im = null; + if (p != null) + im = p.createVolatileImage(width, height); + return im; } /** @@ -2440,9 +2506,19 @@ public abstract class Component ImageCapabilities caps) throws AWTException { - if (peer != null) - return peer.createVolatileImage(width, height); - return null; + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + VolatileImage im = null; + if (p != null) + im = peer.createVolatileImage(width, height); + return im; } /** @@ -2472,10 +2548,21 @@ public abstract class Component public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { - if (peer != null) - return peer.prepareImage(image, width, height, observer); + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + boolean retval; + if (p != null) + retval = p.prepareImage(image, width, height, observer); else - return getToolkit().prepareImage(image, width, height, observer); + retval = getToolkit().prepareImage(image, width, height, observer); + return retval; } /** @@ -2509,9 +2596,21 @@ public abstract class Component public int checkImage(Image image, int width, int height, ImageObserver observer) { - if (peer != null) - return peer.checkImage(image, width, height, observer); - return getToolkit().checkImage(image, width, height, observer); + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + int retval; + if (p != null) + retval = p.checkImage(image, width, height, observer); + else + retval = getToolkit().checkImage(image, width, height, observer); + return retval; } /** @@ -2956,7 +3055,7 @@ public abstract class Component case HierarchyEvent.ANCESTOR_RESIZED: enabled = hierarchyBoundsListener != null || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0; - break; + break; default: assert false : "Should not reach here"; } @@ -3302,18 +3401,48 @@ public abstract class Component */ protected final void enableEvents(long eventsToEnable) { + // Update the counter for hierarchy (bounds) listeners. + if ((eventsToEnable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_EVENT_MASK, + 1); + } + } + if ((eventsToEnable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + 1); + } + } + eventMask |= eventsToEnable; - // TODO: Unlike Sun's implementation, I think we should try and - // enable/disable events at the peer (gtk/X) level. This will avoid - // clogging the event pipeline with useless mousemove events that - // we arn't interested in, etc. This will involve extending the peer - // interface, but thats okay because the peer interfaces have been - // deprecated for a long time, and no longer feature in the - // API specification at all. - if (isLightweight() && parent != null) - parent.enableEvents(eventsToEnable); - else if (peer != null) - peer.setEventMask(eventMask); + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setEventMask(eventMask); + } /** @@ -3326,8 +3455,48 @@ public abstract class Component */ protected final void disableEvents(long eventsToDisable) { + // Update the counter for hierarchy (bounds) listeners. + if ((eventsToDisable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_EVENT_MASK, + -1); + } + } + if ((eventsToDisable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -1); + } + } + eventMask &= ~eventsToDisable; - // forward new event mask to peer? + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setEventMask(eventMask); + } /** @@ -3887,6 +4056,13 @@ public abstract class Component etc. */ if (dropTarget != null) dropTarget.addNotify(peer); + + // Notify hierarchy listeners. + long flags = HierarchyEvent.DISPLAYABILITY_CHANGED; + if (isHierarchyVisible()) + flags |= HierarchyEvent.SHOWING_CHANGED; + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent, + flags); } } @@ -3916,6 +4092,13 @@ public abstract class Component tmp.hide(); tmp.dispose(); } + + // Notify hierarchy listeners. + long flags = HierarchyEvent.DISPLAYABILITY_CHANGED; + if (isHierarchyVisible()) + flags |= HierarchyEvent.SHOWING_CHANGED; + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent, + flags); } } @@ -5493,6 +5676,26 @@ p *
  • the set of backward traversal keys } } + /** + * Returns true when this component and all of its ancestors + * are visible, false otherwise. + * + * @return true when this component and all of its ancestors + * are visible, false otherwise + */ + boolean isHierarchyVisible() + { + boolean visible = isVisible(); + Component comp = parent; + while (comp != null && visible) + { + comp = comp.parent; + if (comp != null) + visible = visible && comp.isVisible(); + } + return visible; + } + /** * Coalesce paint events. Current heuristic is: Merge if the union of * areas is less than twice that of the sum of the areas. The X server diff --git a/java/awt/Container.java b/java/awt/Container.java index f385f539f..e6d8493d3 100644 --- a/java/awt/Container.java +++ b/java/awt/Container.java @@ -209,10 +209,12 @@ public class Container extends Component */ public Insets insets() { - if (peer == null) - return new Insets (0, 0, 0, 0); - - return ((ContainerPeer) peer).getInsets (); + Insets i; + if (peer == null || peer instanceof LightweightPeer) + i = new Insets (0, 0, 0, 0); + else + i = ((ContainerPeer) peer).getInsets (); + return i; } /** @@ -507,26 +509,43 @@ public class Container extends Component r.removeNotify(); + // Update the counter for Hierarchy(Bounds)Listeners. + int childHierarchyListeners = r.numHierarchyListeners; + if (childHierarchyListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + -childHierarchyListeners); + int childHierarchyBoundsListeners = r.numHierarchyBoundsListeners; + if (childHierarchyBoundsListeners > 0) + updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -childHierarchyListeners); + if (layoutMgr != null) layoutMgr.removeLayoutComponent(r); r.parent = null; - if (isShowing ()) + // Send ContainerEvent if necessary. + if (containerListener != null + || (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) { // Post event to notify of removing the component. ContainerEvent ce = new ContainerEvent(this, ContainerEvent.COMPONENT_REMOVED, r); - - getToolkit().getSystemEventQueue().postEvent(ce); + dispatchEvent(ce); } - } - + + // Send HierarchyEvent if necessary. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, r, this, + HierarchyEvent.PARENT_CHANGED); + + } + + if (valid) invalidate(); - ncomponents = 0; + ncomponents = 0; } } @@ -2007,6 +2026,43 @@ public class Container extends Component parent.updateHierarchyListenerCount(type, delta); } + /** + * Notifies interested listeners about resizing or moving the container. + * This performs the super behaviour (sending component events) and + * additionally notifies any hierarchy bounds listeners on child components. + * + * @param resized true if the component has been resized, false otherwise + * @param moved true if the component has been moved, false otherwise + */ + void notifyReshape(boolean resized, boolean moved) + { + // Notify component listeners. + super.notifyReshape(resized, moved); + + if (ncomponents > 0) + { + // Notify hierarchy bounds listeners. + if (resized) + { + for (int i = 0; i < getComponentCount(); i++) + { + Component child = getComponent(i); + child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED, + this, parent, 0); + } + } + if (moved) + { + for (int i = 0; i < getComponentCount(); i++) + { + Component child = getComponent(i); + child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED, + this, parent, 0); + } + } + } + } + private void addNotifyContainerChildren() { synchronized (getTreeLock ()) diff --git a/java/awt/List.java b/java/awt/List.java index ba398dd83..7b6524171 100644 --- a/java/awt/List.java +++ b/java/awt/List.java @@ -108,7 +108,7 @@ private int[] selected; * @serial An index value used by makeVisible() and * getVisibleIndex. */ -private int visibleIndex; +private int visibleIndex = -1; // The list of ItemListeners for this object. private ItemListener item_listeners; @@ -116,7 +116,6 @@ private ItemListener item_listeners; // The list of ActionListeners for this object. private ActionListener action_listeners; - /*************************************************************************/ /* @@ -176,6 +175,7 @@ List(int rows, boolean multipleMode) if (GraphicsEnvironment.isHeadless()) throw new HeadlessException (); + } /*************************************************************************/ @@ -314,12 +314,13 @@ setMultipleMode(boolean multipleMode) */ public void setMultipleSelections(boolean multipleMode) -{ +{ this.multipleMode = multipleMode; ListPeer peer = (ListPeer) getPeer (); if (peer != null) peer.setMultipleMode (multipleMode); + } /*************************************************************************/ @@ -519,6 +520,12 @@ add(String item, int index) public void addItem(String item, int index) { + if (item == null) + item = ""; + + if (index < -1) + index = -1; + if ((index == -1) || (index >= items.size ())) items.addElement (item); else @@ -543,7 +550,17 @@ addItem(String item, int index) public void delItem(int index) throws IllegalArgumentException { + boolean selected = false; + if (isSelected(index)) + { + selected = true; + deselect(index); + } + items.removeElementAt (index); + + if (selected) + select(index); ListPeer peer = (ListPeer) getPeer (); if (peer != null) @@ -580,15 +597,6 @@ remove(int index) throws IllegalArgumentException public synchronized void delItems(int start, int end) throws IllegalArgumentException { - if ((start < 0) || (start >= items.size())) - throw new IllegalArgumentException("Bad list start index value: " + start); - - if ((start < 0) || (start >= items.size())) - throw new IllegalArgumentException("Bad list start index value: " + start); - - if (start > end) - throw new IllegalArgumentException("Start is greater than end!"); - // We must run the loop in reverse direction. for (int i = end; i >= start; --i) items.removeElementAt (i); @@ -644,6 +652,8 @@ clear() ListPeer peer = (ListPeer) getPeer (); if (peer != null) peer.removeAll (); + + selected = new int[0]; } /*************************************************************************/ @@ -695,6 +705,7 @@ getSelectedIndex() if (selected == null || selected.length != 1) return -1; + return selected[0]; } @@ -713,7 +724,8 @@ getSelectedIndexes() { ListPeer l = (ListPeer) peer; selected = l.getSelectedIndexes (); - } + } + return selected; } @@ -862,13 +874,38 @@ getVisibleIndex() * * @param index The index of the item to select. */ -public synchronized void -select(int index) -{ - ListPeer lp = (ListPeer)getPeer(); - if (lp != null) - lp.select(index); -} + public synchronized void select(int index) + { + ListPeer lp = (ListPeer) getPeer(); + if (lp != null) + lp.select(index); + + if (selected != null) + { + boolean found = false; + for (int i = 0; i < selected.length; i++) + { + if (selected[i] == index) + found = true; + } + if (! found) + { + if (! isMultipleMode()) + { + selected = new int[] { index }; + return; + } + int[] temp = new int[selected.length + 1]; + System.arraycopy(selected, 0, temp, 0, selected.length); + temp[selected.length] = index; + selected = temp; + } + } else + { + selected = new int[1]; + selected[0] = index; + } + } /*************************************************************************/ @@ -880,9 +917,26 @@ select(int index) public synchronized void deselect(int index) { - ListPeer lp = (ListPeer)getPeer(); - if (lp != null) - lp.deselect(index); + if (isSelected(index)) + { + ListPeer lp = (ListPeer)getPeer(); + if (lp != null) + lp.deselect(index); + + int[] temp = new int[selected.length - 1]; + for (int i = 0; i < temp.length; i++) + { + if (selected[i] != index) + temp[i] = selected[i]; + else + { + System.arraycopy(selected, i + 1, temp, i, + selected.length - i - 1); + break; + } + } + selected = temp; + } } /*************************************************************************/ diff --git a/java/awt/Toolkit.java b/java/awt/Toolkit.java index b5ab39b5f..d2c5f390e 100644 --- a/java/awt/Toolkit.java +++ b/java/awt/Toolkit.java @@ -133,6 +133,11 @@ public abstract class Toolkit */ AWTEventListenerProxy[] awtEventListeners; + /** + * The shared peer for all lightweight components. + */ + private GLightweightPeer lightweightPeer; + /** * Default constructor for subclasses. */ @@ -382,7 +387,9 @@ public abstract class Toolkit */ protected LightweightPeer createComponent(Component target) { - return new GLightweightPeer(target); + if (lightweightPeer == null) + lightweightPeer = new GLightweightPeer(); + return lightweightPeer; } /** diff --git a/java/awt/dnd/DragGestureRecognizer.java b/java/awt/dnd/DragGestureRecognizer.java index 1a396f198..6a00347b2 100644 --- a/java/awt/dnd/DragGestureRecognizer.java +++ b/java/awt/dnd/DragGestureRecognizer.java @@ -166,6 +166,7 @@ public abstract class DragGestureRecognizer implements Serializable if(dragGestureListener != null) dragGestureListener.dragGestureRecognized (new DragGestureEvent(this, dragAction, p, events)); + resetRecognizer(); } protected void appendEvent(InputEvent e) diff --git a/java/awt/dnd/DragSource.java b/java/awt/dnd/DragSource.java index 2ab748270..cd4a93a3e 100644 --- a/java/awt/dnd/DragSource.java +++ b/java/awt/dnd/DragSource.java @@ -105,16 +105,15 @@ public class DragSource implements Serializable ds = null; throw new HeadlessException(); } - + if (ds == null) ds = new DragSource(); return ds; } public static boolean isDragImageSupported() - throws NotImplementedException { - // FIXME: Implement this + // In all cases, Sun returns false here. return false; } @@ -140,8 +139,6 @@ public class DragSource implements Serializable // This function sends the same message to the context, which then forwards // it to the peer, passing itself as a parameter. Now, the native system has // access to the Transferable through the context. - - // FIXME: Add check to determine if dragging. try { @@ -316,7 +313,7 @@ public class DragSource implements Serializable /** * TODO - * @return + * @return TODO * * @since 1.5 */ @@ -324,6 +321,6 @@ public class DragSource implements Serializable throws NotImplementedException { // FIXME: Not implemented. - return 4; + return 8; } } // class DragSource diff --git a/java/awt/dnd/DropTarget.java b/java/awt/dnd/DropTarget.java index a3650567f..1e7b2c4cd 100644 --- a/java/awt/dnd/DropTarget.java +++ b/java/awt/dnd/DropTarget.java @@ -45,6 +45,7 @@ import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.Point; import java.awt.datatransfer.FlavorMap; +import java.awt.datatransfer.SystemFlavorMap; import java.awt.dnd.peer.DropTargetPeer; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -113,7 +114,7 @@ public class DropTarget */ public DropTarget () { - this (null, 0, null, true, null); + this (null, DnDConstants.ACTION_COPY_OR_MOVE, null, true, null); } /** @@ -124,7 +125,7 @@ public class DropTarget */ public DropTarget (Component c, DropTargetListener dtl) { - this (c, 0, dtl, true, null); + this (c, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true, null); } /** @@ -164,7 +165,11 @@ public class DropTarget setComponent(c); setDefaultActions(i); dropTargetListener = dtl; - flavorMap = fm; + + if (fm == null) + flavorMap = SystemFlavorMap.getDefaultFlavorMap(); + else + flavorMap = fm; setActive (b); @@ -225,8 +230,14 @@ public class DropTarget public void addDropTargetListener (DropTargetListener dtl) throws TooManyListenersException { + if (dtl == null) + return; + + if (dtl.equals(this)) + throw new IllegalArgumentException(); + if (dropTargetListener != null) - throw new TooManyListenersException (); + throw new TooManyListenersException(); dropTargetListener = dtl; } diff --git a/java/awt/font/FontRenderContext.java b/java/awt/font/FontRenderContext.java index c50e5e509..c25bae3ec 100644 --- a/java/awt/font/FontRenderContext.java +++ b/java/awt/font/FontRenderContext.java @@ -117,8 +117,12 @@ public class FontRenderContext */ public int hashCode () { - // FIXME: check what SUN does here. - return affineTransform == null ? 0 : affineTransform.hashCode (); + int code = ( isAntiAliased ? 1 : 0 ) + ( usesFractionalMetrics ? 2 : 0 ); + + if( affineTransform != null && !affineTransform.isIdentity() ) + code ^= affineTransform.hashCode(); + + return code; } public boolean isAntiAliased () diff --git a/java/awt/geom/AffineTransform.java b/java/awt/geom/AffineTransform.java index 55b688355..5bc51ddee 100644 --- a/java/awt/geom/AffineTransform.java +++ b/java/awt/geom/AffineTransform.java @@ -1401,10 +1401,10 @@ public class AffineTransform implements Cloneable, Serializable * documented, but appears to be the same as: *
        * long l = Double.doubleToLongBits(getScaleX());
    -   * l = l * 31 + Double.doubleToLongBits(getShearY());
        * l = l * 31 + Double.doubleToLongBits(getShearX());
    -   * l = l * 31 + Double.doubleToLongBits(getScaleY());
        * l = l * 31 + Double.doubleToLongBits(getTranslateX());
    +   * l = l * 31 + Double.doubleToLongBits(getShearY());
    +   * l = l * 31 + Double.doubleToLongBits(getScaleY());
        * l = l * 31 + Double.doubleToLongBits(getTranslateY());
        * return (int) ((l >> 32) ^ l);
        * 
    @@ -1413,12 +1413,12 @@ public class AffineTransform implements Cloneable, Serializable */ public int hashCode() { - long l = Double.doubleToLongBits(m00); - l = l * 31 + Double.doubleToLongBits(m10); - l = l * 31 + Double.doubleToLongBits(m01); - l = l * 31 + Double.doubleToLongBits(m11); - l = l * 31 + Double.doubleToLongBits(m02); - l = l * 31 + Double.doubleToLongBits(m12); + long l = Double.doubleToLongBits(m00); + l = l * 31 + Double.doubleToLongBits(m01); + l = l * 31 + Double.doubleToLongBits(m02); + l = l * 31 + Double.doubleToLongBits(m10); + l = l * 31 + Double.doubleToLongBits(m11); + l = l * 31 + Double.doubleToLongBits(m12); return (int) ((l >> 32) ^ l); } diff --git a/java/awt/image/BufferedImage.java b/java/awt/image/BufferedImage.java index c6de10fa4..1e94ad66d 100644 --- a/java/awt/image/BufferedImage.java +++ b/java/awt/image/BufferedImage.java @@ -79,26 +79,36 @@ public class BufferedImage extends Image TYPE_BYTE_BINARY = 12, TYPE_BYTE_INDEXED = 13; - static final int[] bits3 = { 8, 8, 8 }; - static final int[] bits4 = { 8, 8, 8, 8 }; - static final int[] bits1byte = { 8 }; - static final int[] bits1ushort = { 16 }; - - static final int[] masks_int = { 0x00ff0000, - 0x0000ff00, - 0x000000ff, - DataBuffer.TYPE_INT }; - static final int[] masks_565 = { 0xf800, - 0x07e0, - 0x001f, - DataBuffer.TYPE_USHORT}; - static final int[] masks_555 = { 0x7c00, - 0x03e0, - 0x001f, - DataBuffer.TYPE_USHORT}; - - Vector observers; + /** + * Vector of TileObservers (or null) + */ + Vector tileObservers; + /** + * The image's WritableRaster + */ + WritableRaster raster; + + /** + * The associated ColorModel + */ + ColorModel colorModel; + + /** + * The image's properties (or null) + */ + Hashtable properties; + + /** + * Whether alpha is premultiplied + */ + boolean isPremultiplied; + + /** + * The predefined type, if any. + */ + int type; + /** * Creates a new BufferedImage with the specified width, height * and type. Valid type values are: @@ -128,128 +138,150 @@ public class BufferedImage extends Image * @throws IllegalArgumentException if type is not one of the * specified values. */ - public BufferedImage(int w, int h, int type) + public BufferedImage(int width, int height, int type) { + SampleModel sm = null; ColorModel cm = null; - - boolean alpha = false; - boolean premultiplied = false; - switch (type) - { - case TYPE_4BYTE_ABGR_PRE: - case TYPE_INT_ARGB_PRE: - premultiplied = true; - // fall through - case TYPE_INT_ARGB: - case TYPE_4BYTE_ABGR: - alpha = true; - } - - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - switch (type) + boolean premultiplied = (type == BufferedImage.TYPE_INT_ARGB_PRE || + type == BufferedImage.TYPE_4BYTE_ABGR_PRE); + + switch( type ) { - case TYPE_INT_RGB: - case TYPE_INT_ARGB: - case TYPE_INT_ARGB_PRE: - case TYPE_USHORT_565_RGB: - case TYPE_USHORT_555_RGB: - int[] masks = null; - switch (type) - { - case TYPE_INT_RGB: - case TYPE_INT_ARGB: - case TYPE_INT_ARGB_PRE: - masks = masks_int; - break; - case TYPE_USHORT_565_RGB: - masks = masks_565; - break; - case TYPE_USHORT_555_RGB: - masks = masks_555; - break; - } - - cm = new DirectColorModel(cs, - 32, // 32 bits in an int - masks[0], // r - masks[1], // g - masks[2], // b - alpha ? 0xff000000 : 0, - premultiplied, - masks[3] // data type - ); + case BufferedImage.TYPE_INT_RGB: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x00FF0000, + 0x0000FF00, + 0x000000FF } ) ; + cm = new DirectColorModel( 24, 0xff0000, 0xff00, 0xff ); break; - case TYPE_INT_BGR: - String msg = - "FIXME: Programmer is confused. Why (and how) does a " + - "TYPE_INT_BGR image use ComponentColorModel to store " + - "8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " + - "is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?"; - throw new UnsupportedOperationException(msg); - - case TYPE_3BYTE_BGR: - case TYPE_4BYTE_ABGR: - case TYPE_4BYTE_ABGR_PRE: - case TYPE_BYTE_GRAY: - case TYPE_USHORT_GRAY: - int[] bits = null; - int dataType = DataBuffer.TYPE_BYTE; - switch (type) { - case TYPE_3BYTE_BGR: - bits = bits3; - break; - case TYPE_4BYTE_ABGR: - case TYPE_4BYTE_ABGR_PRE: - bits = bits4; - break; - case TYPE_BYTE_GRAY: - bits = bits1byte; - cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - break; - case TYPE_USHORT_GRAY: - bits = bits1ushort; - cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - dataType = DataBuffer.TYPE_USHORT; - break; - } - cm = new ComponentColorModel(cs, bits, alpha, premultiplied, - alpha ? - Transparency.TRANSLUCENT: - Transparency.OPAQUE, - dataType); + case BufferedImage.TYPE_3BYTE_BGR: + sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE, + width, height, + 3, width * 3, + new int[]{ 2, 1, 0 } ); + cm = new DirectColorModel( 24, 0xff, 0xff00, 0xff0000 ); break; - case TYPE_BYTE_BINARY: - byte[] vals = { 0, (byte) 0xff }; - cm = new IndexColorModel(8, 2, vals, vals, vals); + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000 } ); + cm = new DirectColorModel( 32, 0xff0000, 0xff00, 0xff, 0xff000000 ); + break; + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x000000FF, + 0xFF000000, + 0x00FF0000, + 0x0000FF00 } ); + cm = new DirectColorModel( 32, 0xff, 0xff00, 0xff0000, 0xff000000 ); + break; + + case BufferedImage.TYPE_INT_BGR: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT, + width, height, + new int[]{ 0x000000FF, + 0x0000FF00, + 0x00FF0000 } ) ; + cm = new DirectColorModel( 32, 0xff, 0xff00, 0xff0000 ); + break; + + case BufferedImage.TYPE_USHORT_565_RGB: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT, + width, height, + new int[]{ 0x0000001F, + 0x000007E0, + 0x0000F800 } ) ; + cm = new DirectColorModel( 16, 0x1F, 0x7E0, 0xf800 ); break; - case TYPE_BYTE_INDEXED: - String msg2 = "type not implemented yet"; - throw new UnsupportedOperationException(msg2); - // FIXME: build color-cube and create color model + case BufferedImage.TYPE_USHORT_555_RGB: + sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT, + width, height, + new int[]{ 0x0000001F, + 0x000003E0, + 0x00007C00 } ) ; + cm = new DirectColorModel( 15, 0x1F, 0x3E0, 0x7c00 ); + break; + + case BufferedImage.TYPE_BYTE_INDEXED: + cm = createDefaultIndexedColorModel( false ); + + case BufferedImage.TYPE_BYTE_GRAY: + sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE, + width, height, + 1, width, new int[]{ 0 } ); + break; + + case BufferedImage.TYPE_USHORT_GRAY: + sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_USHORT, + width, height, + 1, width, new int[]{ 0 } ); + break; + + case BufferedImage.TYPE_BYTE_BINARY: + cm = createDefaultIndexedColorModel( true ); + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1); + break; + default: - throw new IllegalArgumentException("Unknown image type " + type); + sm = null; } + + if( sm == null ) + throw new IllegalArgumentException("Unknown predefined image type."); - init(cm, - cm.createCompatibleWritableRaster(w, h), - premultiplied, - null, // no properties - type - ); + if( cm == null ) // only for the grayscale types + { + int buftype; + int[] bits = new int[1]; + if( type == BufferedImage.TYPE_BYTE_GRAY ) + { + buftype = DataBuffer.TYPE_BYTE; + bits[0] = 8; + } + else + { + buftype = DataBuffer.TYPE_USHORT; + bits[0] = 16; + } + ColorSpace graySpace = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + + cm = new ComponentColorModel( graySpace, bits, false, false, + Transparency.OPAQUE, buftype ); + } + + init( cm, + Raster.createWritableRaster(sm, new Point( 0, 0 ) ), + premultiplied, + null, // no properties + type ); } public BufferedImage(int w, int h, int type, IndexColorModel indexcolormodel) { if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED)) - throw new IllegalArgumentException("type must be binary or indexed"); + throw new IllegalArgumentException("Type must be TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED"); + if( indexcolormodel.getMapSize() > 16 && type == TYPE_BYTE_BINARY ) + throw new IllegalArgumentException("Type TYPE_BYTE_BINARY cannot have a larger than 16-color palette."); + if( indexcolormodel.getMapSize() > 256 ) + throw new IllegalArgumentException("Byte type cannot have a larger than 256-color palette."); - init(indexcolormodel, - indexcolormodel.createCompatibleWritableRaster(w, h), - false, // not premultiplied (guess) - null, // no properties - type); + init( indexcolormodel, + indexcolormodel.createCompatibleWritableRaster(w, h), + indexcolormodel.isAlphaPremultiplied(), + null, // no properties + type ); } public BufferedImage(ColorModel colormodel, @@ -259,15 +291,9 @@ public class BufferedImage extends Image { init(colormodel, writableraster, premultiplied, properties, TYPE_CUSTOM); - // TODO: perhaps try to identify type? } - WritableRaster raster; - ColorModel colorModel; - Hashtable properties; - boolean isPremultiplied; - int type; - + private void init(ColorModel cm, WritableRaster writableraster, boolean premultiplied, @@ -280,8 +306,43 @@ public class BufferedImage extends Image isPremultiplied = premultiplied; this.type = type; } - - //public void addTileObserver(TileObserver tileobserver) {} + + /** + * Creates the default palettes for the predefined indexed color types + * (256-color or black-and-white) + * + * @param binary - If true, a black and white palette, + * otherwise a default 256-color palette is returned. + */ + private IndexColorModel createDefaultIndexedColorModel( boolean binary ) + { + if( binary ) + { + byte[] t = new byte[]{ 0, (byte)255 }; + return new IndexColorModel( 1, 2, t, t, t ); + } + + byte[] r = new byte[256]; + byte[] g = new byte[256]; + byte[] b = new byte[256]; + int index = 0; + for( int i = 0; i < 6; i++ ) + for( int j = 0; j < 6; j++ ) + for( int k = 0; k < 6; k++ ) + { + r[ index ] = (byte)(i * 51); + g[ index ] = (byte)(j * 51); + b[ index ] = (byte)(k * 51); + index++; + } + while( index < 256 ) + { + r[ index ] = g[ index ] = b[ index ] = + (byte)(18 + (index - 216) * 6); + index++; + } + return new IndexColorModel( 8, 256, r, g, b ); + } public void coerceData(boolean premultiplied) { @@ -726,10 +787,10 @@ public class BufferedImage extends Image */ public void addTileObserver (TileObserver to) { - if (observers == null) - observers = new Vector (); + if (tileObservers == null) + tileObservers = new Vector (); - observers.add (to); + tileObservers.add (to); } /** @@ -741,10 +802,10 @@ public class BufferedImage extends Image */ public void removeTileObserver (TileObserver to) { - if (observers == null) + if (tileObservers == null) return; - observers.remove (to); + tileObservers.remove (to); } /** diff --git a/java/io/ObjectInputStream.java b/java/io/ObjectInputStream.java index 18ff95f05..98632607c 100644 --- a/java/io/ObjectInputStream.java +++ b/java/io/ObjectInputStream.java @@ -547,8 +547,6 @@ public class ObjectInputStream extends InputStream flags, fields); assignNewHandle(osc); - ClassLoader callersClassLoader = currentLoader(); - for (int i = 0; i < field_count; i++) { if(dump) dumpElement(" TYPE CODE="); @@ -568,12 +566,17 @@ public class ObjectInputStream extends InputStream class_name = String.valueOf(type_code); fields[i] = - new ObjectStreamField(field_name, class_name, callersClassLoader); + new ObjectStreamField(field_name, class_name); } /* Now that fields have been read we may resolve the class * (and read annotation if needed). */ Class clazz = resolveClass(osc); + ClassLoader loader = clazz.getClassLoader(); + for (int i = 0; i < field_count; i++) + { + fields[i].resolveType(loader); + } boolean oldmode = setBlockDataMode(true); osc.setClass(clazz, lookupClass(clazz.getSuperclass())); classLookupTable.put(clazz, osc); diff --git a/java/io/ObjectStreamField.java b/java/io/ObjectStreamField.java index 26f2d77cb..b0cac5015 100644 --- a/java/io/ObjectStreamField.java +++ b/java/io/ObjectStreamField.java @@ -118,28 +118,10 @@ public class ObjectStreamField { this.name = name; this.typename = typename; - try - { - type = TypeSignature.getClassForEncoding(typename); - } - catch(ClassNotFoundException e) - { - } } - - /** - * There are many cases you can not get java.lang.Class from typename - * if your context class loader cann not load it, then use typename to - * construct the field. - * - * @param name Name of the field to export. - * @param typename The coded name of the type for this field. - * @param loader The class loader to use to resolve class names. - */ - ObjectStreamField (String name, String typename, ClassLoader loader) + + void resolveType(ClassLoader loader) { - this.name = name; - this.typename = typename; try { type = TypeSignature.getClassForEncoding(typename, true, loader); @@ -148,7 +130,7 @@ public class ObjectStreamField { } } - + /** * This method returns the name of the field represented by the * ObjectStreamField instance. diff --git a/java/lang/StrictMath.java b/java/lang/StrictMath.java index 0f0662167..ec74ca413 100644 --- a/java/lang/StrictMath.java +++ b/java/lang/StrictMath.java @@ -632,6 +632,94 @@ public final strictfp class StrictMath return y > 0 ? PI - (z - PI_L) : z - PI_L - PI; } + /** + * Returns the hyperbolic sine of x which is defined as + * (exp(x) - exp(-x)) / 2. + * + * Special cases: + *
      + *
    • If the argument is NaN, the result is NaN
    • + *
    • If the argument is positive infinity, the result is positive + * infinity.
    • + *
    • If the argument is negative infinity, the result is negative + * infinity.
    • + *
    • If the argument is zero, the result is zero.
    • + *
    + * + * @param x the argument to sinh + * @return the hyperbolic sine of x + * + * @since 1.5 + */ + public static double sinh(double x) + { + // Method : + // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + // 1. Replace x by |x| (sinh(-x) = -sinh(x)). + // 2. + // E + E/(E+1) + // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) + // 2 + // + // 22 <= x <= lnovft : sinh(x) := exp(x)/2 + // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) + // ln2ovft < x : sinh(x) := +inf (overflow) + + double t, w, h; + + long bits; + long h_bits; + long l_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + + if (x < 0) + h = - 0.5; + else + h = 0.5; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ignore sign + l_bits = getLowDWord(bits); + + // |x| in [0, 22], return sign(x) * 0.5 * (E+E/(E+1)) + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3e300000L) // |x| < 2^-28 + return x; // for tiny arguments return x + + t = expm1(abs(x)); + + if (h_bits < 0x3ff00000L) + return h * (2.0 * t - t * t / (t + 1.0)); + + return h * (t + t / (t + 1.0)); + } + + // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) + if (h_bits < 0x40862e42L) + return h * exp(abs(x)); + + // |x| in [log(Double.MAX_VALUE), overflowthreshold] + if ((h_bits < 0x408633ceL) + || ((h_bits == 0x408633ceL) && (l_bits <= 0x8fb9f87dL))) + { + w = exp(0.5 * abs(x)); + t = h * w; + + return t * w; + } + + // |x| > overflowthershold + return h * Double.POSITIVE_INFINITY; + } + /** * Returns the hyperbolic cosine of x, which is defined as * (exp(x) + exp(-x)) / 2. @@ -670,36 +758,36 @@ public final strictfp class StrictMath double t, w; long bits; - int hx; - int lx; + long hx; + long lx; // handle special cases if (x != x) - return Double.NaN; + return x; if (x == Double.POSITIVE_INFINITY) return Double.POSITIVE_INFINITY; if (x == Double.NEGATIVE_INFINITY) return Double.POSITIVE_INFINITY; bits = Double.doubleToLongBits(x); - hx = getHighDWord(bits) & 0x7fffffff; // ignore sign + hx = getHighDWord(bits) & 0x7fffffffL; // ignore sign lx = getLowDWord(bits); // |x| in [0, 0.5 * ln(2)], return 1 + expm1(|x|)^2 / (2 * exp(|x|)) - if (hx < 0x3fd62e43) + if (hx < 0x3fd62e43L) { t = expm1(abs(x)); w = 1.0 + t; // for tiny arguments return 1. - if (hx < 0x3c800000) + if (hx < 0x3c800000L) return w; return 1.0 + (t * t) / (w + w); } // |x| in [0.5 * ln(2), 22], return exp(|x|)/2 + 1 / (2 * exp(|x|)) - if (hx < 0x40360000) + if (hx < 0x40360000L) { t = exp(abs(x)); @@ -707,16 +795,13 @@ public final strictfp class StrictMath } // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) - if (hx < 0x40862e42) + if (hx < 0x40862e42L) return 0.5 * exp(abs(x)); // |x| in [log(Double.MAX_VALUE), overflowthreshold], // return exp(x/2)/2 * exp(x/2) - - // we need to force an unsigned <= compare, thus can not use lx. - if ((hx < 0x408633ce) - || ((hx == 0x408633ce) - && ((bits & 0x00000000ffffffffL) <= 0x8fb9f87dL))) + if ((hx < 0x408633ceL) + || ((hx == 0x408633ceL) && (lx <= 0x8fb9f87dL))) { w = exp(0.5 * abs(x)); t = 0.5 * w; @@ -728,14 +813,83 @@ public final strictfp class StrictMath return Double.POSITIVE_INFINITY; } + /** + * Returns the hyperbolic tangent of x, which is defined as + * (exp(x) - exp(-x)) / (exp(x) + exp(-x)), i.e. sinh(x) / cosh(x). + * + Special cases: + *
      + *
    • If the argument is NaN, the result is NaN
    • + *
    • If the argument is positive infinity, the result is 1.
    • + *
    • If the argument is negative infinity, the result is -1.
    • + *
    • If the argument is zero, the result is zero.
    • + *
    + * + * @param x the argument to tanh + * @return the hyperbolic tagent of x + * + * @since 1.5 + */ + public static double tanh(double x) + { + // Method : + // 0. tanh(x) is defined to be (exp(x) - exp(-x)) / (exp(x) + exp(-x)) + // 1. reduce x to non-negative by tanh(-x) = -tanh(x). + // 2. 0 <= x <= 2^-55 : tanh(x) := x * (1.0 + x) + // -t + // 2^-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x) + // t + 2 + // 2 + // 1 <= x <= 22.0 : tanh(x) := 1 - ----- ; t=expm1(2x) + // t + 2 + // 22.0 < x <= INF : tanh(x) := 1. + + double t, z; + + long bits; + long h_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return 1.0; + if (x == Double.NEGATIVE_INFINITY) + return -1.0; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ingnore sign + + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3c800000L) // |x| < 2^-55 + return x * (1.0 + x); + + if (h_bits >= 0x3ff00000L) // |x| >= 1 + { + t = expm1(2.0 * abs(x)); + z = 1.0 - 2.0 / (t + 2.0); + } + else // |x| < 1 + { + t = expm1(-2.0 * abs(x)); + z = -t / (t + 2.0); + } + } + else // |x| >= 22 + z = 1.0; + + return (x >= 0) ? z : -z; + } + /** * Returns the lower two words of a long. This is intended to be * used like this: * getLowDWord(Double.doubleToLongBits(x)). */ - private static int getLowDWord(long x) + private static long getLowDWord(long x) { - return (int) (x & 0x00000000ffffffffL); + return x & 0x00000000ffffffffL; } /** @@ -743,19 +897,19 @@ public final strictfp class StrictMath * used like this: * getHighDWord(Double.doubleToLongBits(x)). */ - private static int getHighDWord(long x) + private static long getHighDWord(long x) { - return (int) ((x & 0xffffffff00000000L) >> 32); + return (x & 0xffffffff00000000L) >> 32; } /** * Returns a double with the IEEE754 bit pattern given in the lower * and higher two words lowDWord and highDWord. */ - private static double buildDouble(int lowDWord, int highDWord) + private static double buildDouble(long lowDWord, long highDWord) { - return Double.longBitsToDouble((((long) highDWord & 0xffffffffL) << 32) - | ((long) lowDWord & 0xffffffffL)); + return Double.longBitsToDouble(((highDWord & 0xffffffffL) << 32) + | (lowDWord & 0xffffffffL)); } /** @@ -788,12 +942,12 @@ public final strictfp class StrictMath double w; long bits; - int l; - int h; + long l; + long h; // handle the special cases if (x != x) - return Double.NaN; + return x; if (x == Double.POSITIVE_INFINITY) return Double.POSITIVE_INFINITY; if (x == Double.NEGATIVE_INFINITY) @@ -847,7 +1001,7 @@ public final strictfp class StrictMath s = t * t; // t * t is exact r = x / s; w = t + t; - r = (r - t) / (w + r); // r - s is exact + r = (r - t) / (w + r); // r - t is exact t = t + t * r; return negative ? -t : t; @@ -1008,8 +1162,8 @@ public final strictfp class StrictMath int k; long bits; - int h_bits; - int l_bits; + long h_bits; + long l_bits; c = 0.0; y = abs(x); @@ -1019,14 +1173,14 @@ public final strictfp class StrictMath l_bits = getLowDWord(bits); // handle special cases and large arguments - if (h_bits >= 0x4043687a) // if |x| >= 56 * ln(2) + if (h_bits >= 0x4043687aL) // if |x| >= 56 * ln(2) { - if (h_bits >= 0x40862e42) // if |x| >= EXP_LIMIT_H + if (h_bits >= 0x40862e42L) // if |x| >= EXP_LIMIT_H { - if (h_bits >= 0x7ff00000) + if (h_bits >= 0x7ff00000L) { - if (((h_bits & 0x000fffff) | (l_bits & 0xffffffff)) != 0) - return Double.NaN; // exp(NaN) = NaN + if (((h_bits & 0x000fffffL) | (l_bits & 0xffffffffL)) != 0) + return x; // exp(NaN) = NaN else return negative ? -1.0 : x; // exp({+-inf}) = {+inf, -1} } @@ -1040,9 +1194,9 @@ public final strictfp class StrictMath } // argument reduction - if (h_bits > 0x3fd62e42) // |x| > 0.5 * ln(2) + if (h_bits > 0x3fd62e42L) // |x| > 0.5 * ln(2) { - if (h_bits < 0x3ff0a2b2) // |x| < 1.5 * ln(2) + if (h_bits < 0x3ff0a2b2L) // |x| < 1.5 * ln(2) { if (negative) { @@ -1069,7 +1223,7 @@ public final strictfp class StrictMath c = (hi - x) - lo; } - else if (h_bits < 0x3c900000) // |x| < 2^-54 return x + else if (h_bits < 0x3c900000L) // |x| < 2^-54 return x return x; else k = 0; @@ -1124,7 +1278,7 @@ public final strictfp class StrictMath if (k < 20) { bits = Double.doubleToLongBits(t); - h_bits = 0x3ff00000 - (0x00200000 >> k); + h_bits = 0x3ff00000L - (0x00200000L >> k); l_bits = getLowDWord(bits); t = buildDouble(l_bits, h_bits); // t = 1 - 2^(-k) @@ -1141,7 +1295,7 @@ public final strictfp class StrictMath else { bits = Double.doubleToLongBits(t); - h_bits = (0x000003ff - k) << 20; + h_bits = (0x000003ffL - k) << 20; l_bits = getLowDWord(bits); t = buildDouble(l_bits, h_bits); // t = 2^(-k) diff --git a/java/nio/DirectByteBufferImpl.java b/java/nio/DirectByteBufferImpl.java index 3a9036f31..8c907f597 100644 --- a/java/nio/DirectByteBufferImpl.java +++ b/java/nio/DirectByteBufferImpl.java @@ -233,7 +233,7 @@ abstract class DirectByteBufferImpl extends ByteBuffer { int pos = position(); if (this.mark != -1) - reset(); + reset(); int mark = position(); position(pos); DirectByteBufferImpl result; diff --git a/java/security/AccessControlContext.java b/java/security/AccessControlContext.java index 3b51e9412..ffcfc0e41 100644 --- a/java/security/AccessControlContext.java +++ b/java/security/AccessControlContext.java @@ -89,12 +89,30 @@ public final class AccessControlContext public AccessControlContext(AccessControlContext acc, DomainCombiner combiner) { + AccessControlContext acc2 = null; SecurityManager sm = System.getSecurityManager (); if (sm != null) { - sm.checkPermission (new SecurityPermission ("createAccessControlContext")); + Permission perm = + new SecurityPermission ("createAccessControlContext"); + + // The default SecurityManager.checkPermission(perm) just calls + // AccessController.checkPermission(perm) which in turn just + // calls AccessController.getContext().checkPermission(perm). + // This means AccessController.getContext() is called twice, + // once for the security check and once by us. It's a very + // expensive call (on gcj at least) so if we're using the + // default security manager we avoid this duplication. + if (sm.getClass() == SecurityManager.class) + { + acc2 = AccessController.getContext (); + acc2.checkPermission (perm); + } + else + sm.checkPermission (perm); } - AccessControlContext acc2 = AccessController.getContext(); + if (acc2 == null) + acc2 = AccessController.getContext (); protectionDomains = combiner.combine (acc2.protectionDomains, acc.protectionDomains); this.combiner = combiner; diff --git a/java/text/SimpleDateFormat.java b/java/text/SimpleDateFormat.java index 2825c7bed..1e1952569 100644 --- a/java/text/SimpleDateFormat.java +++ b/java/text/SimpleDateFormat.java @@ -917,7 +917,25 @@ public class SimpleDateFormat extends DateFormat || ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))) { - if (! expect (dateStr, pos, ch)) + if (quote_start == -1 && ch == ' ') + { + // A single unquoted space in the pattern may match + // any number of spaces in the input. + int index = pos.getIndex(); + int save = index; + while (index < dateStr.length() + && Character.isWhitespace(dateStr.charAt(index))) + ++index; + if (index > save) + pos.setIndex(index); + else + { + // Didn't see any whitespace. + pos.setErrorIndex(index); + return null; + } + } + else if (! expect (dateStr, pos, ch)) return null; continue; } diff --git a/javax/management/BadAttributeValueExpException.java b/javax/management/BadAttributeValueExpException.java new file mode 100644 index 000000000..fbdf1deca --- /dev/null +++ b/javax/management/BadAttributeValueExpException.java @@ -0,0 +1,91 @@ +/* BadAttributeValueExpException.java -- Thrown by invalid query attributes. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when the value of an a attribute passed to a query proves to + * be invalid. This exception is only used internally by the Java + * management API and is not exposed to user code. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class BadAttributeValueExpException + extends Exception +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -3105272988410493376L; + + /** + * The attribute value that caused the exception. + */ + private Object val; + + /** + * Constructs a new BadAttributeValueExpException + * using the specified object to represent the invalid value. + * + * @param val the inappropriate value. + */ + public BadAttributeValueExpException(Object val) + { + super(); + this.val = val; + } + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.BadAttributeValueExpException) + * and the invalid value. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + return getClass().getName() + + "[val=" + val + + "]"; + } + +} + diff --git a/javax/management/BadStringOperationException.java b/javax/management/BadStringOperationException.java new file mode 100644 index 000000000..8e5949ef7 --- /dev/null +++ b/javax/management/BadStringOperationException.java @@ -0,0 +1,92 @@ +/* BadStringOperationException.java -- Thrown by invalid query attributes. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when a string-based operation passed to a query proves to + * be invalid. This exception is only used internally by the Java + * management API and is not exposed to user code. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class BadStringOperationException + extends Exception +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 7802201238441662100L; + + /** + * The operation that caused the exception. + */ + private String op; + + /** + * Constructs a new BadStringOperationException + * using the specified object to represent the invalid string + * operation. + * + * @param op the inappropriate string operation. + */ + public BadStringOperationException(String op) + { + super(); + this.op = op; + } + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.BadStringOperationException) + * and the invalid string operation. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + return getClass().getName() + + "[op=" + op + + "]"; + } + +} + diff --git a/javax/management/InstanceAlreadyExistsException.java b/javax/management/InstanceAlreadyExistsException.java new file mode 100644 index 000000000..c783208cb --- /dev/null +++ b/javax/management/InstanceAlreadyExistsException.java @@ -0,0 +1,76 @@ +/* InstanceAlreadyExistsException.java -- Thrown by invalid values. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when an attempt to register a bean is made, and + * the bean is already registered. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class InstanceAlreadyExistsException + extends OperationsException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 8893743928912733931L; + + /** + * Constructs a new InstanceAlreadyExistsException. + */ + public InstanceAlreadyExistsException() + { + super(); + } + + /** + * Constructs a new InstanceAlreadyExistsException + * with the specified message. + * + * @param message the error message to give to the user. + */ + public InstanceAlreadyExistsException(String message) + { + super(message); + } + +} + diff --git a/javax/management/InstanceNotFoundException.java b/javax/management/InstanceNotFoundException.java new file mode 100644 index 000000000..4d209fc47 --- /dev/null +++ b/javax/management/InstanceNotFoundException.java @@ -0,0 +1,76 @@ +/* InstanceNotFoundException.java -- Thrown by invalid values. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when an attempt to locate a bean is made, and + * the bean does not exist in the repository. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class InstanceNotFoundException + extends OperationsException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -882579438394773049L; + + /** + * Constructs a new InstanceNotFoundException. + */ + public InstanceNotFoundException() + { + super(); + } + + /** + * Constructs a new InstanceNotFoundException + * with the specified message. + * + * @param message the error message to give to the user. + */ + public InstanceNotFoundException(String message) + { + super(message); + } + +} + diff --git a/javax/management/InvalidApplicationException.java b/javax/management/InvalidApplicationException.java new file mode 100644 index 000000000..0bcf2d6cb --- /dev/null +++ b/javax/management/InvalidApplicationException.java @@ -0,0 +1,92 @@ +/* InvalidApplicationException.java -- Thrown by invalid query attributes. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when a query or attribute is applied to a management bean + * which is of the wrong class. This exception is only used + * internally by the Java management API and is not exposed to user + * code. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class InvalidApplicationException + extends Exception +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -3048022274675537269L; + + /** + * The attribute value that caused the exception. + */ + private Object val; + + /** + * Constructs a new InvalidApplicationException + * using the specified object to represent the invalid value. + * + * @param val the inappropriate expression. + */ + public InvalidApplicationException(Object val) + { + super(); + this.val = val; + } + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.InvalidApplicationException) + * and the invalid expression. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + return getClass().getName() + + "[val=" + val + + "]"; + } + +} + diff --git a/javax/management/MBeanConstructorInfo.java b/javax/management/MBeanConstructorInfo.java index 832a3296d..9ddd432a8 100644 --- a/javax/management/MBeanConstructorInfo.java +++ b/javax/management/MBeanConstructorInfo.java @@ -89,10 +89,11 @@ public class MBeanConstructorInfo * Constructs a @link{MBeanConstructorInfo} with the specified * name, description and parameter information. A null * value for the parameter information is the same as passing in - * an empty array. + * an empty array. A copy of the parameter array is taken, so + * later changes have no effect. * * @param name the name of the constructor. - * @param desc a description of the attribute. + * @param desc a description of the constructor. * @param sig the signature of the constructor, as a series * of {@link MBeanParameterInfo} objects, one for * each parameter. @@ -104,7 +105,10 @@ public class MBeanConstructorInfo if (sig == null) signature = new MBeanParameterInfo[0]; else - signature = sig; + { + signature = new MBeanParameterInfo[sig.length]; + System.arraycopy(sig, 0, signature, 0, sig.length); + } } /** diff --git a/javax/management/MBeanFeatureInfo.java b/javax/management/MBeanFeatureInfo.java index 4f0243e18..74a030387 100644 --- a/javax/management/MBeanFeatureInfo.java +++ b/javax/management/MBeanFeatureInfo.java @@ -79,7 +79,7 @@ public class MBeanFeatureInfo /** * The toString() result of this instance. */ - protected transient String string; + transient String string; /** * Constructs a new {@link MBeanFeatureInfo} with the specified diff --git a/javax/management/MBeanInfo.java b/javax/management/MBeanInfo.java index e6f03f065..d30de0499 100644 --- a/javax/management/MBeanInfo.java +++ b/javax/management/MBeanInfo.java @@ -140,7 +140,8 @@ public class MBeanInfo * can be loaded by the MBean server or class loader; it merely * has to be a syntactically correct class name. Any of the * arrays may be null; this will be treated as if - * an empty array was supplied. + * an empty array was supplied. A copy of the arrays is + * taken, so later changes have no effect. * * @param name the name of the class this instance describes. * @param desc a description of the bean. @@ -162,19 +163,31 @@ public class MBeanInfo if (attribs == null) attributes = new MBeanAttributeInfo[0]; else - attributes = attribs; + { + attributes = new MBeanAttributeInfo[attribs.length]; + System.arraycopy(attribs, 0, attributes, 0, attribs.length); + } if (cons == null) constructors = new MBeanConstructorInfo[0]; else - constructors = cons; + { + constructors = new MBeanConstructorInfo[cons.length]; + System.arraycopy(cons, 0, constructors, 0, cons.length); + } if (ops == null) operations = new MBeanOperationInfo[0]; else - operations = ops; + { + operations = new MBeanOperationInfo[ops.length]; + System.arraycopy(ops, 0, operations, 0, ops.length); + } if (notifs == null) notifications = new MBeanNotificationInfo[0]; else - notifications = notifs; + { + notifications = new MBeanNotificationInfo[notifs.length]; + System.arraycopy(notifs, 0, notifications, 0, notifs.length); + } } /** diff --git a/javax/management/MBeanOperationInfo.java b/javax/management/MBeanOperationInfo.java index a2db8d1b0..2a78d19d9 100644 --- a/javax/management/MBeanOperationInfo.java +++ b/javax/management/MBeanOperationInfo.java @@ -140,7 +140,8 @@ public class MBeanOperationInfo * Constructs a @link{MBeanOperationInfo} with the specified name, * description, parameter information, return type and impact. A * null value for the parameter information is the same - * as passing in an empty array. + * as passing in an empty array. A copy of the parameter array is + * taken, so later changes have no effect. * * @param name the name of the constructor. * @param desc a description of the attribute. @@ -158,7 +159,10 @@ public class MBeanOperationInfo if (sig == null) signature = new MBeanParameterInfo[0]; else - signature = sig; + { + signature = new MBeanParameterInfo[sig.length]; + System.arraycopy(sig, 0, signature, 0, sig.length); + } this.type = type; this.impact = impact; } diff --git a/javax/management/MBeanRegistrationException.java b/javax/management/MBeanRegistrationException.java new file mode 100644 index 000000000..9f62b9aa0 --- /dev/null +++ b/javax/management/MBeanRegistrationException.java @@ -0,0 +1,84 @@ +/* MBeanRegistrationException.java -- A bean registration exception. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Represents an arbitrary exception thrown during registration of a + * management bean. When registering a bean causes an exception to be + * thrown, the resulting exception is wrapped inside an {@link + * MBeanRegistrationException}. Calling {@link getTargetException()} + * will return the wrapped exception. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class MBeanRegistrationException + extends MBeanException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 4482382455277067805L; + + /** + * Constructs a new MBeanRegistrationException wrapping + * the specified exception. + * + * @param e the exception to be wrapped. + */ + public MBeanRegistrationException(Exception e) + { + super(e); + } + + /** + * Constructs a new MBeanRegistrationException wrapping + * the specified exception and using the supplied message. + * + * @param e the exception to be wrapped. + * @param message the error message to give to the user. + */ + public MBeanRegistrationException(Exception e, String message) + { + super(e, message); + } + + +} + diff --git a/javax/management/MalformedObjectNameException.java b/javax/management/MalformedObjectNameException.java new file mode 100644 index 000000000..e2f577490 --- /dev/null +++ b/javax/management/MalformedObjectNameException.java @@ -0,0 +1,76 @@ +/* MalformedObjectNameException.java -- Thrown by invalid values. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when a string used as an {@link ObjectName} + * is invalid. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class MalformedObjectNameException + extends OperationsException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -572689714442915824L; + + /** + * Constructs a new MalformedObjectNameException. + */ + public MalformedObjectNameException() + { + super(); + } + + /** + * Constructs a new MalformedObjectNameException + * with the specified message. + * + * @param message the error message to give to the user. + */ + public MalformedObjectNameException(String message) + { + super(message); + } + +} + diff --git a/javax/management/RuntimeErrorException.java b/javax/management/RuntimeErrorException.java new file mode 100644 index 000000000..811dc40f2 --- /dev/null +++ b/javax/management/RuntimeErrorException.java @@ -0,0 +1,115 @@ +/* RuntimeErrorException.java -- A user-defined management error. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Represents an arbitrary error thrown by a management + * bean. When a management bean executes code that causes + * an error to be thrown, the resulting error is + * wrapped inside an {@link RuntimeErrorException}. Calling + * {@link getTargetError()} will return the wrapped + * exception. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class RuntimeErrorException + extends JMRuntimeException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 704338937753949796L; + + /** + * The target error. + * + * @serial the target error. + */ + private Error error; + + /** + * Constructs a new RuntimeErrorException wrapping + * the specified error. + * + * @param e the error to be wrapped. + */ + public RuntimeErrorException(Error e) + { + super(); + error = e; + } + + /** + * Constructs a new RuntimeErrorException wrapping + * the specified error and using the supplied message. + * + * @param e the error to be wrapped. + * @param message the error message to give to the user. + */ + public RuntimeErrorException(Error e, String message) + { + super(message); + error = e; + } + + /** + * Returns the true cause of this error, the wrapped + * error. + * + * @return the wrapped error. + */ + public Throwable getCause() + { + return error; + } + + /** + * Returns the true cause of this error, the wrapped + * error. + * + * @return the wrapped error. + */ + public Error getTargetError() + { + return error; + } + +} + diff --git a/javax/management/RuntimeMBeanException.java b/javax/management/RuntimeMBeanException.java new file mode 100644 index 000000000..95225a80a --- /dev/null +++ b/javax/management/RuntimeMBeanException.java @@ -0,0 +1,114 @@ +/* RuntimeMBeanException.java -- A user-defined management exception. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Represents an arbitrary runtime exception thrown by a management + * bean. When a management bean executes code that causes a runtime + * exception to be thrown, the resulting exception is wrapped inside a + * {@link RuntimeMBeanException}. Calling {@link + * getTargetException()} will return the wrapped exception. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class RuntimeMBeanException + extends JMRuntimeException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 5274912751982730171L; + + /** + * The target exception. + * + * @serial the target exception. + */ + private RuntimeException runtimeException; + + /** + * Constructs a new RuntimeMBeanException wrapping + * the specified exception. + * + * @param e the exception to be wrapped. + */ + public RuntimeMBeanException(RuntimeException e) + { + super(); + runtimeException = e; + } + + /** + * Constructs a new RuntimeMBeanException wrapping + * the specified exception and using the supplied message. + * + * @param e the exception to be wrapped. + * @param message the error message to give to the user. + */ + public RuntimeMBeanException(RuntimeException e, String message) + { + super(message); + runtimeException = e; + } + + /** + * Returns the true cause of this exception, the wrapped runtime + * exception. + * + * @return the wrapped exception. + */ + public Throwable getCause() + { + return runtimeException; + } + + /** + * Returns the true cause of this exception, the wrapped runtime + * exception. + * + * @return the wrapped exception. + */ + public RuntimeException getTargetException() + { + return runtimeException; + } + +} + diff --git a/javax/management/ServiceNotFoundException.java b/javax/management/ServiceNotFoundException.java new file mode 100644 index 000000000..602e1490d --- /dev/null +++ b/javax/management/ServiceNotFoundException.java @@ -0,0 +1,75 @@ +/* ServiceNotFoundException.java -- Thrown by invalid values. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management; + +/** + * Thrown when a requested service is unsupported. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class ServiceNotFoundException + extends OperationsException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -3990675661956646827L; + + /** + * Constructs a new ServiceNotFoundException. + */ + public ServiceNotFoundException() + { + super(); + } + + /** + * Constructs a new ServiceNotFoundException + * with the specified message. + * + * @param message the error message to give to the user. + */ + public ServiceNotFoundException(String message) + { + super(message); + } + +} + diff --git a/javax/management/StandardMBean.java b/javax/management/StandardMBean.java index 736192ee2..16b6f0b66 100644 --- a/javax/management/StandardMBean.java +++ b/javax/management/StandardMBean.java @@ -205,17 +205,13 @@ public class StandardMBean Method getter; try { - getter = iface.getMethod("get" + - name.substring(0, 1).toUpperCase() + - name.substring(1), null); + getter = iface.getMethod("get" + name, null); } catch (NoSuchMethodException e) { try { - getter = iface.getMethod("is" + - name.substring(0, 1).toUpperCase() + - name.substring(1), null); + getter = iface.getMethod("is" + name, null); } catch (NoSuchMethodException ex) { @@ -564,11 +560,9 @@ public class StandardMBean Method[] amethods; String attrib; if (name.startsWith("is")) - attrib = name.substring(2,3).toLowerCase() - + name.substring(3); + attrib = name.substring(2); else - attrib = name.substring(3,4).toLowerCase() - + name.substring(4); + attrib = name.substring(3); if (attributes.containsKey(attrib)) amethods = (Method[]) attributes.get(attrib); else @@ -583,8 +577,7 @@ public class StandardMBean methods[a].getParameterTypes().length == 1) { Method[] amethods; - String attrib = name.substring(3,4).toLowerCase() - + name.substring(4); + String attrib = name.substring(3); if (attributes.containsKey(attrib)) amethods = (Method[]) attributes.get(attrib); else @@ -595,7 +588,8 @@ public class StandardMBean amethods[1] = methods[a]; } else - operations.add(new MBeanOperationInfo("", methods[a])); + operations.add(new MBeanOperationInfo(methods[a].getName(), + methods[a])); } List attribs = new ArrayList(attributes.size()); Iterator it = attributes.entrySet().iterator(); @@ -605,7 +599,8 @@ public class StandardMBean Method[] amethods = (Method[]) entry.getValue(); try { - attribs.add(new MBeanAttributeInfo((String) entry.getKey(), "", + attribs.add(new MBeanAttributeInfo((String) entry.getKey(), + (String) entry.getKey(), amethods[0], amethods[1])); } catch (IntrospectionException e) @@ -632,7 +627,8 @@ public class StandardMBean MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length]; for (int a = 0; a < cinfo.length; ++a) { - MBeanConstructorInfo oldInfo = new MBeanConstructorInfo("", cons[a]); + MBeanConstructorInfo oldInfo = new MBeanConstructorInfo(cons[a].getName(), + cons[a]); String desc = getDescription(oldInfo); MBeanParameterInfo[] params = oldInfo.getSignature(); MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length]; @@ -665,8 +661,8 @@ public class StandardMBean oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo, oldInfo.getReturnType(), impact); } - info = new MBeanInfo(impl.getClass().getName(), "", ainfo, cinfo, - oinfo, null); + info = new MBeanInfo(impl.getClass().getName(), impl.getClass().getName(), + ainfo, cinfo, oinfo, null); String cname = getClassName(info); String desc = getDescription(info); info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, null); @@ -679,7 +675,7 @@ public class StandardMBean * * @return the management interface. */ - public Class getMBeanInterface() + public final Class getMBeanInterface() { return iface; } diff --git a/javax/management/openmbean/InvalidOpenTypeException.java b/javax/management/openmbean/InvalidOpenTypeException.java new file mode 100644 index 000000000..9c9ff8cfa --- /dev/null +++ b/javax/management/openmbean/InvalidOpenTypeException.java @@ -0,0 +1,76 @@ +/* InvalidOpenTypeException.java -- Thrown by an invalid open type. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +/** + * Thrown when a open data value has an erroneous open + * type. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class InvalidOpenTypeException + extends IllegalArgumentException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -2837312755412327534L; + + /** + * Constructs a new InvalidOpenTypeException. + */ + public InvalidOpenTypeException() + { + super(); + } + + /** + * Constructs a new InvalidOpenTypeException + * with the specified message. + * + * @param message the error message to give to the user. + */ + public InvalidOpenTypeException(String message) + { + super(message); + } + +} + diff --git a/javax/management/openmbean/KeyAlreadyExistsException.java b/javax/management/openmbean/KeyAlreadyExistsException.java new file mode 100644 index 000000000..cc6bba636 --- /dev/null +++ b/javax/management/openmbean/KeyAlreadyExistsException.java @@ -0,0 +1,77 @@ +/* KeyAlreadyExistsException.java -- Thrown when a key clashes with another. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +/** + * Thrown when a key (a field name or row index) is passed to a method + * of the {@link CompositeData} or {@link TabularData} classes and it + * is found to already be in use. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class KeyAlreadyExistsException + extends IllegalArgumentException +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 1845183636745282866L; + + /** + * Constructs a new KeyAlreadyExistsException. + */ + public KeyAlreadyExistsException() + { + super(); + } + + /** + * Constructs a new KeyAlreadyExistsException + * with the specified message. + * + * @param message the error message to give to the user. + */ + public KeyAlreadyExistsException(String message) + { + super(message); + } + +} + diff --git a/javax/management/openmbean/OpenMBeanAttributeInfo.java b/javax/management/openmbean/OpenMBeanAttributeInfo.java new file mode 100644 index 000000000..1b276fd19 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanAttributeInfo.java @@ -0,0 +1,120 @@ +/* OpenMBeanAttributeInfo.java -- Open typed info about an attribute. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +/** + * Describes an attribute associated with an open management bean. + * This interface includes those methods specified by {@link + * javax.management.MBeanAttributeInfo}, so implementations should + * extend this class. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface OpenMBeanAttributeInfo + extends OpenMBeanParameterInfo +{ + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanAttributeInfo} + * with an equal name and open type, the same default, minimum, + * maximum and legal values and the same access properties + * ({@link #isIs()}, {@link #isReadable()}, {@link #isWritable()}). + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * openType.equals(object.getOpenType()), + * defaultValue.equals(object.getDefaultValue()), + * minValue.equals(object.getMinValue()), + * maxValue.equals(object.getMaxValue()), + * legalValues.equals(object.getLegalValues()), + * is == object.isIs(), + * isRead == object.isReadable(), + * and isWrite == object.isWritable(). + */ + boolean equals(Object obj); + + /** + * Returns the hashcode of the attribute information as the sum of + * the hashcodes of the name, open type, default value, maximum + * value, minimum value, the set of legal values and the access + * properties. + * + * @return the hashcode of the attribute information. + */ + int hashCode(); + + /** + * Returns true if the accessor method of this attribute + * is of the form isXXX. + * + * @return true if the accessor takes the form isXXX. + */ + boolean isIs(); + + /** + * Returns true if value of this attribute can be read. + * + * @return true if the value of the attribute can be read. + */ + boolean isReadable(); + + /** + * Returns true if the value of this attribute can be changed. + * + * @return true if the value of the attribute can be changed. + */ + boolean isWritable(); + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanAttributeInfo) + * along with the name, open type, default, minimum, maximum + * and legal values of the parameter and the access permissions + * ({@link #isIs()}, {@link #isReadable()}, {@link #isWritable()}). + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + String toString(); + +} diff --git a/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java b/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java new file mode 100644 index 000000000..83e043640 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanAttributeInfoSupport.java @@ -0,0 +1,546 @@ +/* OpenMBeanAttributeInfoSupport.java -- Open typed info about an attribute. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.management.MBeanAttributeInfo; + +/** + * Describes an attribute of an open management bean. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class OpenMBeanAttributeInfoSupport + extends MBeanAttributeInfo + implements OpenMBeanAttributeInfo +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -4867215622149721849L; + + /** + * The open type of the attribute. + */ + private OpenType openType; + + /** + * The default value of the attribute (may be null). + */ + private Object defaultValue; + + /** + * The possible legal values of the attribute (may be null). + */ + private Set legalValues; + + /** + * The minimum value of the attribute (may be null). + */ + private Comparable minValue; + + /** + * The maximum value of the attribute (may be null). + */ + private Comparable maxValue; + + /** + * The hash code of this instance. + */ + private transient Integer hashCode; + + /** + * The toString() result of this instance. + */ + private transient String string; + + /** + * Constructs a new {@link OpenMBeanAttributeInfo} using the + * specified name, description, open type and access properties. + * The name, description and open type may not be null + * and the name and description may not be equal to the empty + * string. + * + * @param name the name of the attribute. + * @param desc a description of the attribute. + * @param type the open type of the attribute. + * @param isReadable true if the attribute's value can be read. + * @param isWritable true if the attribute's value can be changed. + * @param isIs true if the attribute uses an accessor of the form isXXX. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + */ + public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type, + boolean isReadable, boolean isWritable, + boolean isIs) + { + super(name, type == null ? null : type.getClassName(), desc, isReadable, + isWritable, isIs); + if (name == null) + throw new IllegalArgumentException("The name may not be null."); + if (desc == null) + throw new IllegalArgumentException("The description may not be null."); + if (type == null) + throw new IllegalArgumentException("The type may not be null."); + if (name.length() == 0) + throw new IllegalArgumentException("The name may not be the empty string."); + if (desc.length() == 0) + throw new IllegalArgumentException("The description may not be the " + + "empty string."); + } + + /** + * Constructs a new {@link OpenMBeanAttributeInfo} using the + * specified name, description, open type and default value. The + * name, description and open type cannot be null and + * the name and description may not be equal to the empty string. + * The default value may be null. If non-null, it must + * be a valid value of the given open type. Default values are not + * applicable to the open types, {@link ArrayType} and {@link + * TabularType}. + * + * @param name the name of the attribute. + * @param desc a description of the attribute. + * @param type the open type of the attribute. + * @param isReadable true if the attribute's value can be read. + * @param isWritable true if the attribute's value can be changed. + * @param isIs true if the attribute uses an accessor of the form isXXX. + * @param defaultValue the default value of the attribute. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + * @throws OpenDataException if defaultValue is non-null + * and is either not a value of the given + * open type or the open type is an instance + * of {@link ArrayType} or {@link TabularType}. + */ + public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type, + boolean isReadable, boolean isWritable, + boolean isIs, Object defaultValue) + throws OpenDataException + { + this(name, desc, type, isReadable, isWritable, isIs, defaultValue, null); + } + + /** + *

    + * Constructs a new {@link OpenMBeanAttributeInfo} using the + * specified name, description, open type, access properties, + * default, maximum and minimum values. The name, description + * and open type cannot be null and the name and + * description may not be equal to the empty string. The + * default, maximum and minimum values may be null. + * The following conditions apply when the attributes mentioned + * are non-null: + *

    + *
      + *
    • The values must be valid values for the given open type.
    • + *
    • Default values are not applicable to the open types, {@link + * ArrayType} and {@link TabularType}.
    • + *
    • The minimum value must be smaller than or equal to the maximum value + * (literally, minValue.compareTo(maxValue) <= 0.
    • + *
    • The minimum value must be smaller than or equal to the default value + * (literally, minValue.compareTo(defaultValue) <= 0.
    • + *
    • The default value must be smaller than or equal to the maximum value + * (literally, defaultValue.compareTo(maxValue) <= 0.
    • + *
    + * + * @param name the name of the attribute. + * @param desc a description of the attribute. + * @param type the open type of the attribute. + * @param isReadable true if the attribute's value can be read. + * @param isWritable true if the attribute's value can be changed. + * @param isIs true if the attribute uses an accessor of the form isXXX. + * @param defaultValue the default value of the attribute, or null. + * @param minimumValue the minimum value of the attribute, or null. + * @param maximumValue the maximum value of the attribute, or null. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + * @throws OpenDataException if any condition in the list above is broken. + */ + public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type, + boolean isReadable, boolean isWritable, + boolean isIs, Object defaultValue, + Comparable minimumValue, + Comparable maximumValue) + throws OpenDataException + { + this(name, desc, type, isReadable, isWritable, isIs); + if (defaultValue != null && !(type.isValue(defaultValue))) + throw new OpenDataException("The default value is not a member of the " + + "open type given."); + if (minimumValue != null && !(type.isValue(minimumValue))) + throw new OpenDataException("The minimum value is not a member of the " + + "open type given."); + if (maximumValue != null && !(type.isValue(maximumValue))) + throw new OpenDataException("The maximum value is not a member of the " + + "open type given."); + if (defaultValue != null && (type instanceof ArrayType || + type instanceof TabularType)) + throw new OpenDataException("Default values are not applicable for " + + "array or tabular types."); + if (minValue != null && maxValue != null + && minValue.compareTo(maxValue) > 0) + throw new OpenDataException("The minimum value is greater than the " + + "maximum."); + if (minValue != null && defaultValue != null + && minValue.compareTo(defaultValue) > 0) + throw new OpenDataException("The minimum value is greater than the " + + "default."); + if (defaultValue != null && maxValue != null + && maxValue.compareTo(defaultValue) < 0) + throw new OpenDataException("The default value is greater than the " + + "maximum."); + + openType = type; + this.defaultValue = defaultValue; + minValue = minimumValue; + maxValue = maximumValue; + } + + /** + *

    + * Constructs a new {@link OpenMBeanAttributeInfo} using the + * specified name, description, open type, access properties, default + * value and set of legal values. The name, description and open type + * cannot be null and the name and description may not be + * equal to the empty string. The default, maximum and minimum values + * may be null. The following conditions apply when the + * attributes mentioned are non-null: + *

    + *
      + *
    • The default value and each of the legal values must be a valid + * value for the given open type.
    • + *
    • Default and legal values are not applicable to the open types, {@link + * ArrayType} and {@link TabularType}.
    • + *
    • The default value is not in the set of legal values.
    • + *
    + *

    + * The legal values are copied from the array into a unmodifiable set, + * so future modifications to the array have no effect. + *

    + * + * @param name the name of the attribute. + * @param desc a description of the attribute. + * @param type the open type of the attribute. + * @param isReadable true if the attribute's value can be read. + * @param isWritable true if the attribute's value can be changed. + * @param isIs true if the attribute uses an accessor of the form isXXX. + * @param defaultValue the default value of the attribute, or null. + * @param legalValues the legal values of the attribute. May be + * null or an empty array. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + * @throws OpenDataException if any condition in the list above is broken. + */ + public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType type, + boolean isReadable, boolean isWritable, + boolean isIs, Object defaultValue, + Object[] legalValues) + throws OpenDataException + { + this(name, desc, type, isReadable, isWritable, isIs); + if (defaultValue != null && !(type.isValue(defaultValue))) + throw new OpenDataException("The default value is not a member of the " + + "open type given."); + if (defaultValue != null && (type instanceof ArrayType || + type instanceof TabularType)) + throw new OpenDataException("Default values are not applicable for " + + "array or tabular types."); + if (legalValues != null && (type instanceof ArrayType || + type instanceof TabularType)) + throw new OpenDataException("Legal values are not applicable for " + + "array or tabular types."); + if (legalValues != null && legalValues.length > 0) + { + Set lv = new HashSet(legalValues.length); + for (int a = 0; a < legalValues.length; ++a) + { + if (legalValues[a] != null && + !(type.isValue(legalValues[a]))) + throw new OpenDataException("The legal value, " + + legalValues[a] + + "is not a member of the " + + "open type given."); + lv.add(legalValues[a]); + } + if (defaultValue != null && !(lv.contains(defaultValue))) + throw new OpenDataException("The default value is not in the set " + + "of legal values."); + this.legalValues = Collections.unmodifiableSet(lv); + } + openType = type; + this.defaultValue = defaultValue; + } + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanAttributeInfo} + * with an equal name and open type and the same default, minimum, + * maximum and legal values and the same access properties. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanAttributeInfo} + * instance, + * name.equals(object.getName()), + * openType.equals(object.getOpenType()), + * isRead == object.isReadable(), + * isWrite == object.isWritable(), + * isIs == object.isIs(), + * defaultValue.equals(object.getDefaultValue()), + * minValue.equals(object.getMinValue()), + * maxValue.equals(object.getMaxValue()), + * and legalValues.equals(object.getLegalValues()). + */ + public boolean equals(Object obj) + { + if (!(obj instanceof OpenMBeanAttributeInfo)) + return false; + OpenMBeanAttributeInfo o = (OpenMBeanAttributeInfo) obj; + return getName().equals(o.getName()) && + openType.equals(o.getOpenType()) && + isReadable() == o.isReadable() && + isWritable() == o.isWritable() && + isIs() == o.isIs() && + (defaultValue == null ? o.getDefaultValue() == null : + defaultValue.equals(o.getDefaultValue())) && + (minValue == null ? o.getMinValue() == null : + minValue.equals(o.getMinValue())) && + (maxValue == null ? o.getMaxValue() == null : + maxValue.equals(o.getMaxValue())) && + (legalValues == null ? o.getLegalValues() == null : + legalValues.equals(o.getLegalValues())); + } + + /** + * Returns the default value of this attribute, or null + * if there is no default value. + * + * @return the default value of the attribute, or null + * if there is no default. + */ + public Object getDefaultValue() + { + return defaultValue; + } + + /** + * Returns a {@link java.util.Set} enumerating the legal values + * of this attribute, or null if no such limited + * set exists for this attribute. + * + * @return a set of legal values, or null if no such + * set exists. + */ + public Set getLegalValues() + { + return legalValues; + } + + /** + * Returns the maximum value of this attribute, or null + * if there is no maximum. + * + * @return the maximum value, or null if none exists. + */ + public Comparable getMaxValue() + { + return maxValue; + } + + /** + * Returns the minimum value of this attribute, or null + * if there is no minimum. + * + * @return the minimum value, or null if none exists. + */ + public Comparable getMinValue() + { + return minValue; + } + + /** + * Returns the open type instance which represents the type of this + * attribute. + * + * @return the open type of this attribute. + */ + public OpenType getOpenType() + { + return openType; + } + + /** + * Returns true if this attribute has a default value + * (i.e. the value is non-null). + * + * @return true if this attribute has a default. + */ + public boolean hasDefaultValue() + { + return defaultValue != null; + } + + /** + *

    + * Returns the hashcode of the attribute information as the sum of + * the hashcodes of the name, open type, default value, maximum + * value, minimum value and the set of legal values. + *

    + *

    + * As instances of this class are immutable, the hash code + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return the hashcode of the attribute information. + */ + public int hashCode() + { + if (hashCode == null) + hashCode = Integer.valueOf(getName().hashCode() + + openType.hashCode() + + Boolean.valueOf(isReadable()).hashCode() + + (2 * + Boolean.valueOf(isWritable()).hashCode()) + + (4 * Boolean.valueOf(isIs()).hashCode()) + + (defaultValue == null ? 0 : + defaultValue.hashCode()) + + (minValue == null ? 0 : + minValue.hashCode()) + + (maxValue == null ? 0 : + maxValue.hashCode()) + + (legalValues == null ? 0 : + legalValues.hashCode())); + return hashCode.intValue(); + } + + /** + * Returns true if there is a set of legal values for this + * attribute (i.e. the value is non-null). + * + * @return true if a set of legal values exists for this + * attribute. + */ + public boolean hasLegalValues() + { + return legalValues != null; + } + + /** + * Returns true if there is a maximum value for this attribute + * (i.e. the value is non-null). + * + * @return true if a maximum value exists for this attribute. + */ + public boolean hasMaxValue() + { + return maxValue != null; + } + + /** + * Returns true if there is a minimum value for this attribute. + * (i.e. the value is non-null). + * + * @return true if a minimum value exists for this attribute. + */ + public boolean hasMinValue() + { + return minValue != null; + } + + /** + * Returns true if the specified object is a valid value for + * this attribute. + * + * @param obj the object to test. + * @return true if obj is a valid value for this + * attribute. + */ + public boolean isValue(Object obj) + { + return openType.isValue(obj); + } + + /** + *

    + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanAttributeInfo) + * along with the name, open type, access properties, default, + * minimum, maximum and legal values of the attribute. + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + if (string == null) + string = getClass().getName() + + "[name=" + getName() + + ",openType=" + openType + + ",isReadable=" + isReadable() + + ",isWritable=" + isWritable() + + ",isIs=" + isIs() + + ",defaultValue=" + defaultValue + + ",minValue=" + minValue + + ",maxValue=" + maxValue + + ",legalValues=" + legalValues + + "]"; + return string; + } + +} diff --git a/javax/management/openmbean/OpenMBeanConstructorInfo.java b/javax/management/openmbean/OpenMBeanConstructorInfo.java new file mode 100644 index 000000000..34cef131f --- /dev/null +++ b/javax/management/openmbean/OpenMBeanConstructorInfo.java @@ -0,0 +1,112 @@ +/* OpenMBeanConstructorInfo.java -- Open typed info about a constructor. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import javax.management.MBeanParameterInfo; + +/** + * Describes a constructor for an open management bean. + * This interface includes those methods specified by {@link + * javax.management.MBeanConstructorInfo}, so implementations should + * extend this class. The {@link #getSignature()} method should + * return an array containing instances of {@link OpenMBeanParameterInfo}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface OpenMBeanConstructorInfo +{ + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanConstructorInfo} + * with an equal name and signature. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * and signature.equals(object.getSignature()). + */ + boolean equals(Object obj); + + /** + * Returns a description of this constructor. + * + * @return a human-readable description. + */ + String getDescription(); + + /** + * Returns the name of this constructor. + * + * @return the name of the constructor. + */ + String getName(); + + /** + * Returns the constructor's signature, in the form of + * information on each parameter. Each parameter is + * described by an instance of {@link OpenMBeanParameterInfo}. + * + * @return an array of {@link OpenMBeanParameterInfo} objects, + * describing the constructor parameters. + */ + MBeanParameterInfo[] getSignature(); + + /** + * Returns the hashcode of the constructor information as the sum of + * the hashcodes of the name and signature (calculated by + * java.util.Arrays.asList(signature).hashCode()). + * + * @return the hashcode of the constructor information. + */ + int hashCode(); + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanConstructorInfo) + * along with the name and signature. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + String toString(); + +} diff --git a/javax/management/openmbean/OpenMBeanConstructorInfoSupport.java b/javax/management/openmbean/OpenMBeanConstructorInfoSupport.java new file mode 100644 index 000000000..9dac01a59 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanConstructorInfoSupport.java @@ -0,0 +1,174 @@ +/* OpenMBeanConstructorInfoSupport.java -- Open typed info about an constructor. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.util.Arrays; + +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanParameterInfo; + +/** + * Describes a constructor for an open management bean. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class OpenMBeanConstructorInfoSupport + extends MBeanConstructorInfo + implements OpenMBeanConstructorInfo +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -4400441579007477003L; + + /** + * The hash code of this instance. + */ + private transient Integer hashCode; + + /** + * The toString() result of this instance. + */ + private transient String string; + + /** + * Constructs a @link{OpenMBeanConstructorInfo} with the specified + * name, description and parameter information. A null + * value for the parameter information is the same as passing in + * an empty array. Neither the name nor the description may be + * null or equal to the empty string. A copy of the parameter array + * is taken, so later changes have no effect. + * + * @param name the name of the constructor. + * @param desc a description of the constructor. + * @param sig the signature of the constructor, as a series + * of {@link MBeanParameterInfo} objects, one for + * each parameter. + * @throws IllegalArgumentException if the name or description is + * either null + * or the empty string. + * @throws ArrayStoreException if the members of the signature array + * are not assignable to + * {@link javax.management.MBeanParameterInfo} + */ + public OpenMBeanConstructorInfoSupport(String name, String desc, + OpenMBeanParameterInfo[] sig) + { + super(name, desc, (MBeanParameterInfo[]) sig); + if (name == null) + throw new IllegalArgumentException("The name may not be null."); + if (desc == null) + throw new IllegalArgumentException("The description may not be null."); + if (name.length() == 0) + throw new IllegalArgumentException("The name may not be the empty string."); + if (desc.length() == 0) + throw new IllegalArgumentException("The description may not be the " + + "empty string."); + } + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanConstructorInfo} + * with an equal name and signature. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * and signature.equals(object.getSignature()). + */ + public boolean equals(Object obj) + { + if (!(obj instanceof OpenMBeanConstructorInfo)) + return false; + OpenMBeanConstructorInfo o = (OpenMBeanConstructorInfo) obj; + return getName().equals(o.getName()) && + getSignature().equals(o.getSignature()); + } + + /** + *

    + * Returns the hashcode of the constructor information as the sum of + * the hashcodes of the name and signature (calculated by + * java.util.Arrays.asList(signature).hashCode()). + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return the hashcode of the constructor information. + */ + public int hashCode() + { + if (hashCode == null) + hashCode = Integer.valueOf(getName().hashCode() + + Arrays.asList(getSignature()).hashCode()); + return hashCode.intValue(); + } + + /** + *

    + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanConstructorInfo) + * along with the name and signature. + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + if (string == null) + string = getClass().getName() + + "[name=" + getName() + + ",signature=" + Arrays.toString(getSignature()) + + "]"; + return string; + } + +} diff --git a/javax/management/openmbean/OpenMBeanInfo.java b/javax/management/openmbean/OpenMBeanInfo.java new file mode 100644 index 000000000..5aa4df451 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanInfo.java @@ -0,0 +1,154 @@ +/* OpenMBeanInfo.java -- Open typed info about a management bean. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; + +/** + * Describes an open management bean. Open management beans are + * management beans where {@link + * javax.management.DynamicMBean#getMBeanInfo()} returns an + * implementation of this interface. This interface includes those + * methods specified by {@link javax.management.MBeanInfo}, + * so implementations should extend this class. Each method + * which returns an array of one of the MBeanXXXInfo + * classes should return an array containing instances + * of the equivalent open version (OpenMBeanXXXInfo). + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface OpenMBeanInfo +{ + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanInfo} + * with the same class name and equal instances of the info classes. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanInfo} + * instance, + * className.equals(object.getClassName()) + * and each info class has an equal in the other object. + */ + boolean equals(Object obj); + + /** + * Returns descriptions of each of the attributes provided by this + * management bean. The elements should be implementations of the + * {@link OpenMBeanAttributeInfo} class. + * + * @return an array of {@link OpenMBeanAttributeInfo} objects, + * representing the attributes emitted by this + * management bean. + */ + MBeanAttributeInfo[] getAttributes(); + + /** + * Returns the class name of the management bean. + * + * @return the bean's class name. + */ + String getClassName(); + + /** + * Returns descriptions of each of the constructors provided by this + * management bean. The elements should be implementations of the + * {@link OpenMBeanConstructorInfo} class. + * + * @return an array of {@link OpenMBeanConstructorInfo} objects, + * representing the constructors emitted by this + * management bean. + */ + MBeanConstructorInfo[] getConstructors(); + + /** + * Returns a description of this operation. + * + * @return a human-readable description. + */ + String getDescription(); + + /** + * Returns descriptions of each of the notifications provided by this + * management bean. The elements should be implementations of the + * {@link OpenMBeanNotificationInfo} class. + * + * @return an array of {@link OpenMBeanNotificationInfo} objects, + * representing the notifications emitted by this + * management bean. + */ + MBeanNotificationInfo[] getNotifications(); + + /** + * Returns descriptions of each of the operations provided by this + * management bean. The elements should be implementations of the + * {@link OpenMBeanOperationInfo} class. + * + * @return an array of {@link OpenMBeanOperationInfo} objects, + * representing the operations emitted by this + * management bean. + */ + MBeanOperationInfo[] getOperations(); + + /** + * Returns the hashcode of the bean information as the sum of the + * hashcodes of the class name and each array (calculated using + * java.util.HashSet(java.util.Arrays.asList(signature)).hashCode()). + * + * @return the hashcode of the bean information. + */ + int hashCode(); + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanInfo) + * along with the class name and textual representations + * of each array. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + String toString(); + +} diff --git a/javax/management/openmbean/OpenMBeanInfoSupport.java b/javax/management/openmbean/OpenMBeanInfoSupport.java new file mode 100644 index 000000000..5f8d55b83 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanInfoSupport.java @@ -0,0 +1,191 @@ +/* OpenMBeanInfoSupport.java -- Open typed info about a bean. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.util.Arrays; +import java.util.HashSet; + +import javax.management.MBeanInfo; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; + +/** + * Describes an open management bean. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class OpenMBeanInfoSupport + extends MBeanInfo + implements OpenMBeanInfo +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 4349395935420511492L; + + /** + * The hash code of this instance. + */ + private transient Integer hashCode; + + /** + * The toString() result of this instance. + */ + private transient String string; + + /** + * Constructs a new {@link OpenMBeanInfo} using the supplied + * class name and description with the given attributes, + * operations, constructors and notifications. The class + * name does not have to actually specify a valid class that + * can be loaded by the MBean server or class loader; it merely + * has to be a syntactically correct class name. Any of the + * arrays may be null; this will be treated as if + * an empty array was supplied. A copy of the arrays is + * taken, so later changes have no effect. + * + * @param name the name of the class this instance describes. + * @param desc a description of the bean. + * @param attribs the attribute descriptions for the bean, + * or null. + * @param cons the constructor descriptions for the bean, + * or null. + * @param ops the operation descriptions for the bean, + * or null. + * @param notifs the notification descriptions for the bean, + * or null. + * @throws ArrayStoreException if a members of an array + * is not assignable to the equivalent + * MBeanXXXInfo class. + */ + public OpenMBeanInfoSupport(String name, String desc, + OpenMBeanAttributeInfo[] attribs, + OpenMBeanConstructorInfo[] cons, + OpenMBeanOperationInfo[] ops, + MBeanNotificationInfo[] notifs) + { + super(name, desc, (MBeanAttributeInfo[]) attribs, + (MBeanConstructorInfo[]) cons, + (MBeanOperationInfo[]) ops, + notifs); + } + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanInfo} + * with the same class name and equal instances of the info classes. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanInfo} + * instance, + * className.equals(object.getClassName()) + * and each info class has an equal in the other object. + */ + public boolean equals(Object obj) + { + if (!(obj instanceof OpenMBeanInfo)) + return false; + OpenMBeanInfo o = (OpenMBeanInfo) obj; + return getClassName().equals(o.getClassName()) && + getAttributes().equals(o.getAttributes()) && + getConstructors().equals(o.getConstructors()) && + getNotifications().equals(o.getNotifications()) && + getOperations().equals(o.getOperations()); + } + + /** + *

    + * Returns the hashcode of the bean information as the sum of the + * hashcodes of the class name and each array (calculated using + * java.util.HashSet(java.util.Arrays.asList(signature)).hashCode()). + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return the hashcode of the bean information. + */ + public int hashCode() + { + if (hashCode == null) + hashCode = + Integer.valueOf(getClassName().hashCode() + + new HashSet(Arrays.asList(getAttributes())).hashCode() + + new HashSet(Arrays.asList(getConstructors())).hashCode() + + new HashSet(Arrays.asList(getNotifications())).hashCode() + + new HashSet(Arrays.asList(getOperations())).hashCode()); + return hashCode.intValue(); + } + + /** + *

    + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanInfo) + * along with the class name and textual representations + * of each array. + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + if (string == null) + string = getClass().getName() + + "[className=" + getClassName() + + ",attributes=" + Arrays.toString(getAttributes()) + + ",constructors=" + Arrays.toString(getConstructors()) + + ",notifications=" + Arrays.toString(getNotifications()) + + ",operations=" + Arrays.toString(getOperations()) + + "]"; + return string; + } + +} diff --git a/javax/management/openmbean/OpenMBeanOperationInfo.java b/javax/management/openmbean/OpenMBeanOperationInfo.java new file mode 100644 index 000000000..8b61329d9 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanOperationInfo.java @@ -0,0 +1,154 @@ +/* OpenMBeanOperationInfo.java -- Open typed info about a operation. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import javax.management.MBeanParameterInfo; + +/** + * Describes a operation for an open management bean. + * This interface includes those methods specified by {@link + * javax.management.MBeanOperationInfo}, so implementations should + * extend this class. The {@link #getSignature()} method should + * return an array containing instances of {@link OpenMBeanParameterInfo}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface OpenMBeanOperationInfo +{ + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanOperationInfo} + * with an equal name, signature, open return type and impact. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * signature.equals(object.getSignature()), + * returnOpenType.equals(object.getReturnOpenType()), + * and impact == object.getImpact(). + */ + boolean equals(Object obj); + + /** + * Returns a description of this operation. + * + * @return a human-readable description. + */ + String getDescription(); + + /** + *

    + * Returns the impact of performing this operation. + * The value is equal to one of the following: + *

    + *
      + *
    1. {@link javax.management.MBeanOperationInfo#INFO} + * — the method just returns + * information (akin to an accessor).
    2. + *
    3. {@link javax.management.MBeanOperationInfo#ACTION} + * the method just alters the state of the bean, without + * returning a value (akin to a mutator).
    4. + *
    5. {@link javax.management.MBeanOperationInfo#ACTION_INFO} + * the method both makes state changes and returns a value.
    6. + *
    7. {@link javax.management.MBeanOperationInfo#UNKNOWN} + * the behaviour of the operation is unknown.
    8. + *
    + * + * @return the impact of performing the operation. + */ + int getImpact(); + + /** + * Returns the name of this operation. + * + * @return the name of the operation. + */ + String getName(); + + /** + * Returns the open type instance which represents the type of the + * return value. + * + * @return the open type of the return value. + */ + OpenType getReturnOpenType(); + + /** + * Returns the return type of the operation, as the class + * name. This should be identical to + * getReturnOpenType.getClassName(). + * + * @return the return type. + */ + String getReturnType(); + + /** + * Returns the operation's signature, in the form of + * information on each parameter. Each parameter is + * described by an instance of {@link OpenMBeanParameterInfo}. + * + * @return an array of {@link OpenMBeanParameterInfo} objects, + * describing the operation parameters. + */ + MBeanParameterInfo[] getSignature(); + + /** + * Returns the hashcode of the operation information as the sum of + * the hashcodes of the name, open return type, impact and signature + * (calculated by + * java.util.Arrays.asList(signature).hashCode()). + * + * @return the hashcode of the operation information. + */ + int hashCode(); + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanOperationInfo) + * along with the name, signature, open return type and impact. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + String toString(); + +} diff --git a/javax/management/openmbean/OpenMBeanOperationInfoSupport.java b/javax/management/openmbean/OpenMBeanOperationInfoSupport.java new file mode 100644 index 000000000..07564897c --- /dev/null +++ b/javax/management/openmbean/OpenMBeanOperationInfoSupport.java @@ -0,0 +1,240 @@ +/* OpenMBeanOperationInfoSupport.java -- Open typed info about an operation. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.util.Arrays; + +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; + +/** + * Describes a operation for an open management bean. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class OpenMBeanOperationInfoSupport + extends MBeanOperationInfo + implements OpenMBeanOperationInfo +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 4996859732565369366L; + + /** + * The open type representing the return value. + */ + private OpenType returnOpenType; + + /** + * The hash code of this instance. + */ + private transient Integer hashCode; + + /** + * The toString() result of this instance. + */ + private transient String string; + + /** + * Constructs a @link{OpenMBeanOperationInfo} with the specified name, + * description, parameter information, open return type and impact. A + * null value for the parameter information is the same + * as passing in an empty array. A copy of the parameter array is + * taken, so later changes have no effect. The name and the + * description may not be equal to the empty string, and neither + * the name, description nor the open return type may be + * null. The value of impact must be + * one of the four valid values + * ({@link javax.management.MBeanOperationInfo#INFO}, + * {@link javax.management.MBeanOperationInfo#ACTION}, + * {@link javax.management.MBeanOperationInfo#ACTION_INFO} and + * {@link javax.management.MBeanOperationInfo#UNKNOWN}). + * + * + * @param name the name of the constructor. + * @param desc a description of the attribute. + * @param sig the signature of the method, as a series + * of {@link MBeanParameterInfo} objects, one for + * each parameter. + * @param type the open return type of the method. + * @param impact the impact of performing the operation. + * @throws IllegalArgumentException if the name, description or + * open return type is null, + * the name or description are equal to + * the empty string, or the impact factor + * is not one of the values enumerated + * above. + * @throws ArrayStoreException if the members of the signature array + * are not assignable to + * {@link javax.management.MBeanParameterInfo} + */ + public OpenMBeanOperationInfoSupport(String name, String desc, + OpenMBeanParameterInfo[] sig, + OpenType type, int impact) + { + super(name, desc, (MBeanParameterInfo[]) sig, + type == null ? null : type.getClassName(), impact); + if (name == null) + throw new IllegalArgumentException("The name may not be null."); + if (desc == null) + throw new IllegalArgumentException("The description may not be null."); + if (type == null) + throw new IllegalArgumentException("The type may not be null."); + if (name.length() == 0) + throw new IllegalArgumentException("The name may not be the empty string."); + if (desc.length() == 0) + throw new IllegalArgumentException("The description may not be the " + + "empty string."); + if (impact != ACTION && impact != INFO && + impact != ACTION_INFO && impact != UNKNOWN) + throw new IllegalArgumentException("The impact factor is an invalid value."); + returnOpenType = type; + } + + /** + * Compares this attribute with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanOperationInfo} + * with an equal name, signature, open return type and impact. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * signature.equals(object.getSignature()), + * returnOpenType.equals(object.getReturnOpenType()), + * and impact == object.getImpact(). + */ + public boolean equals(Object obj) + { + if (!(obj instanceof OpenMBeanOperationInfo)) + return false; + OpenMBeanOperationInfo o = (OpenMBeanOperationInfo) obj; + return getName().equals(o.getName()) && + getSignature().equals(o.getSignature()) && + returnOpenType.equals(o.getReturnOpenType()) && + getImpact() == o.getImpact(); + } + + /** + * Returns the open type instance which represents the type of the + * return value. + * + * @return the open type of the return value. + */ + public OpenType getReturnOpenType() + { + return returnOpenType; + } + + /** + *

    + * Returns the hashcode of the operation information as the sum of + * the hashcodes of the name, open return type, impact and signature + * (calculated by + * java.util.Arrays.asList(signature).hashCode()). + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return the hashcode of the operation information. + */ + public int hashCode() + { + if (hashCode == null) + hashCode = Integer.valueOf(getName().hashCode() + + returnOpenType.hashCode() + + Integer.valueOf(getImpact()).hashCode() + + Arrays.asList(getSignature()).hashCode()); + return hashCode.intValue(); + } + + /** + *

    + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanOperationInfo) + * along with the name, signature, open return type and impact. + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + if (string == null) + { + String impactString; + switch (getImpact()) + { + case INFO: + impactString = "INFO"; + break; + case ACTION: + impactString = "ACTION"; + break; + case ACTION_INFO: + impactString = "ACTION_INFO"; + break; + case UNKNOWN: + impactString = "UNKNOWN"; + break; + default: + impactString = "ERRONEOUS VALUE"; + } + string = getClass().getName() + + "[name=" + getName() + + ",signature=" + Arrays.toString(getSignature()) + + ",returnOpenType=" + returnOpenType + + ",impact=" + impactString + + "]"; + } + return string; + } + +} diff --git a/javax/management/openmbean/OpenMBeanParameterInfo.java b/javax/management/openmbean/OpenMBeanParameterInfo.java new file mode 100644 index 000000000..780e8ba11 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanParameterInfo.java @@ -0,0 +1,190 @@ +/* OpenMBeanParameterInfo.java -- Open typed info about a parameter. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.util.Set; + +/** + * Describes the parameters of a constructor or operation associated + * with an open management bean. This interface includes those methods + * specified by {@link javax.management.MBeanParameterInfo}, so + * implementations should extend this class. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public interface OpenMBeanParameterInfo +{ + + /** + * Compares this parameter with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanParameterInfo} + * with an equal name and open type and the same default, minimum, + * maximum and legal values. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * openType.equals(object.getOpenType()), + * defaultValue.equals(object.getDefaultValue()), + * minValue.equals(object.getMinValue()), + * maxValue.equals(object.getMaxValue()), + * and legalValues.equals(object.getLegalValues()). + */ + boolean equals(Object obj); + + /** + * Returns the default value of this parameter, or null + * if there is no default value. + * + * @return the default value of the parameter, or null + * if there is no default. + */ + Object getDefaultValue(); + + /** + * Returns a description of this parameter. + * + * @return a human-readable description. + */ + String getDescription(); + + /** + * Returns a {@link java.util.Set} enumerating the legal values + * of this parameter, or null if no such limited + * set exists for this parameter. + * + * @return a set of legal values, or null if no such + * set exists. + */ + Set getLegalValues(); + + /** + * Returns the maximum value of this parameter, or null + * if there is no maximum. + * + * @return the maximum value, or null if none exists. + */ + Comparable getMaxValue(); + + /** + * Returns the minimum value of this parameter, or null + * if there is no minimum. + * + * @return the minimum value, or null if none exists. + */ + Comparable getMinValue(); + + /** + * Returns the name of this parameter. + * + * @return the name of the parameter. + */ + String getName(); + + /** + * Returns the open type instance which represents the type of this + * parameter. + * + * @return the open type of this parameter. + */ + OpenType getOpenType(); + + /** + * Returns true if this parameter has a default value. + * + * @return true if this parameter has a default. + */ + boolean hasDefaultValue(); + + /** + * Returns the hashcode of the parameter information as the sum of + * the hashcodes of the name, open type, default value, maximum + * value, minimum value and the set of legal values. + * + * @return the hashcode of the parameter information. + */ + int hashCode(); + + /** + * Returns true if there is a set of legal values for this + * parameter. + * + * @return true if a set of legal values exists for this + * parameter. + */ + boolean hasLegalValues(); + + /** + * Returns true if there is a maximum value for this parameter. + * + * @return true if a maximum value exists for this parameter. + */ + boolean hasMaxValue(); + + /** + * Returns true if there is a minimum value for this parameter. + * + * @return true if a minimum value exists for this parameter. + */ + boolean hasMinValue(); + + /** + * Returns true if the specified object is a valid value for + * this parameter. + * + * @param obj the object to test. + * @return true if obj is a valid value for this + * parameter. + */ + boolean isValue(Object obj); + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanParameterInfo) + * along with the name, open type, default, minimum, maximum + * and legal values of the parameter. + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + String toString(); + +} diff --git a/javax/management/openmbean/OpenMBeanParameterInfoSupport.java b/javax/management/openmbean/OpenMBeanParameterInfoSupport.java new file mode 100644 index 000000000..af3bda6c7 --- /dev/null +++ b/javax/management/openmbean/OpenMBeanParameterInfoSupport.java @@ -0,0 +1,511 @@ +/* OpenMBeanParameterInfoSupport.java -- Open typed info about a parameter. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.management.MBeanParameterInfo; + +/** + * Describes the parameters of a constructor or operation associated + * with an open management bean. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class OpenMBeanParameterInfoSupport + extends MBeanParameterInfo + implements OpenMBeanParameterInfo +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = -7235016873758443122L; + + /** + * The open type of the parameter. + */ + private OpenType openType; + + /** + * The default value of the parameter (may be null). + */ + private Object defaultValue; + + /** + * The possible legal values of the parameter (may be null). + */ + private Set legalValues; + + /** + * The minimum value of the parameter (may be null). + */ + private Comparable minValue; + + /** + * The maximum value of the parameter (may be null). + */ + private Comparable maxValue; + + /** + * The hash code of this instance. + */ + private transient Integer hashCode; + + /** + * The toString() result of this instance. + */ + private transient String string; + + /** + * Constructs a new {@link OpenMBeanParameterInfo} using the specified + * name, description and open type. None of these values may be + * null and the name and description may not be equal + * to the empty string. + * + * @param name the name of the parameter. + * @param desc a description of the parameter. + * @param type the open type of the parameter. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + */ + public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type) + { + super(name, type == null ? null : type.getClassName(), desc); + if (name == null) + throw new IllegalArgumentException("The name may not be null."); + if (desc == null) + throw new IllegalArgumentException("The description may not be null."); + if (type == null) + throw new IllegalArgumentException("The type may not be null."); + if (name.length() == 0) + throw new IllegalArgumentException("The name may not be the empty string."); + if (desc.length() == 0) + throw new IllegalArgumentException("The description may not be the " + + "empty string."); + openType = type; + } + + /** + * Constructs a new {@link OpenMBeanParameterInfo} using the + * specified name, description, open type and default value. The + * name, description and open type cannot be null and + * the name and description may not be equal to the empty string. + * The default value may be null. If non-null, it must + * be a valid value of the given open type. Default values are not + * applicable to the open types, {@link ArrayType} and {@link + * TabularType}. + * + * @param name the name of the parameter. + * @param desc a description of the parameter. + * @param type the open type of the parameter. + * @param defaultValue the default value of the parameter. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + * @throws OpenDataException if defaultValue is non-null + * and is either not a value of the given + * open type or the open type is an instance + * of {@link ArrayType} or {@link TabularType}. + */ + public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type, + Object defaultValue) + throws OpenDataException + { + this(name, desc, type, defaultValue, null); + } + + /** + *

    + * Constructs a new {@link OpenMBeanParameterInfo} using the + * specified name, description, open type, default, maximum and + * minimum values. The name, description and open type cannot be + * null and the name and description may not be equal + * to the empty string. The default, maximum and minimum values may + * be null. The following conditions apply when the + * parameters mentioned are non-null: + *

    + *
      + *
    • The values must be valid values for the given open type.
    • + *
    • Default values are not applicable to the open types, {@link + * ArrayType} and {@link TabularType}.
    • + *
    • The minimum value must be smaller than or equal to the maximum value + * (literally, minValue.compareTo(maxValue) <= 0.
    • + *
    • The minimum value must be smaller than or equal to the default value + * (literally, minValue.compareTo(defaultValue) <= 0.
    • + *
    • The default value must be smaller than or equal to the maximum value + * (literally, defaultValue.compareTo(maxValue) <= 0.
    • + *
    + * + * @param name the name of the parameter. + * @param desc a description of the parameter. + * @param type the open type of the parameter. + * @param defaultValue the default value of the parameter, or null. + * @param minimumValue the minimum value of the parameter, or null. + * @param maximumValue the maximum value of the parameter, or null. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + * @throws OpenDataException if any condition in the list above is broken. + */ + public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type, + Object defaultValue, Comparable minimumValue, + Comparable maximumValue) + throws OpenDataException + { + this(name, desc, type); + if (defaultValue != null && !(type.isValue(defaultValue))) + throw new OpenDataException("The default value is not a member of the " + + "open type given."); + if (minimumValue != null && !(type.isValue(minimumValue))) + throw new OpenDataException("The minimum value is not a member of the " + + "open type given."); + if (maximumValue != null && !(type.isValue(maximumValue))) + throw new OpenDataException("The maximum value is not a member of the " + + "open type given."); + if (defaultValue != null && (type instanceof ArrayType || + type instanceof TabularType)) + throw new OpenDataException("Default values are not applicable for " + + "array or tabular types."); + if (minValue != null && maxValue != null + && minValue.compareTo(maxValue) > 0) + throw new OpenDataException("The minimum value is greater than the " + + "maximum."); + if (minValue != null && defaultValue != null + && minValue.compareTo(defaultValue) > 0) + throw new OpenDataException("The minimum value is greater than the " + + "default."); + if (defaultValue != null && maxValue != null + && maxValue.compareTo(defaultValue) < 0) + throw new OpenDataException("The default value is greater than the " + + "maximum."); + + this.defaultValue = defaultValue; + minValue = minimumValue; + maxValue = maximumValue; + } + + /** + *

    + * Constructs a new {@link OpenMBeanParameterInfo} using the + * specified name, description, open type, default value and + * set of legal values. The name, description and open type cannot be + * null and the name and description may not be equal + * to the empty string. The default, maximum and minimum values may + * be null. The following conditions apply when the + * parameters mentioned are non-null: + *

    + *
      + *
    • The default value and each of the legal values must be a valid + * value for the given open type.
    • + *
    • Default and legal values are not applicable to the open types, {@link + * ArrayType} and {@link TabularType}.
    • + *
    • The default value is not in the set of legal values.
    • + *
    + *

    + * The legal values are copied from the array into a unmodifiable set, + * so future modifications to the array have no effect. + *

    + * + * @param name the name of the parameter. + * @param desc a description of the parameter. + * @param type the open type of the parameter. + * @param defaultValue the default value of the parameter, or null. + * @param legalValues the legal values of the parameter. May be + * null or an empty array. + * @throws IllegalArgumentException if the name, description or + * open type are null + * or the name or description are + * the empty string. + * @throws OpenDataException if any condition in the list above is broken. + */ + public OpenMBeanParameterInfoSupport(String name, String desc, OpenType type, + Object defaultValue, Object[] legalValues) + throws OpenDataException + { + this(name, desc, type); + if (defaultValue != null && !(type.isValue(defaultValue))) + throw new OpenDataException("The default value is not a member of the " + + "open type given."); + if (defaultValue != null && (type instanceof ArrayType || + type instanceof TabularType)) + throw new OpenDataException("Default values are not applicable for " + + "array or tabular types."); + if (legalValues != null && (type instanceof ArrayType || + type instanceof TabularType)) + throw new OpenDataException("Legal values are not applicable for " + + "array or tabular types."); + if (legalValues != null && legalValues.length > 0) + { + Set lv = new HashSet(legalValues.length); + for (int a = 0; a < legalValues.length; ++a) + { + if (legalValues[a] != null && + !(type.isValue(legalValues[a]))) + throw new OpenDataException("The legal value, " + + legalValues[a] + + "is not a member of the " + + "open type given."); + lv.add(legalValues[a]); + } + if (defaultValue != null && !(lv.contains(defaultValue))) + throw new OpenDataException("The default value is not in the set " + + "of legal values."); + this.legalValues = Collections.unmodifiableSet(lv); + } + this.defaultValue = defaultValue; + } + + /** + * Compares this parameter with the supplied object. This returns + * true iff the object is an instance of {@link OpenMBeanParameterInfo} + * with an equal name and open type and the same default, minimum, + * maximum and legal values. + * + * @param obj the object to compare. + * @return true if the object is a {@link OpenMBeanParameterInfo} + * instance, + * name.equals(object.getName()), + * openType.equals(object.getOpenType()), + * defaultValue.equals(object.getDefaultValue()), + * minValue.equals(object.getMinValue()), + * maxValue.equals(object.getMaxValue()), + * and legalValues.equals(object.getLegalValues()). + */ + public boolean equals(Object obj) + { + if (!(obj instanceof OpenMBeanParameterInfo)) + return false; + OpenMBeanParameterInfo o = (OpenMBeanParameterInfo) obj; + return getName().equals(o.getName()) && + openType.equals(o.getOpenType()) && + (defaultValue == null ? o.getDefaultValue() == null : + defaultValue.equals(o.getDefaultValue())) && + (minValue == null ? o.getMinValue() == null : + minValue.equals(o.getMinValue())) && + (maxValue == null ? o.getMaxValue() == null : + maxValue.equals(o.getMaxValue())) && + (legalValues == null ? o.getLegalValues() == null : + legalValues.equals(o.getLegalValues())); + } + + /** + * Returns the default value of this parameter, or null + * if there is no default value. + * + * @return the default value of the parameter, or null + * if there is no default. + */ + public Object getDefaultValue() + { + return defaultValue; + } + + /** + * Returns a {@link java.util.Set} enumerating the legal values + * of this parameter, or null if no such limited + * set exists for this parameter. + * + * @return a set of legal values, or null if no such + * set exists. + */ + public Set getLegalValues() + { + return legalValues; + } + + /** + * Returns the maximum value of this parameter, or null + * if there is no maximum. + * + * @return the maximum value, or null if none exists. + */ + public Comparable getMaxValue() + { + return maxValue; + } + + /** + * Returns the minimum value of this parameter, or null + * if there is no minimum. + * + * @return the minimum value, or null if none exists. + */ + public Comparable getMinValue() + { + return minValue; + } + + /** + * Returns the open type instance which represents the type of this + * parameter. + * + * @return the open type of this parameter. + */ + public OpenType getOpenType() + { + return openType; + } + + /** + * Returns true if this parameter has a default value + * (i.e. the value is non-null). + * + * @return true if this parameter has a default. + */ + public boolean hasDefaultValue() + { + return defaultValue != null; + } + + /** + *

    + * Returns the hashcode of the parameter information as the sum of + * the hashcodes of the name, open type, default value, maximum + * value, minimum value and the set of legal values. + *

    + *

    + * As instances of this class are immutable, the hash code + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return the hashcode of the parameter information. + */ + public int hashCode() + { + if (hashCode == null) + hashCode = Integer.valueOf(getName().hashCode() + + openType.hashCode() + + (defaultValue == null ? 0 : + defaultValue.hashCode()) + + (minValue == null ? 0 : + minValue.hashCode()) + + (maxValue == null ? 0 : + maxValue.hashCode()) + + (legalValues == null ? 0 : + legalValues.hashCode())); + return hashCode.intValue(); + } + + /** + * Returns true if there is a set of legal values for this + * parameter (i.e. the value is non-null). + * + * @return true if a set of legal values exists for this + * parameter. + */ + public boolean hasLegalValues() + { + return legalValues != null; + } + + /** + * Returns true if there is a maximum value for this parameter + * (i.e. the value is non-null). + * + * @return true if a maximum value exists for this parameter. + */ + public boolean hasMaxValue() + { + return maxValue != null; + } + + /** + * Returns true if there is a minimum value for this parameter. + * (i.e. the value is non-null). + * + * @return true if a minimum value exists for this parameter. + */ + public boolean hasMinValue() + { + return minValue != null; + } + + /** + * Returns true if the specified object is a valid value for + * this parameter. + * + * @param obj the object to test. + * @return true if obj is a valid value for this + * parameter. + */ + public boolean isValue(Object obj) + { + return openType.isValue(obj); + } + + /** + *

    + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.OpenMBeanParameterInfo) + * along with the name, open type, default, minimum, maximum + * and legal values of the parameter. + *

    + *

    + * As instances of this class are immutable, the return value + * is computed just once for each instance and reused + * throughout its life. + *

    + * + * @return a @link{java.lang.String} instance representing + * the instance in textual form. + */ + public String toString() + { + if (string == null) + string = getClass().getName() + + "[name=" + getName() + + ",openType=" + openType + + ",defaultValue=" + defaultValue + + ",minValue=" + minValue + + ",maxValue=" + maxValue + + ",legalValues=" + legalValues + + "]"; + return string; + } + +} diff --git a/javax/management/openmbean/SimpleType.java b/javax/management/openmbean/SimpleType.java index 3962909d4..39753f1c6 100644 --- a/javax/management/openmbean/SimpleType.java +++ b/javax/management/openmbean/SimpleType.java @@ -53,7 +53,7 @@ import java.io.ObjectStreamException; * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @since 1.5 */ -public class SimpleType +public final class SimpleType extends OpenType { diff --git a/javax/management/openmbean/TabularData.java b/javax/management/openmbean/TabularData.java index 17c8de981..7e57e0fd8 100644 --- a/javax/management/openmbean/TabularData.java +++ b/javax/management/openmbean/TabularData.java @@ -55,12 +55,14 @@ public interface TabularData /** * Calculates the index the specified {@link CompositeData} value * would have, if it was to be added to this {@link TabularData} - * instance. This method includes a check that the type of - * the given value is the same as the row type of this instance, - * but not a check for existing instances of the given value. - * The value must also not be null. Possible indices - * are returned by the {@link TabularType#getIndexNames()} method - * of this instance's tabular type. + * instance. This method includes a check that the type of the + * given value is the same as the row type of this instance, but not + * a check for existing instances of the given value. The value + * must also not be null. Possible indices are + * returned by the {@link TabularType#getIndexNames()} method of + * this instance's tabular type. The returned indices are the + * values of the fields in the supplied {@link CompositeData} + * instance that match the names given in the {@link TabularType}. * * @param val the {@link CompositeData} value whose index should * be calculated. @@ -106,7 +108,7 @@ public interface TabularData * Compares the specified object with this object for equality. * The object is judged equivalent if it is non-null, and also * an instance of {@link TabularData} with the same row type, - * and index to value mappings. The two compared instances may + * and {@link CompositeData} values. The two compared instances may * be equivalent even if they represent different implementations * of {@link TabularData}. * @@ -123,9 +125,9 @@ public interface TabularData * @return the matching {@link CompositeData} value, or * null if one does not exist. * @throws NullPointerException if the key is null. - * @throws InvalidOpenTypeException if the key does not match - * the {@link TabularType} of this - * instance. + * @throws InvalidKeyException if the key does not match + * the {@link TabularType} of this + * instance. */ CompositeData get(Object[] key); @@ -138,14 +140,12 @@ public interface TabularData TabularType getTabularType(); /** - * Returns the hash code of the composite data type. - * This is computed as the sum of the hash codes of the - * each index and its value, together with the hash - * code of the tabular type. These are the same elements - * of the type that are compared as part of the - * {@link #equals(java.lang.Object)} method, thus ensuring - * that the hashcode is compatible with the equality - * test. + * Returns the hash code of the composite data type. This is + * computed as the sum of the hash codes of each value, together + * with the hash code of the tabular type. These are the same + * elements of the type that are compared as part of the {@link + * #equals(java.lang.Object)} method, thus ensuring that the + * hashcode is compatible with the equality test. * * @return the hash code of this instance. */ @@ -196,15 +196,16 @@ public interface TabularData * values in the array, as well as from the existing values * in the table. The operation should be atomic; if one * value can not be added, then none of the values should - * be. + * be. If the array is null or empty, the + * method simply returns. * * @param vals the {@link CompositeData} values to add. - * @throws NullPointerException if val is + * @throws NullPointerException if a value from the array is * null. - * @throws InvalidOpenTypeException if the type of the + * @throws InvalidOpenTypeException if the type of a * given value does not * match the row type. - * @throws KeyAlreadyExistsException if the value has the + * @throws KeyAlreadyExistsException if a value has the * same calculated index * as an existing value or * of one of the other diff --git a/javax/management/openmbean/TabularDataSupport.java b/javax/management/openmbean/TabularDataSupport.java new file mode 100644 index 000000000..9dc8a0e97 --- /dev/null +++ b/javax/management/openmbean/TabularDataSupport.java @@ -0,0 +1,652 @@ +/* TabularDataSupport.java -- Tables of composite data structures. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.management.openmbean; + +import java.io.Serializable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Provides an implementation of the {@link TabularData} + * interface using a {@link java.util.HashMap}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class TabularDataSupport + implements TabularData, Serializable, Cloneable, Map +{ + + /** + * Compatible with JDK 1.5 + */ + private static final long serialVersionUID = 5720150593236309827L; + + /** + * Mapping of rows to column values. + * + * @serial the map of rows to column values. + */ + private Map dataMap; + + /** + * The tabular type which represents this tabular data instance. + * + * @serial the type information for this instance. + */ + private TabularType tabularType; + + /** + * Constructs a new empty {@link TabularDataSupport} with the + * specified type. The type may not be null. This constructor + * simply calls the other, with the default initial capacity of + * 101 and default load factor of 0.75. + * + * @param type the tabular type of this tabular data instance. + * @throws IllegalArgumentException if type is + * null. + */ + public TabularDataSupport(TabularType type) + { + this(type, 101, 0.75f); + } + + /** + * Constructs a new empty {@link TabularDataSupport} with the + * specified type and the supplied initial capacity and load factor + * being used for the underlying {@link java.util.HashMap}. The + * type may not be null and the initial capacity and load factor + * must be positive. + * + * @param type the tabular type of this tabular data instance. + * @param cap the initial capacity of the underlying map. + * @param lf the load factor of the underlying map. + * @throws IllegalArgumentException if type is + * null, or + * cap or + * lf are + * negative. + */ + public TabularDataSupport(TabularType type, int cap, float lf) + { + if (type == null) + throw new IllegalArgumentException("The type may not be null."); + tabularType = type; + dataMap = new HashMap(cap, lf); + } + + /** + * Calculates the index the specified {@link CompositeData} value + * would have, if it was to be added to this {@link TabularData} + * instance. This method includes a check that the type of the + * given value is the same as the row type of this instance, but not + * a check for existing instances of the given value. The value + * must also not be null. Possible indices are + * selected by the {@link TabularType#getIndexNames()} method of + * this instance's tabular type. The returned indices are the + * values of the fields in the supplied {@link CompositeData} + * instance that match the names given in the {@link TabularType}. + * + * @param val the {@link CompositeData} value whose index should + * be calculated. + * @return the index the value would take on, if it were to be added. + * @throws NullPointerException if the value is null. + * @throws InvalidOpenTypeException if the value does not match the + * row type of this instance. + */ + public Object[] calculateIndex(CompositeData val) + { + if (!(val.getCompositeType().equals(tabularType.getRowType()))) + throw new InvalidOpenTypeException("The type of the given value " + + "does not match the row type " + + "of this instance."); + List indexNames = tabularType.getIndexNames(); + List matchingIndicies = new ArrayList(indexNames.size()); + Iterator it = indexNames.iterator(); + while (it.hasNext()) + { + String name = (String) it.next(); + matchingIndicies.add(val.get(name)); + } + return matchingIndicies.toArray(); + } + + /** + * Removes all {@link CompositeData} values from the table. + */ + public void clear() + { + dataMap.clear(); + } + + /** + * Returns a shallow clone of the information, as obtained by the + * {@link Object} implementation of {@link Object#clone()}. The map + * is also cloned, but it still references the same objects. + * + * @return a shallow clone of this {@link TabularDataSupport}. + */ + public Object clone() + { + TabularDataSupport clone = null; + try + { + clone = (TabularDataSupport) super.clone(); + clone.setMap((HashMap) ((HashMap) dataMap).clone()); + } + catch (CloneNotSupportedException e) + { + /* This won't happen as we implement Cloneable */ + } + return clone; + } + + /** + * Returns true iff this instance of the {@link TabularData} class + * contains a {@link CompositeData} value at the specified index. + * The method returns false if the given key can + * not be cast to an {@link java.lang.Object} array; otherwise + * it returns the result of {@link #containsKey(java.lang.Object[])}. + * + * + * @param key the key to test for. + * @return true if the key maps to a {@link CompositeData} value. + */ + public boolean containsKey(Object key) + { + if (key instanceof Object[]) + return containsKey((Object[]) key); + else + return false; + } + + /** + * Returns true iff this instance of the {@link TabularData} class + * contains a {@link CompositeData} value at the specified index. + * In any other circumstance, including if the given key + * is null or of the incorrect type, according to + * the {@link TabularType} of this instance, this method returns + * false. + * + * @param key the key to test for. + * @return true if the key maps to a {@link CompositeData} value. + */ + public boolean containsKey(Object[] key) + { + if (key == null) + return false; + if (!(isKeyValid(key))) + return false; + return dataMap.containsKey(key); + } + + /** + * Returns true iff this instance of the {@link TabularData} class + * contains the specified {@link CompositeData} value. If the given + * value is not an instance of {@link CompositeData}, this method + * simply returns false. + * + * @param val the value to test for. + * @return true if the value exists. + */ + public boolean containsValue(Object val) + { + if (val instanceof CompositeData) + return containsValue((CompositeData) val); + else + return false; + } + + /** + * Returns true iff this instance of the {@link TabularData} class + * contains the specified {@link CompositeData} value. + * In any other circumstance, including if the given value + * is null or of the incorrect type, according to + * the {@link TabularType} of this instance, this method returns + * false. + * + * @param val the value to test for. + * @return true if the value exists. + */ + public boolean containsValue(CompositeData val) + { + if (val == null) + return false; + if (!(val.getCompositeType().equals(tabularType.getRowType()))) + return false; + return dataMap.containsValue(val); + } + + /** + *

    + * Returns a set view of the mappings in this Map. Each element in the + * set is a Map.Entry. The set is backed by the map, so that changes in + * one show up in the other. Modifications made while an iterator is + * in progress cause undefined behavior. If the set supports removal, + * these methods remove the underlying mapping from the map: + * Iterator.remove, Set.remove, + * removeAll, retainAll, and clear. + * Element addition, via add or addAll, is + * not supported via this set. + *

    + *

    + * Note: using the + * {@link java.util.Map.Entry#setValue(Object) will cause corruption of + * the index to row mappings. + *

    + * + * @return the set view of all mapping entries + * @see java.util.Map.Entry + */ + public Set entrySet() + { + return dataMap.entrySet(); + } + + /** + * Compares the specified object with this object for equality. + * The object is judged equivalent if it is non-null, and also + * an instance of {@link TabularData} with the same row type, + * and {@link CompositeData} values. The two compared instances may + * be equivalent even if they represent different implementations + * of {@link TabularData}. + * + * @param obj the object to compare for equality. + * @return true if obj is equal to this. + */ + public boolean equals(Object obj) + { + if (!(obj instanceof TabularData)) + return false; + TabularData data = (TabularData) obj; + return tabularType.equals(data.getTabularType()) && + dataMap.values().equals(data.values()); + } + + /** + * Retrieves the value for the specified key by simply + * calling get((Object[]) key). + * + * @param key the key whose value should be returned. + * @return the matching {@link CompositeData} value, or + * null if one does not exist. + * @throws NullPointerException if the key is null. + * @throws ClassCastException if the key is not an instance + * of Object[]. + * @throws InvalidKeyException if the key does not match + * the {@link TabularType} of this + * instance. + */ + public Object get(Object key) + { + return get((Object[]) key); + } + + /** + * Retrieves the {@link CompositeData} value for the specified + * key, or null if no such mapping exists. + * + * @param key the key whose value should be returned. + * @return the matching {@link CompositeData} value, or + * null if one does not exist. + * @throws NullPointerException if the key is null. + * @throws InvalidKeyException if the key does not match + * the {@link TabularType} of this + * instance. + */ + public CompositeData get(Object[] key) + { + if (!(isKeyValid(key))) + throw new InvalidKeyException("The key does not match the " + + "tabular type of this instance."); + return (CompositeData) dataMap.get(key); + } + + /** + * Returns the tabular type which corresponds to this instance + * of {@link TabularData}. + * + * @return the tabular type for this instance. + */ + public TabularType getTabularType() + { + return tabularType; + } + + /** + * Returns the hash code of the composite data type. This is + * computed as the sum of the hash codes of each value, together + * with the hash code of the tabular type. These are the same + * elements of the type that are compared as part of the {@link + * #equals(java.lang.Object)} method, thus ensuring that the + * hashcode is compatible with the equality test. + * + * @return the hash code of this instance. + */ + public int hashCode() + { + return tabularType.hashCode() + dataMap.values().hashCode(); + } + + /** + * Returns true if this {@link TabularData} instance + * contains no {@link CompositeData} values. + * + * @return true if the instance is devoid of rows. + */ + public boolean isEmpty() + { + return dataMap.isEmpty(); + } + + /** + * Returns true if the given key is valid for the + * @link{TabularType} of this instance. + * + * @return true if the key is valid. + * @throws NullPointerException if key + * is null. + */ + private boolean isKeyValid(Object[] key) + { + Iterator it = tabularType.getIndexNames().iterator(); + CompositeType rowType = tabularType.getRowType(); + for (int a = 0; it.hasNext(); ++a) + { + OpenType type = rowType.getType((String) it.next()); + if (!(type.isValue(key[a]))) + return false; + } + return true; + } + + /** + * Returns a set view of the keys in this Map. The set is backed by the + * map, so that changes in one show up in the other. Modifications made + * while an iterator is in progress cause undefined behavior. If the set + * supports removal, these methods remove the underlying mapping from + * the map: Iterator.remove, Set.remove, + * removeAll, retainAll, and clear. + * Element addition, via add or addAll, is + * not supported via this set. + * + * @return the set view of all keys + */ + public Set keySet() + { + return dataMap.keySet(); + } + + /** + * Adds the specified {@link CompositeData} value to the + * table. The value must be non-null, of the same type + * as the row type of this instance, and must not have + * the same index as an existing value. The index is + * calculated using the index names of the + * {@link TabularType} for this instance. + * + * @param val the {@link CompositeData} value to add. + * @throws NullPointerException if val is + * null. + * @throws InvalidOpenTypeException if the type of the + * given value does not + * match the row type. + * @throws KeyAlreadyExistsException if the value has the + * same calculated index + * as an existing value. + */ + public void put(CompositeData val) + { + Object[] key = calculateIndex(val); + if (dataMap.containsKey(key)) + throw new KeyAlreadyExistsException("A value with this index " + + "already exists."); + dataMap.put(key, val); + } + + /** + * Adds the specified {@link CompositeData} value to the + * table, ignoring the supplied key, by simply calling + * put((CompositeData) val). + * + * @param key ignored. + * @param val the {@link CompositeData} value to add. + * @return the {@link CompositeData} value. + * @throws NullPointerException if val is + * null. + * @throws InvalidOpenTypeException if the type of the + * given value does not + * match the row type. + * @throws KeyAlreadyExistsException if the value has the + * same calculated index + * as an existing value. + */ + public Object put(Object key, Object val) + { + put((CompositeData) val); + return val; + } + + /** + * Adds each of the specified {@link CompositeData} values + * to the table. Each element of the array must meet the + * conditions given for the {@link #put(CompositeData)} + * method. In addition, the index of each value in the + * array must be distinct from the index of the other + * values in the array, as well as from the existing values + * in the table. The operation should be atomic; if one + * value can not be added, then none of the values should + * be. If the array is null or empty, the + * method simply returns. + * + * @param vals the {@link CompositeData} values to add. + * @throws NullPointerException if a value from the array is + * null. + * @throws InvalidOpenTypeException if the type of a + * given value does not + * match the row type. + * @throws KeyAlreadyExistsException if a value has the + * same calculated index + * as an existing value or + * of one of the other + * specified values. + */ + public void putAll(CompositeData[] vals) + { + if (vals == null || vals.length == 0) + return; + Map mapToAdd = new HashMap(vals.length); + for (int a = 0; a < vals.length; ++a) + { + Object[] key = calculateIndex(vals[a]); + if (dataMap.containsKey(key)) + throw new KeyAlreadyExistsException("Element " + a + ": A " + + "value with this index " + + "already exists."); + mapToAdd.put(key, vals[a]); + } + dataMap.putAll(mapToAdd); + } + + /** + * Converts each value from the specified map to a member of an + * array of {@link CompositeData} values and adds them using {@link + * #put(CompositeData[])}, if possible. As in {@link + * #put(Object,Object)}, the keys are simply ignored. This method + * is useful for adding the {@link CompositeData} values from a + * different {@link TabularData} instance, which uses the same + * {@link TabularType} but a different selection of index names, to + * this one. If the map is null or empty, the method + * simply returns. + * + * @param m the map to add. Only the values are used and must + * all be instances of {@link CompositeData}. + * @throws NullPointerException if a value from the map is + * null. + * @throws ClassCastException if a value from the map is not + * an instance of {@link CompositeData}. + * @throws InvalidOpenTypeException if the type of the + * given value does not + * match the row type. + * @throws KeyAlreadyExistsException if the value has the + * same calculated index + * as an existing value or + * of one of the other + * specified values. + */ + public void putAll(Map m) + { + if (m == null || m.size() == 0) + return; + Collection vals = m.values(); + CompositeData[] data = new CompositeData[vals.size()]; + Iterator it = vals.iterator(); + for (int a = 0; it.hasNext(); ++a) + { + data[a] = (CompositeData) it.next(); + } + putAll(data); + } + + /** + * Removes the value for the specified key by simply + * calling remove((Object[]) key). + * + * @param key the key whose value should be removed. + * @return the removed value, or null if + * there is no value for the given key. + * @throws NullPointerException if the key is null. + * @throws ClassCastException if the key is not an instance + * of Object[]. + * @throws InvalidOpenTypeException if the key does not match + * the {@link TabularType} of this + * instance. + */ + public Object remove(Object key) + { + return remove((Object[]) key); + } + + /** + * Removes the {@link CompositeData} value located at the + * specified index. null is returned if the + * value does not exist. Otherwise, the removed value is + * returned. + * + * @param key the key of the value to remove. + * @return the removed value, or null if + * there is no value for the given key. + * @throws NullPointerException if the key is null. + * @throws InvalidOpenTypeException if the key does not match + * the {@link TabularType} of this + * instance. + */ + public CompositeData remove(Object[] key) + { + if (!(isKeyValid(key))) + throw new InvalidKeyException("The key does not match the " + + "tabular type of this instance."); + return (CompositeData) dataMap.remove(key); + } + + /** + * Package-private method to set the internal {@link java.util.Map} + * instance (used in cloning). + * + * @param map the new map used. + */ + void setMap(Map map) + { + dataMap = map; + } + + /** + * Returns the number of {@link CompositeData} values or rows + * in the table. + * + * @return the number of rows in the table. + */ + public int size() + { + return dataMap.size(); + } + + /** + * Returns a textual representation of this instance. This + * is constructed using the class name + * (javax.management.openmbean.TabularDataSupport) + * and the result of calling toString() on the + * tabular type and underlying hash map instance. + * + * @return a {@link java.lang.String} representation of the + * object. + */ + public String toString() + { + return getClass().getName() + + "[tabularType=" + tabularType + + ",dataMap=" + dataMap + + "]"; + } + + /** + * Returns a collection (or bag) view of the values in this Map. The + * collection is backed by the map, so that changes in one show up in + * the other. Modifications made while an iterator is in progress cause + * undefined behavior. If the collection supports removal, these methods + * remove the underlying mapping from the map: Iterator.remove, + * Collection.remove, removeAll, + * retainAll, and clear. Element addition, via + * add or addAll, is not supported via this + * collection. + * + * @return the collection view of all values + */ + public Collection values() + { + return dataMap.values(); + } + +} + diff --git a/javax/naming/Name.java b/javax/naming/Name.java index 18655c339..687ebd6fb 100644 --- a/javax/naming/Name.java +++ b/javax/naming/Name.java @@ -62,6 +62,8 @@ import java.util.Enumeration; */ public interface Name extends Cloneable, Serializable, Comparable { + // This class is implemented as gnu.javax.naming.ictxImpl.trans.GnuName + long serialVersionUID = -3617482732056931635L; /** @@ -94,22 +96,27 @@ public interface Name extends Cloneable, Serializable, Comparable * Returns the components till the given index as a Name. * The returned Name can be modified without changing the * original. + * + * @param posn the ending position, exclusive * * @exception ArrayIndexOutOfBoundsException if the given index is smaller * then zero or greater then or equal to size(). */ - Name getPrefix(int i); + Name getPrefix(int posn); /** * Returns the components from the given index till the end as a * Name. * The returned Name can be modified without changing the * original. + * + * @param posn the starting position, inclusive. If it is equal to the size + * of the name, the empty name is returned. * * @exception ArrayIndexOutOfBoundsException if the given index is smaller * then zero or greater then or equal to size(). */ - Name getSuffix(int i); + Name getSuffix(int posn); /** * Adds the given String component to the end of this @@ -145,7 +152,8 @@ public interface Name extends Cloneable, Serializable, Comparable /** * Inserts all the components of the given Name to this - * Name at the given index. The method modifies the current + * Name at the given index. Components after this index + * (if any) are shifted up. The method modifies the current * Name and then returns it. * * @exception ArrayIndexOutOfBoundsException if the given index is smaller diff --git a/javax/naming/spi/NamingManager.java b/javax/naming/spi/NamingManager.java index 04c119edc..3dfba0f66 100644 --- a/javax/naming/spi/NamingManager.java +++ b/javax/naming/spi/NamingManager.java @@ -190,9 +190,12 @@ public class NamingManager String scheme, Hashtable environment) throws NamingException { - // Specified as the default in the docs. Unclear if this is - // right for us. - String defaultPrefix = "com.sun.jndi.url"; + // Doc specifies com.sun.jndi.url as the final destination, but we cannot + // put our classes into such namespace. + String defaultPrefix = "gnu.javax.naming.jndi.url"; + + // The final default location, as specified in the documentation. + String finalPrefix = "com.sun.jndi.url"; StringBuffer allPrefixes = new StringBuffer(); @@ -215,6 +218,8 @@ public class NamingManager if (allPrefixes.length() > 0) allPrefixes.append(':'); allPrefixes.append(defaultPrefix); + allPrefixes.append(':'); + allPrefixes.append(finalPrefix); scheme = scheme + "." + scheme + "URLContextFactory"; @@ -228,12 +233,21 @@ public class NamingManager Class factoryClass = forName(tryClass); if (factoryClass != null) { - ObjectFactory factory = (ObjectFactory) factoryClass.newInstance(); - Object obj = factory.getObjectInstance(refInfo, name, nameCtx, - environment); - Context ctx = (Context) obj; - if (ctx != null) - return ctx; + Object obj; + try + { + ObjectFactory factory = (ObjectFactory) factoryClass.newInstance(); + obj = factory.getObjectInstance(refInfo, name, nameCtx, + environment); + Context ctx = (Context) obj; + if (ctx != null) + return ctx; + } + catch (RuntimeException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } catch (ClassNotFoundException _1) diff --git a/javax/swing/JMenu.java b/javax/swing/JMenu.java index 0840509f9..68f31e335 100644 --- a/javax/swing/JMenu.java +++ b/javax/swing/JMenu.java @@ -40,7 +40,6 @@ package javax.swing; import java.awt.Component; import java.awt.Point; -import java.awt.PopupMenu; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -99,7 +98,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement { super(); setOpaque(false); - setDelay(200); } /** @@ -113,7 +111,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement popupMenu = new JPopupMenu(); popupMenu.setInvoker(this); setOpaque(false); - setDelay(200); } /** @@ -129,7 +126,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement popupMenu = new JPopupMenu(); popupMenu.setInvoker(this); setOpaque(false); - setDelay(200); } /** @@ -143,7 +139,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement { // FIXME: tearoff not implemented this(text); - setDelay(200); } /** @@ -341,63 +336,6 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement return super.isSelected(); } - /** - * A helper method to handle setSelected calls from both mouse events and - * direct calls to setSelected. Direct calls shouldn't expand the popup - * menu and should select the JMenu even if it is disabled. Mouse events - * only select the JMenu if it is enabled and should expand the popup menu - * associated with this JMenu. - * @param selected whether or not the JMenu was selected - * @param menuEnabled whether or not selecting the menu is "enabled". This - * is always true for direct calls, and is set to isEnabled() for mouse - * based calls. - * @param showMenu whether or not to show the popup menu - */ - private void setSelectedHelper(boolean selected, boolean menuEnabled, boolean showMenu) - { - // If menu is selected and enabled, activates the menu and - // displays associated popup. - if (selected && menuEnabled) - { - super.setArmed(true); - super.setSelected(true); - - // FIXME: The popup menu should be shown on the screen after certain - // number of seconds pass. The 'delay' property of this menu indicates - // this amount of seconds. 'delay' property is 0 by default. - if (isShowing()) - { - fireMenuSelected(); - - int x = 0; - int y = 0; - if (showMenu) - if (menuLocation == null) - { - // Calculate correct position of the popup. Note that location of the popup - // passed to show() should be relative to the popup's invoker - if (isTopLevelMenu()) - y = this.getHeight(); - else - x = this.getWidth(); - getPopupMenu().show(this, x, y); - } - else - { - getPopupMenu().show(this, menuLocation.x, menuLocation.y); - } - } - } - - else - { - super.setSelected(false); - super.setArmed(false); - fireMenuDeselected(); - getPopupMenu().setVisible(false); - } - } - /** * Changes this menu selected state if selected is true and false otherwise * This method fires menuEvents to menu's registered listeners. @@ -406,7 +344,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement */ public void setSelected(boolean selected) { - setSelectedHelper(selected, true, false); + ButtonModel m = getModel(); + if (selected != m.isSelected()) + m.setSelected(selected); } /** @@ -427,8 +367,17 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement */ public void setPopupMenuVisible(boolean popup) { - if (getModel().isEnabled()) - getPopupMenu().setVisible(popup); + if (popup != isPopupMenuVisible() && (isEnabled() || ! popup)) + { + if (popup && isShowing()) + { + // Set location as determined by getPopupLocation(). + Point loc = getPopupMenuOrigin(); + getPopupMenu().show(this, loc.x, loc.y); + } + else + getPopupMenu().setVisible(false); + } } /** @@ -438,12 +387,22 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement */ protected Point getPopupMenuOrigin() { + Point point; + // if menu in the menu bar if (isTopLevelMenu()) - return new Point(0, this.getHeight()); + point = new Point(0, this.getHeight()); - // if submenu - return new Point(this.getWidth(), 0); + // if submenu + else + { + int xOffset = UIManager.getInt("Menu.submenuPopupOffsetX"); + int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY"); + int x = getWidth() + xOffset; + int y = yOffset; + point = new Point(x, y); + } + return point; } /** @@ -748,7 +707,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement { // if this menu selection is true, then activate this menu and // display popup associated with this menu - setSelectedHelper(changed, isEnabled(), true); + setSelected(changed); } /** diff --git a/javax/swing/JPopupMenu.java b/javax/swing/JPopupMenu.java index d46015afd..2e59d4767 100644 --- a/javax/swing/JPopupMenu.java +++ b/javax/swing/JPopupMenu.java @@ -820,7 +820,14 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement */ public void menuSelectionChanged(boolean changed) { - if (! changed) + if (invoker instanceof JMenu) + { + // We need to special case this since the JMenu calculates the + // position etc of the popup. + JMenu menu = (JMenu) invoker; + menu.setPopupMenuVisible(changed); + } + else if (! changed) setVisible(false); } diff --git a/javax/swing/JTree.java b/javax/swing/JTree.java index aaf326b69..32acca643 100644 --- a/javax/swing/JTree.java +++ b/javax/swing/JTree.java @@ -1509,8 +1509,7 @@ public class JTree extends JComponent implements Scrollable, Accessible public JTree(TreeModel model) { setRootVisible(true); - setSelectionModel(new EmptySelectionModel()); - selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + setSelectionModel( new DefaultTreeSelectionModel() ); // The root node appears expanded by default. nodeStates = new Hashtable(); @@ -2050,14 +2049,16 @@ public class JTree extends JComponent implements Scrollable, Accessible if (selectionModel == model) return; + if( model == null ) + model = EmptySelectionModel.sharedInstance(); + if (selectionModel != null) selectionModel.removeTreeSelectionListener(selectionRedirector); TreeSelectionModel oldValue = selectionModel; selectionModel = model; - if (selectionModel != null) - selectionModel.addTreeSelectionListener(selectionRedirector); + selectionModel.addTreeSelectionListener(selectionRedirector); firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model); revalidate(); diff --git a/javax/swing/Popup.java b/javax/swing/Popup.java index 308cd662d..5074d6418 100644 --- a/javax/swing/Popup.java +++ b/javax/swing/Popup.java @@ -284,7 +284,7 @@ public class Popup panel.setSize(contents.getSize()); Point layeredPaneLoc = layeredPane.getLocationOnScreen(); panel.setLocation(x - layeredPaneLoc.x, y - layeredPaneLoc.y); - layeredPane.add(panel, JLayeredPane.POPUP_LAYER); + layeredPane.add(panel, JLayeredPane.POPUP_LAYER, 0); panel.repaint(); } diff --git a/javax/swing/SwingUtilities.java b/javax/swing/SwingUtilities.java index 996cc2efc..2823367ce 100644 --- a/javax/swing/SwingUtilities.java +++ b/javax/swing/SwingUtilities.java @@ -61,6 +61,8 @@ import javax.accessibility.Accessible; import javax.accessibility.AccessibleStateSet; import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.InputMapUIResource; +import javax.swing.plaf.basic.BasicHTML; +import javax.swing.text.View; /** * A number of static utility functions which are @@ -751,12 +753,12 @@ public class SwingUtilities horizontalAlignment = RIGHT; } - return layoutCompoundLabel(fm, text, icon, - verticalAlignment, - horizontalAlignment, - verticalTextPosition, - horizontalTextPosition, - viewR, iconR, textR, textIconGap); + return layoutCompoundLabelImpl(c, fm, text, icon, + verticalAlignment, + horizontalAlignment, + verticalTextPosition, + horizontalTextPosition, + viewR, iconR, textR, textIconGap); } /** @@ -829,6 +831,82 @@ public class SwingUtilities Rectangle textR, int textIconGap) { + return layoutCompoundLabelImpl(null, fm, text, icon, verticalAlignment, + horizontalAlignment, verticalTextPosition, + horizontalTextPosition, viewR, iconR, textR, + textIconGap); + } + + /** + *

    Layout a "compound label" consisting of a text string and an icon + * which is to be placed near the rendered text. Once the text and icon + * are laid out, the text rectangle and icon rectangle parameters are + * altered to store the calculated positions.

    + * + *

    The size of the text is calculated from the provided font metrics + * object. This object should be the metrics of the font you intend to + * paint the label with.

    + * + *

    The position values control where the text is placed relative to + * the icon. The horizontal position value should be one of the constants + * LEFT, RIGHT or CENTER. The + * vertical position value should be one fo the constants + * TOP, BOTTOM or CENTER.

    + * + *

    The text-icon gap value controls the number of pixels between the + * icon and the text.

    + * + *

    The alignment values control where the text and icon are placed, as + * a combined unit, within the view rectangle. The horizontal alignment + * value should be one of the constants LEFT, RIGHT or + * CENTER. The vertical alignment valus should be one of the + * constants TOP, BOTTOM or + * CENTER.

    + * + *

    If the text and icon are equal to or larger than the view + * rectangle, the horizontal and vertical alignment values have no + * affect.

    + * + *

    Note that this method does not know how to deal with + * horizontal alignments or positions given as LEADING or + * TRAILING values. Use the other overloaded variant of this + * method if you wish to use such values. + * + * @param fm The font metrics used to measure the text + * @param text The text to place in the compound label + * @param icon The icon to place next to the text + * @param verticalAlignment The vertical alignment of the label relative + * to its component + * @param horizontalAlignment The horizontal alignment of the label + * relative to its component + * @param verticalTextPosition The vertical position of the label's text + * relative to its icon + * @param horizontalTextPosition The horizontal position of the label's + * text relative to its icon + * @param viewR The view rectangle, specifying the area which layout is + * constrained to + * @param iconR A rectangle which is modified to hold the laid-out + * position of the icon + * @param textR A rectangle which is modified to hold the laid-out + * position of the text + * @param textIconGap The distance between text and icon + * + * @return The string of characters, possibly truncated with an elipsis, + * which is laid out in this label + */ + private static String layoutCompoundLabelImpl(JComponent c, + FontMetrics fm, + String text, + Icon icon, + int verticalAlignment, + int horizontalAlignment, + int verticalTextPosition, + int horizontalTextPosition, + Rectangle viewR, + Rectangle iconR, + Rectangle textR, + int textIconGap) + { // Work out basic height and width. @@ -851,13 +929,23 @@ public class SwingUtilities } else { - int fromIndex = 0; - textR.width = fm.stringWidth(text); - textR.height = fm.getHeight(); - while (text.indexOf('\n', fromIndex) != -1) + View html = c == null ? null + : (View) c.getClientProperty(BasicHTML.propertyKey); + if (html != null) + { + textR.width = (int) html.getPreferredSpan(View.X_AXIS); + textR.height = (int) html.getPreferredSpan(View.Y_AXIS); + } + else { - textR.height += fm.getHeight(); - fromIndex = text.indexOf('\n', fromIndex) + 1; + int fromIndex = 0; + textR.width = fm.stringWidth(text); + textR.height = fm.getHeight(); + while (text.indexOf('\n', fromIndex) != -1) + { + textR.height += fm.getHeight(); + fromIndex = text.indexOf('\n', fromIndex) + 1; + } } } diff --git a/javax/swing/plaf/basic/BasicButtonListener.java b/javax/swing/plaf/basic/BasicButtonListener.java index 848958215..042192b62 100644 --- a/javax/swing/plaf/basic/BasicButtonListener.java +++ b/javax/swing/plaf/basic/BasicButtonListener.java @@ -73,12 +73,12 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, // Store the TextLayout for this in a client property for speed-up // painting of the label. String property = e.getPropertyName(); + AbstractButton b = (AbstractButton) e.getSource(); if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY) || property.equals("font")) && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null) { - AbstractButton b = (AbstractButton) e.getSource(); String text = b.getText(); if (text == null) text = ""; @@ -87,6 +87,10 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener, TextLayout layout = new TextLayout(text, b.getFont(), frc); b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout); } + if (property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)) + { + BasicHTML.updateRenderer(b, b.getText()); + } } protected void checkOpacity(AbstractButton b) diff --git a/javax/swing/plaf/basic/BasicButtonUI.java b/javax/swing/plaf/basic/BasicButtonUI.java index d531133ba..cdaec2543 100644 --- a/javax/swing/plaf/basic/BasicButtonUI.java +++ b/javax/swing/plaf/basic/BasicButtonUI.java @@ -56,6 +56,7 @@ import javax.swing.UIManager; import javax.swing.plaf.ButtonUI; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; +import javax.swing.text.View; /** * A UI delegate for the {@link JButton} component. @@ -255,9 +256,71 @@ public class BasicButtonUI extends ButtonUI installDefaults(b); installListeners(b); installKeyboardActions(b); + BasicHTML.updateRenderer(b, b.getText()); } } + /** + * Uninstalls the UI from the component. + * + * @param c the component from which to uninstall the UI + */ + public void uninstallUI(JComponent c) + { + if (c instanceof AbstractButton) + { + AbstractButton b = (AbstractButton) c; + uninstallKeyboardActions(b); + uninstallListeners(b); + uninstallDefaults(b); + BasicHTML.updateRenderer(b, ""); + } + } + + /** + * Calculates the minimum size for the specified component. + * + * @param c the component for which to compute the minimum size + * + * @return the minimum size for the specified component + */ + public Dimension getMinimumSize(JComponent c) + { + Dimension size = getPreferredSize(c); + // When the HTML view has a minimum width different from the preferred + // width, then substract this here accordingly. The height is not + // affected by that. + View html = (View) c.getClientProperty(BasicHTML.propertyKey); + if (html != null) + { + size.width -= html.getPreferredSpan(View.X_AXIS) + - html.getPreferredSpan(View.X_AXIS); + } + return size; + } + + /** + * Calculates the maximum size for the specified component. + * + * @param c the component for which to compute the maximum size + * + * @return the maximum size for the specified component + */ + public Dimension getMaximumSize(JComponent c) + { + Dimension size = getPreferredSize(c); + // When the HTML view has a maximum width different from the preferred + // width, then add this here accordingly. The height is not + // affected by that. + View html = (View) c.getClientProperty(BasicHTML.propertyKey); + if (html != null) + { + size.width += html.getMaximumSpan(View.X_AXIS) + - html.getPreferredSpan(View.X_AXIS); + } + return size; + } + /** * Calculate the preferred size of this component, by delegating to * {@link BasicGraphicsUtils#getPreferredButtonSize}. @@ -269,8 +332,8 @@ public class BasicButtonUI extends ButtonUI public Dimension getPreferredSize(JComponent c) { AbstractButton b = (AbstractButton) c; - Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, - defaultTextIconGap + defaultTextShiftOffset); + Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, + b.getIconTextGap()); return d; } @@ -344,7 +407,13 @@ public class BasicButtonUI extends ButtonUI paintIcon(g, c, ir); if (text != null) - paintText(g, b, tr, text); + { + View html = (View) b.getClientProperty(BasicHTML.propertyKey); + if (html != null) + html.paint(g, tr); + else + paintText(g, b, tr, text); + } if (b.isFocusOwner() && b.isFocusPainted()) paintFocus(g, b, vr, tr, ir); } diff --git a/javax/swing/plaf/basic/BasicInternalFrameUI.java b/javax/swing/plaf/basic/BasicInternalFrameUI.java index 8f2181336..8161df29f 100644 --- a/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -459,18 +459,12 @@ public class BasicInternalFrameUI extends InternalFrameUI { if (frame.isMaximum()) { - JDesktopPane pane = (JDesktopPane) e.getSource(); - Insets insets = pane.getInsets(); - Rectangle bounds = pane.getBounds(); - - frame.setBounds(bounds.x + insets.left, bounds.y + insets.top, - bounds.width - insets.left - insets.right, - bounds.height - insets.top - insets.bottom); - frame.revalidate(); - frame.repaint(); + Container parent = frame.getParent(); + Insets i = parent.getInsets(); + int width = parent.getWidth() - i.left - i.right; + int height = parent.getHeight() - i.top - i.bottom; + frame.setBounds(0, 0, width, height); } - - // Sun also resizes the icons. but it doesn't seem to do anything. } /** @@ -949,17 +943,25 @@ public class BasicInternalFrameUI extends InternalFrameUI { if (evt.getNewValue() == Boolean.TRUE) { + Container parent = frame.getParent(); + if (parent != null) + parent.removeComponentListener(componentListener); closeFrame(frame); } } - /* - * FIXME: need to add ancestor properties to JComponents. else if - * (evt.getPropertyName().equals(JComponent.ANCESTOR_PROPERTY)) { if - * (desktopPane != null) - * desktopPane.removeComponentListener(componentListener); desktopPane = - * frame.getDesktopPane(); if (desktopPane != null) - * desktopPane.addComponentListener(componentListener); } - */ + else if (property.equals("ancestor")) + { + Container newParent = (Container) evt.getNewValue(); + Container oldParent = (Container) evt.getOldValue(); + if (newParent != null) + { + newParent.addComponentListener(componentListener); + } + else if (oldParent != null) + { + oldParent.removeComponentListener(componentListener); + } + } } } @@ -1258,6 +1260,12 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.addPropertyChangeListener(propertyChangeListener); frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher); frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher); + + Container parent = frame.getParent(); + if (parent != null) + { + parent.addComponentListener(componentListener); + } } /** @@ -1286,8 +1294,13 @@ public class BasicInternalFrameUI extends InternalFrameUI */ protected void uninstallListeners() { - if (desktopPane != null) - desktopPane.removeComponentListener(componentListener); + + Container parent = frame.getParent(); + if (parent != null) + { + parent.removeComponentListener(componentListener); + } + componentListener = null; frame.getRootPane().getGlassPane().removeMouseMotionListener(glassPaneDispatcher); frame.getRootPane().getGlassPane().removeMouseListener(glassPaneDispatcher); @@ -1298,7 +1311,7 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.removeMouseListener(borderListener); propertyChangeListener = null; - componentListener = null; + borderListener = null; internalFrameListener = null; glassPaneDispatcher = null; diff --git a/javax/swing/plaf/basic/BasicMenuItemUI.java b/javax/swing/plaf/basic/BasicMenuItemUI.java index bbc08535c..6110aca66 100644 --- a/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -411,10 +411,6 @@ public class BasicMenuItemUI extends MenuItemUI { ArrayList path = new ArrayList(); - // Path to menu should also include its popup menu. - if (menuItem instanceof JMenu) - path.add(((JMenu) menuItem).getPopupMenu()); - Component c = menuItem; while (c instanceof MenuElement) { diff --git a/javax/swing/plaf/basic/BasicMenuUI.java b/javax/swing/plaf/basic/BasicMenuUI.java index 7d8784fd1..355e0435e 100644 --- a/javax/swing/plaf/basic/BasicMenuUI.java +++ b/javax/swing/plaf/basic/BasicMenuUI.java @@ -41,16 +41,22 @@ package javax.swing.plaf.basic; import gnu.classpath.NotImplementedException; import java.awt.Component; +import java.awt.Container; import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.beans.PropertyChangeListener; +import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JPopupMenu; import javax.swing.LookAndFeel; +import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; +import javax.swing.Timer; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; @@ -69,6 +75,32 @@ import javax.swing.plaf.ComponentUI; */ public class BasicMenuUI extends BasicMenuItemUI { + /** + * Selects a menu. This is used to delay menu selection. + */ + class SelectMenuAction + extends AbstractAction + { + /** + * Performs the action. + */ + public void actionPerformed(ActionEvent event) + { + JMenu menu = (JMenu) menuItem; + MenuSelectionManager defaultManager = + MenuSelectionManager.defaultManager(); + MenuElement path[] = defaultManager.getSelectedPath(); + if(path.length > 0 && path[path.length - 1] == menu) + { + MenuElement newPath[] = new MenuElement[path.length + 1]; + System.arraycopy(path, 0, newPath, 0, path.length); + newPath[path.length] = menu.getPopupMenu(); + defaultManager.setSelectedPath(newPath); + } + } + + } + protected ChangeListener changeListener; /* MenuListener listens to MenuEvents fired by JMenu */ @@ -201,6 +233,7 @@ public class BasicMenuUI extends BasicMenuItemUI */ protected void installDefaults() { + LookAndFeel.installBorder(menuItem, "Menu.border"); LookAndFeel.installColorsAndFont(menuItem, "Menu.background", "Menu.foreground", "Menu.font"); @@ -212,6 +245,7 @@ public class BasicMenuUI extends BasicMenuItemUI selectionForeground = UIManager.getColor("Menu.selectionForeground"); arrowIcon = UIManager.getIcon("Menu.arrowIcon"); oldBorderPainted = UIManager.getBoolean("Menu.borderPainted"); + ((JMenu) menuItem).setDelay(200); } /** @@ -234,9 +268,10 @@ public class BasicMenuUI extends BasicMenuItemUI } protected void setupPostTimer(JMenu menu) - throws NotImplementedException { - // TODO: Implement this properly. + Timer timer = new Timer(menu.getDelay(), new SelectMenuAction()); + timer.setRepeats(false); + timer.start(); } /** @@ -285,8 +320,7 @@ public class BasicMenuUI extends BasicMenuItemUI { public void mouseClicked(MouseEvent e) { - MenuSelectionManager manager = MenuSelectionManager.defaultManager(); - manager.processMouseEvent(e); + // Nothing to do here. } public void mouseDragged(MouseEvent e) @@ -313,29 +347,46 @@ public class BasicMenuUI extends BasicMenuItemUI public void mouseEntered(MouseEvent e) { - /* When mouse enters menu item, it should be considered selected - - if (i) if this menu is a submenu in some other menu - (ii) or if this menu is in a menu bar and some other menu in a - menu bar was just selected and has its popup menu visible. - (If nothing was selected, menu should be pressed before - it will be selected) - */ JMenu menu = (JMenu) menuItem; - - // NOTE: the following if used to require !menu.isArmed but I could find - // no reason for this and it was preventing some JDK-compatible behaviour. - // Specifically, if a menu is selected but its popup menu not visible, - // and then another menu is selected whose popup menu IS visible, when - // the mouse is moved over the first menu, its popup menu should become - // visible. - - if (! menu.isTopLevelMenu() || popupVisible()) + if (menu.isEnabled()) { - // set new selection and forward this event to MenuSelectionManager - MenuSelectionManager manager = MenuSelectionManager.defaultManager(); - manager.setSelectedPath(getPath()); - manager.processMouseEvent(e); + MenuSelectionManager manager = + MenuSelectionManager.defaultManager(); + MenuElement[] selectedPath = manager.getSelectedPath(); + if (! menu.isTopLevelMenu()) + { + // Open the menu immediately or delayed, depending on the + // delay value. + if(! (selectedPath.length > 0 + && selectedPath[selectedPath.length - 1] == menu.getPopupMenu())) + { + if(menu.getDelay() == 0) + { + MenuElement[] path = getPath(); + MenuElement[] newPath = new MenuElement[path.length + 1]; + System.arraycopy(path, 0, newPath, 0, path.length); + newPath[path.length] = menu.getPopupMenu(); + manager.setSelectedPath(newPath); + } + else + { + manager.setSelectedPath(getPath()); + setupPostTimer(menu); + } + } + } + else + { + if(selectedPath.length > 0 + && selectedPath[0] == menu.getParent()) + { + MenuElement[] newPath = new MenuElement[3]; + newPath[0] = (MenuElement) menu.getParent(); + newPath[1] = menu; + newPath[2] = menu.getPopupMenu(); + manager.setSelectedPath(newPath); + } + } } } @@ -354,29 +405,48 @@ public class BasicMenuUI extends BasicMenuItemUI { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); JMenu menu = (JMenu) menuItem; - manager.processMouseEvent(e); - - // Menu should be displayed when the menu is pressed only if - // it is top-level menu - if (menu.isTopLevelMenu()) + if (menu.isEnabled()) { - if (menu.getPopupMenu().isVisible()) - // If menu is visible and menu button was pressed.. - // then need to cancel the menu - manager.clearSelectedPath(); - else - { - // Display the menu - int x = 0; - int y = menu.getHeight(); - - manager.setSelectedPath(getPath()); - - JMenuBar mb = (JMenuBar) menu.getParent(); - - // set selectedIndex of the selectionModel of a menuBar - mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu)); - } + // Open up the menu immediately if it's a toplevel menu. + // But not yet the popup, which might be opened delayed, see below. + if (menu.isTopLevelMenu()) + { + if (menu.isSelected()) + manager.clearSelectedPath(); + else + { + Container cnt = menu.getParent(); + if (cnt != null && cnt instanceof JMenuBar) + { + MenuElement[] me = new MenuElement[2]; + me[0] = (MenuElement) cnt; + me[1] = menu; + manager.setSelectedPath(me); + } + } + } + + // Open the menu's popup. Either do that immediately if delay == 0, + // or delayed when delay > 0. + MenuElement[] selectedPath = manager.getSelectedPath(); + if (selectedPath.length > 0 + && selectedPath[selectedPath.length - 1] != menu.getPopupMenu()) + { + if(menu.isTopLevelMenu() || menu.getDelay() == 0) + { + MenuElement[] newPath = + new MenuElement[selectedPath.length + 1]; + System.arraycopy(selectedPath, 0, newPath, 0, + selectedPath.length); + newPath[selectedPath.length] = menu.getPopupMenu(); + manager.setSelectedPath(newPath); + } + else + { + setupPostTimer(menu); + } + } + } } @@ -493,8 +563,44 @@ public class BasicMenuUI extends BasicMenuItemUI */ public void menuDragMouseDragged(MenuDragMouseEvent e) { - MenuSelectionManager manager = MenuSelectionManager.defaultManager(); - manager.setSelectedPath(e.getPath()); + if (menuItem.isEnabled()) + { + MenuSelectionManager manager = e.getMenuSelectionManager(); + MenuElement path[] = e.getPath(); + + Point p = e.getPoint(); + if(p.x >= 0 && p.x < menuItem.getWidth() + && p.y >= 0 && p.y < menuItem.getHeight()) + { + JMenu menu = (JMenu) menuItem; + MenuElement[] selectedPath = manager.getSelectedPath(); + if(! (selectedPath.length > 0 + && selectedPath[selectedPath.length-1] + == menu.getPopupMenu())) + { + if(menu.isTopLevelMenu() || menu.getDelay() == 0 + || e.getID() == MouseEvent.MOUSE_DRAGGED) + { + MenuElement[] newPath = new MenuElement[path.length + 1]; + System.arraycopy(path, 0, newPath, 0, path.length); + newPath[path.length] = menu.getPopupMenu(); + manager.setSelectedPath(newPath); + } + else + { + manager.setSelectedPath(path); + setupPostTimer(menu); + } + } + } + else if (e.getID() == MouseEvent.MOUSE_RELEASED) + { + Component comp = manager.componentForPoint(e.getComponent(), + e.getPoint()); + if (comp == null) + manager.clearSelectedPath(); + } + } } /** @@ -505,8 +611,7 @@ public class BasicMenuUI extends BasicMenuItemUI */ public void menuDragMouseEntered(MenuDragMouseEvent e) { - MenuSelectionManager manager = MenuSelectionManager.defaultManager(); - manager.setSelectedPath(e.getPath()); + // Nothing to do here. } /** diff --git a/javax/swing/plaf/metal/MetalBorders.java b/javax/swing/plaf/metal/MetalBorders.java index 7c41180ae..d4e3a8497 100644 --- a/javax/swing/plaf/metal/MetalBorders.java +++ b/javax/swing/plaf/metal/MetalBorders.java @@ -926,15 +926,11 @@ public class MetalBorders /** The border insets. */ protected static Insets borderInsets = new Insets(1, 0, 1, 0); - // TODO: find where this color really comes from - private static Color borderColor = new Color(153, 153, 153); - /** * Creates a new border instance. */ public MenuBarBorder() { - // Nothing to do here. } /** @@ -951,7 +947,17 @@ public class MetalBorders public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { - g.setColor(borderColor); + // Although it is not correct to decide on the static property + // currentTheme which color to use the RI does it like that. + // The trouble is that by simply changing the current theme to + // e.g. DefaultMetalLookAndFeel this method will use another color + // although a change in painting behavior should be expected only + // after setting a new look and feel and updating all components. + if(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + g.setColor(UIManager.getColor("MenuBar.borderColor")); + else + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x, y + h - 1, x + w, y + h - 1); } diff --git a/javax/swing/plaf/metal/MetalMenuBarUI.java b/javax/swing/plaf/metal/MetalMenuBarUI.java index ff763ea9d..40661946b 100644 --- a/javax/swing/plaf/metal/MetalMenuBarUI.java +++ b/javax/swing/plaf/metal/MetalMenuBarUI.java @@ -1,5 +1,5 @@ /* MetalMenuBarUI.java -- MenuBar UI for the Metal L&F - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -76,12 +76,15 @@ public class MetalMenuBarUI extends BasicMenuBarUI */ public void update(Graphics g, JComponent c) { + int height = c.getHeight(); if (c.isOpaque() && UIManager.get("MenuBar.gradient") != null - && c.getBackground() instanceof UIResource) + && c.getBackground() instanceof UIResource + && height > 2) { - MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), + MetalUtils.paintGradient(g, 0, 0, c.getWidth(), height - 2, SwingConstants.VERTICAL, "MenuBar.gradient"); + paint(g, c); } else diff --git a/javax/swing/text/AbstractDocument.java b/javax/swing/text/AbstractDocument.java index 200ea6742..54797fdb0 100644 --- a/javax/swing/text/AbstractDocument.java +++ b/javax/swing/text/AbstractDocument.java @@ -38,8 +38,11 @@ exception statement from your version. */ package javax.swing.text; +import java.awt.font.TextAttribute; import java.io.PrintStream; import java.io.Serializable; +import java.text.Bidi; +import java.util.ArrayList; import java.util.Dictionary; import java.util.Enumeration; import java.util.EventListener; @@ -104,6 +107,21 @@ public abstract class AbstractDocument implements Document, Serializable */ public static final String ElementNameAttribute = "$ename"; + /** + * Standard name for the bidi root element. + */ + private static final String BidiRootName = "bidi root"; + + /** + * Key for storing the asynchronous load priority. + */ + private static final String AsyncLoadPriority = "load priority"; + + /** + * Key for storing the I18N state. + */ + private static final String I18N = "i18n"; + /** * The actual content model of this Document. */ @@ -158,7 +176,7 @@ public abstract class AbstractDocument implements Document, Serializable /** * The bidi root element. */ - private Element bidiRoot; + private BidiRootElement bidiRoot; /** * Creates a new AbstractDocument with the specified @@ -191,12 +209,25 @@ public abstract class AbstractDocument implements Document, Serializable content = doc; context = ctx; + // FIXME: Fully implement bidi. + bidiRoot = new BidiRootElement(); + // FIXME: This is determined using a Mauve test. Make the document // actually use this. - putProperty("i18n", Boolean.FALSE); + putProperty(I18N, Boolean.FALSE); - // FIXME: Fully implement bidi. - bidiRoot = new BranchElement(null, null); + // Add one child to the bidi root. + writeLock(); + try + { + Element[] children = new Element[1]; + children[0] = new BidiElement(bidiRoot, 0, 1, 0); + bidiRoot.replace(0, 0, children); + } + finally + { + writeUnlock(); + } } /** Returns the DocumentFilter.FilterBypass instance for this @@ -352,7 +383,11 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getAsynchronousLoadPriority() { - return 0; + Object val = getProperty(AsyncLoadPriority); + int prio = -1; + if (val != null) + prio = ((Integer) val).intValue(); + return prio; } /** @@ -425,14 +460,17 @@ public abstract class AbstractDocument implements Document, Serializable */ public final Position getEndPosition() { - // FIXME: Properly implement this by calling Content.createPosition(). - return new Position() - { - public int getOffset() - { - return getLength(); - } - }; + Position p; + try + { + p = createPosition(content.length()); + } + catch (BadLocationException ex) + { + // Shouldn't really happen. + p = null; + } + return p; } /** @@ -504,14 +542,17 @@ public abstract class AbstractDocument implements Document, Serializable */ public final Position getStartPosition() { - // FIXME: Properly implement this using Content.createPosition(). - return new Position() - { - public int getOffset() - { - return 0; - } - }; + Position p; + try + { + p = createPosition(0); + } + catch (BadLocationException ex) + { + // Shouldn't really happen. + p = null; + } + return p; } /** @@ -574,11 +615,19 @@ public abstract class AbstractDocument implements Document, Serializable // Bail out if we have a bogus insertion (Behavior observed in RI). if (text == null || text.length() == 0) return; - - if (documentFilter == null) - insertStringImpl(offset, text, attributes); - else - documentFilter.insertString(getBypass(), offset, text, attributes); + + writeLock(); + try + { + if (documentFilter == null) + insertStringImpl(offset, text, attributes); + else + documentFilter.insertString(getBypass(), offset, text, attributes); + } + finally + { + writeUnlock(); + } } void insertStringImpl(int offset, String text, AttributeSet attributes) @@ -591,23 +640,30 @@ public abstract class AbstractDocument implements Document, Serializable new DefaultDocumentEvent(offset, text.length(), DocumentEvent.EventType.INSERT); - try - { - writeLock(); - UndoableEdit undo = content.insertString(offset, text); - if (undo != null) - event.addEdit(undo); - - insertUpdate(event, attributes); + UndoableEdit undo = content.insertString(offset, text); + if (undo != null) + event.addEdit(undo); - fireInsertUpdate(event); - if (undo != null) - fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); - } - finally + // Check if we need bidi layout. + if (getProperty(I18N).equals(Boolean.FALSE)) { - writeUnlock(); + Object dir = getProperty(TextAttribute.RUN_DIRECTION); + if (TextAttribute.RUN_DIRECTION_RTL.equals(dir)) + putProperty(I18N, Boolean.TRUE); + else + { + char[] chars = text.toCharArray(); + if (Bidi.requiresBidi(chars, 0, chars.length)) + putProperty(I18N, Boolean.TRUE); + } } + + insertUpdate(event, attributes); + + fireInsertUpdate(event); + + if (undo != null) + fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); } /** @@ -620,7 +676,8 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { - // Do nothing here. Subclasses may want to override this. + if (Boolean.TRUE.equals(getProperty(I18N))) + updateBidi(chng); } /** @@ -632,7 +689,8 @@ public abstract class AbstractDocument implements Document, Serializable */ protected void postRemoveUpdate(DefaultDocumentEvent chng) { - // Do nothing here. Subclasses may want to override this. + if (Boolean.TRUE.equals(getProperty(I18N))) + updateBidi(chng); } /** @@ -647,7 +705,317 @@ public abstract class AbstractDocument implements Document, Serializable if (properties == null) properties = new Hashtable(); - properties.put(key, value); + if (value == null) + properties.remove(key); + else + properties.put(key, value); + + // Update bidi structure if the RUN_DIRECTION is set. + if (TextAttribute.RUN_DIRECTION.equals(key)) + { + if (TextAttribute.RUN_DIRECTION_RTL.equals(value) + && Boolean.FALSE.equals(getProperty(I18N))) + putProperty(I18N, Boolean.TRUE); + + if (Boolean.TRUE.equals(getProperty(I18N))) + { + writeLock(); + try + { + DefaultDocumentEvent ev = + new DefaultDocumentEvent(0, getLength(), + DocumentEvent.EventType.INSERT); + updateBidi(ev); + } + finally + { + writeUnlock(); + } + } + } + } + + /** + * Updates the bidi element structure. + * + * @param ev the document event for the change + */ + private void updateBidi(DefaultDocumentEvent ev) + { + // Determine start and end offset of the paragraphs to be scanned. + int start = 0; + int end = 0; + DocumentEvent.EventType type = ev.getType(); + if (type == DocumentEvent.EventType.INSERT + || type == DocumentEvent.EventType.CHANGE) + { + int offs = ev.getOffset(); + int endOffs = offs + ev.getLength(); + start = getParagraphElement(offs).getStartOffset(); + end = getParagraphElement(endOffs).getEndOffset(); + } + else if (type == DocumentEvent.EventType.REMOVE) + { + Element par = getParagraphElement(ev.getOffset()); + start = par.getStartOffset(); + end = par.getEndOffset(); + } + else + assert false : "Unknown event type"; + + // Determine the bidi levels for the affected range. + Bidi[] bidis = getBidis(start, end); + + int removeFrom = 0; + int removeTo = 0; + + int offs = 0; + int lastRunStart = 0; + int lastRunEnd = 0; + int lastRunLevel = 0; + ArrayList newEls = new ArrayList(); + for (int i = 0; i < bidis.length; i++) + { + Bidi bidi = bidis[i]; + int numRuns = bidi.getRunCount(); + for (int r = 0; r < numRuns; r++) + { + if (r == 0 && i == 0) + { + if (start > 0) + { + // Try to merge with the previous element if it has the + // same bidi level as the first run. + int prevElIndex = bidiRoot.getElementIndex(start - 1); + removeFrom = prevElIndex; + Element prevEl = bidiRoot.getElement(prevElIndex); + AttributeSet atts = prevEl.getAttributes(); + int prevElLevel = StyleConstants.getBidiLevel(atts); + if (prevElLevel == bidi.getRunLevel(r)) + { + // Merge previous element with current run. + lastRunStart = prevEl.getStartOffset() - start; + lastRunEnd = bidi.getRunLimit(r); + lastRunLevel = bidi.getRunLevel(r); + } + else if (prevEl.getEndOffset() > start) + { + // Split previous element and replace by 2 new elements. + lastRunStart = 0; + lastRunEnd = bidi.getRunLimit(r); + lastRunLevel = bidi.getRunLevel(r); + newEls.add(new BidiElement(bidiRoot, + prevEl.getStartOffset(), + start, prevElLevel)); + } + else + { + // Simply start new run at start location. + lastRunStart = 0; + lastRunEnd = bidi.getRunLimit(r); + lastRunLevel = bidi.getRunLevel(r); + removeFrom++; + } + } + else + { + // Simply start new run at start location. + lastRunStart = 0; + lastRunEnd = bidi.getRunLimit(r); + lastRunLevel = bidi.getRunLevel(r); + removeFrom = 0; + } + } + if (i == bidis.length - 1 && r == numRuns - 1) + { + if (end <= getLength()) + { + // Try to merge last element with next element. + int nextIndex = bidiRoot.getElementIndex(end); + Element nextEl = bidiRoot.getElement(nextIndex); + AttributeSet atts = nextEl.getAttributes(); + int nextLevel = StyleConstants.getBidiLevel(atts); + int level = bidi.getRunLevel(r); + if (lastRunLevel == level && level == nextLevel) + { + // Merge runs together. + if (lastRunStart + start == nextEl.getStartOffset()) + removeTo = nextIndex - 1; + else + { + newEls.add(new BidiElement(bidiRoot, start + lastRunStart, + nextEl.getEndOffset(), level)); + removeTo = nextIndex; + } + } + else if (lastRunLevel == level) + { + // Merge current and last run. + int endOffs = offs + bidi.getRunLimit(r); + newEls.add(new BidiElement(bidiRoot, start + lastRunStart, + start + endOffs, level)); + if (start + endOffs == nextEl.getStartOffset()) + removeTo = nextIndex - 1; + else + { + newEls.add(new BidiElement(bidiRoot, start + endOffs, + nextEl.getEndOffset(), + nextLevel)); + removeTo = nextIndex; + } + } + else if (level == nextLevel) + { + // Merge current and next run. + newEls.add(new BidiElement(bidiRoot, start + lastRunStart, + start + lastRunEnd, + lastRunLevel)); + newEls.add(new BidiElement(bidiRoot, start + lastRunEnd, + nextEl.getEndOffset(), level)); + removeTo = nextIndex; + } + else + { + // Split next element. + int endOffs = offs + bidi.getRunLimit(r); + newEls.add(new BidiElement(bidiRoot, start + lastRunStart, + start + lastRunEnd, + lastRunLevel)); + newEls.add(new BidiElement(bidiRoot, start + lastRunEnd, + start + endOffs, level)); + newEls.add(new BidiElement(bidiRoot, start + endOffs, + nextEl.getEndOffset(), + nextLevel)); + removeTo = nextIndex; + } + } + else + { + removeTo = bidiRoot.getElementIndex(end); + int level = bidi.getRunLevel(r); + int runEnd = offs + bidi.getRunLimit(r); + + if (level == lastRunLevel) + { + // Merge with previous. + lastRunEnd = offs + runEnd; + newEls.add(new BidiElement(bidiRoot, + start + lastRunStart, + start + runEnd, level)); + } + else + { + // Create element for last run and current run. + newEls.add(new BidiElement(bidiRoot, start + lastRunStart, + start + lastRunEnd, + lastRunLevel)); + newEls.add(new BidiElement(bidiRoot, + start + lastRunEnd, + start + runEnd, + level)); + } + } + } + else + { + int level = bidi.getRunLevel(r); + int runEnd = bidi.getRunLimit(r); + + if (level == lastRunLevel) + { + // Merge with previous. + lastRunEnd = offs + runEnd; + } + else + { + // Create element for last run and update values for + // current run. + newEls.add(new BidiElement(bidiRoot, start + lastRunStart, + start + lastRunEnd, + lastRunLevel)); + lastRunStart = lastRunEnd; + lastRunEnd = offs + runEnd; + lastRunLevel = level; + } + } + } + offs += bidi.getLength(); + } + + // Determine the bidi elements which are to be removed. + int numRemoved = 0; + if (bidiRoot.getElementCount() > 0) + numRemoved = removeTo - removeFrom + 1; + Element[] removed = new Element[numRemoved]; + for (int i = 0; i < numRemoved; i++) + removed[i] = bidiRoot.getElement(removeFrom + i); + + Element[] added = new Element[newEls.size()]; + added = (Element[]) newEls.toArray(added); + + // Update the event. + ElementEdit edit = new ElementEdit(bidiRoot, removeFrom, removed, added); + ev.addEdit(edit); + + // Update the structure. + bidiRoot.replace(removeFrom, numRemoved, added); + } + + /** + * Determines the Bidi objects for the paragraphs in the specified range. + * + * @param start the start of the range + * @param end the end of the range + * + * @return the Bidi analysers for the paragraphs in the range + */ + private Bidi[] getBidis(int start, int end) + { + // Determine the default run direction from the document property. + Boolean defaultDir = null; + Object o = getProperty(TextAttribute.RUN_DIRECTION); + if (o instanceof Boolean) + defaultDir = (Boolean) o; + + // Scan paragraphs and add their level arrays to the overall levels array. + ArrayList bidis = new ArrayList(); + Segment s = new Segment(); + for (int i = start; i < end;) + { + Element par = getParagraphElement(i); + int pStart = par.getStartOffset(); + int pEnd = par.getEndOffset(); + + // Determine the default run direction of the paragraph. + Boolean dir = defaultDir; + o = par.getAttributes().getAttribute(TextAttribute.RUN_DIRECTION); + if (o instanceof Boolean) + dir = (Boolean) o; + + // Bidi over the paragraph. + try + { + getText(pStart, pEnd - pStart, s); + } + catch (BadLocationException ex) + { + assert false : "Must not happen"; + } + int flag = Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT; + if (dir != null) + { + if (TextAttribute.RUN_DIRECTION_LTR.equals(dir)) + flag = Bidi.DIRECTION_LEFT_TO_RIGHT; + else + flag = Bidi.DIRECTION_RIGHT_TO_LEFT; + } + Bidi bidi = new Bidi(s.array, s.offset, null, 0, s.count, flag); + bidis.add(bidi); + i = pEnd; + } + Bidi[] ret = new Bidi[bidis.size()]; + ret = (Bidi[]) bidis.toArray(ret); + return ret; } /** @@ -662,6 +1030,7 @@ public abstract class AbstractDocument implements Document, Serializable { while (currentWriter != null || numWritersWaiting > 0) { + try { documentCV.wait(); @@ -814,21 +1183,28 @@ public abstract class AbstractDocument implements Document, Serializable if (length == 0 && (text == null || text.length() == 0)) return; - - if (documentFilter == null) + + writeLock(); + try { - // It is important to call the methods which again do the checks - // of the arguments and the DocumentFilter because subclasses may - // have overridden these methods and provide crucial behavior - // which would be skipped if we call the non-checking variants. - // An example for this is PlainDocument where insertString can - // provide a filtering of newlines. - remove(offset, length); - insertString(offset, text, attributes); + if (documentFilter == null) + { + // It is important to call the methods which again do the checks + // of the arguments and the DocumentFilter because subclasses may + // have overridden these methods and provide crucial behavior + // which would be skipped if we call the non-checking variants. + // An example for this is PlainDocument where insertString can + // provide a filtering of newlines. + remove(offset, length); + insertString(offset, text, attributes); + } + else + documentFilter.replace(getBypass(), offset, length, text, attributes); + } + finally + { + writeUnlock(); } - else - documentFilter.replace(getBypass(), offset, length, text, attributes); - } void replaceImpl(int offset, int length, String text, @@ -948,7 +1324,8 @@ public abstract class AbstractDocument implements Document, Serializable */ public void setAsynchronousLoadPriority(int p) { - // TODO: Implement this properly. + Integer val = p >= 0 ? new Integer(p) : null; + putProperty(AsyncLoadPriority, val); } /** @@ -1039,6 +1416,7 @@ public abstract class AbstractDocument implements Document, Serializable public void dump(PrintStream out) { ((AbstractElement) getDefaultRootElement()).dump(out, 0); + ((AbstractElement) getBidiRootElement()).dump(out, 0); } /** @@ -1255,7 +1633,7 @@ public abstract class AbstractDocument implements Document, Serializable AttributeContext ctx = getAttributeContext(); attributes = ctx.getEmptySet(); if (s != null) - attributes = ctx.addAttributes(attributes, s); + addAttributes(s); } /** @@ -1567,7 +1945,7 @@ public abstract class AbstractDocument implements Document, Serializable */ public String getName() { - return (String) getAttribute(NameAttribute); + return (String) attributes.getAttribute(ElementNameAttribute); } /** @@ -1644,6 +2022,11 @@ public abstract class AbstractDocument implements Document, Serializable b.append('\n'); } } + if (getAttributeCount() > 0) + { + for (int i = 0; i < indent; ++i) + b.append(' '); + } b.append(">\n"); // Dump element content for leaf elements. @@ -1704,6 +2087,11 @@ public abstract class AbstractDocument implements Document, Serializable */ private int numChildren; + /** + * The last found index in getElementIndex(). Used for faster searching. + */ + private int lastIndex; + /** * Creates a new BranchElement with the specified * parent and attributes. @@ -1717,6 +2105,7 @@ public abstract class AbstractDocument implements Document, Serializable super(parent, attributes); children = new Element[1]; numChildren = 0; + lastIndex = -1; } /** @@ -1726,7 +2115,7 @@ public abstract class AbstractDocument implements Document, Serializable */ public Enumeration children() { - if (children.length == 0) + if (numChildren == 0) return null; Vector tmp = new Vector(); @@ -1785,35 +2174,73 @@ public abstract class AbstractDocument implements Document, Serializable */ public int getElementIndex(int offset) { - // If offset is less than the start offset of our first child, - // return 0 - if (offset < getStartOffset()) - return 0; + // Implemented using an improved linear search. + // This makes use of the fact that searches are not random but often + // close to the previous search. So we try to start the binary + // search at the last found index. - // XXX: There is surely a better algorithm - // as beginning from first element each time. - for (int index = 0; index < numChildren - 1; ++index) + int i0 = 0; // The lower bounds. + int i1 = numChildren - 1; // The upper bounds. + int index = -1; // The found index. + + int p0 = getStartOffset(); + int p1; // Start and end offset local variables. + + if (numChildren == 0) + index = 0; + else if (offset >= getEndOffset()) + index = numChildren - 1; + else { - Element elem = children[index]; - - if ((elem.getStartOffset() <= offset) - && (offset < elem.getEndOffset())) - return index; - // If the next element's start offset is greater than offset - // then we have to return the closest Element, since no Elements - // will contain the offset - if (children[index + 1].getStartOffset() > offset) + // Try lastIndex. + if (lastIndex >= i0 && lastIndex <= i1) { - if ((offset - elem.getEndOffset()) > (children[index + 1].getStartOffset() - offset)) - return index + 1; + Element last = getElement(lastIndex); + p0 = last.getStartOffset(); + p1 = last.getEndOffset(); + if (offset >= p0 && offset < p1) + index = lastIndex; else - return index; + { + // Narrow the search bounds using the lastIndex, even + // if it hasn't been a hit. + if (offset < p0) + i1 = lastIndex; + else + i0 = lastIndex; + } + } + // The actual search. + int i = 0; + while (i0 <= i1 && index == -1) + { + i = i0 + (i1 - i0) / 2; + Element el = getElement(i); + p0 = el.getStartOffset(); + p1 = el.getEndOffset(); + if (offset >= p0 && offset < p1) + { + // Found it! + index = i; + } + else if (offset < p0) + i1 = i - 1; + else + i0 = i + 1; } - } - // If offset is greater than the index of the last element, return - // the index of the last element. - return getElementCount() - 1; + if (index == -1) + { + // Didn't find it. Return the boundary index. + if (offset < p0) + index = i; + else + index = i + 1; + } + + lastIndex = index; + } + return index; } /** @@ -2333,7 +2760,63 @@ public abstract class AbstractDocument implements Document, Serializable + getStartOffset() + "," + getEndOffset() + "\n"); } } - + + /** + * The root element for bidirectional text. + */ + private class BidiRootElement + extends BranchElement + { + /** + * Creates a new bidi root element. + */ + BidiRootElement() + { + super(null, null); + } + + /** + * Returns the name of the element. + * + * @return the name of the element + */ + public String getName() + { + return BidiRootName; + } + } + + /** + * A leaf element for the bidi structure. + */ + private class BidiElement + extends LeafElement + { + /** + * Creates a new BidiElement. + * + * @param parent the parent element + * @param start the start offset + * @param end the end offset + * @param level the bidi level + */ + BidiElement(Element parent, int start, int end, int level) + { + super(parent, new SimpleAttributeSet(), start, end); + addAttribute(StyleConstants.BidiLevel, new Integer(level)); + } + + /** + * Returns the name of the element. + * + * @return the name of the element + */ + public String getName() + { + return BidiElementName; + } + } + /** A class whose methods delegate to the insert, remove and replace methods * of this document which do not check for an installed DocumentFilter. */ diff --git a/javax/swing/text/BoxView.java b/javax/swing/text/BoxView.java index 27e3c0f9a..7e8f19f74 100644 --- a/javax/swing/text/BoxView.java +++ b/javax/swing/text/BoxView.java @@ -476,8 +476,8 @@ public class BoxView { View child = getView(i); min += child.getMinimumSpan(axis); - pref = child.getPreferredSpan(axis); - max = child.getMaximumSpan(axis); + pref += child.getPreferredSpan(axis); + max += child.getMaximumSpan(axis); } res.minimum = (int) min; @@ -568,9 +568,9 @@ public class BoxView boolean result = false; if (myAxis == X_AXIS) - result = x > r.x; + result = x > r.x + r.width; else - result = y > r.y; + result = y > r.y + r.height; return result; } @@ -623,9 +623,6 @@ public class BoxView */ protected void childAllocation(int index, Rectangle a) { - if (! isAllocationValid()) - layout(a.width, a.height); - a.x += offsets[X_AXIS][index]; a.y += offsets[Y_AXIS][index]; a.width = spans[X_AXIS][index]; @@ -776,7 +773,7 @@ public class BoxView View child = getView(i); int max = (int) child.getMaximumSpan(axis); if (max < targetSpan) - {System.err.println("align: " + child); + { // Align child when it can't be made as wide as the target span. float align = child.getAlignment(axis); offsets[i] = (int) ((targetSpan - max) * align); @@ -811,7 +808,7 @@ public class BoxView */ public int getWidth() { - return span[X_AXIS]; + return span[X_AXIS] + getLeftInset() - getRightInset(); } /** @@ -821,7 +818,7 @@ public class BoxView */ public int getHeight() { - return span[Y_AXIS]; + return span[Y_AXIS] + getTopInset() - getBottomInset(); } /** @@ -833,7 +830,8 @@ public class BoxView */ public void setSize(float width, float height) { - layout((int) width, (int) height); + layout((int) (width - getLeftInset() - getRightInset()), + (int) (height - getTopInset() - getBottomInset())); } /** @@ -1024,6 +1022,8 @@ public class BoxView */ private void updateRequirements(int axis) { + if (axis != Y_AXIS && axis != X_AXIS) + throw new IllegalArgumentException("Illegal axis: " + axis); if (! requirementsValid[axis]) { if (axis == myAxis) diff --git a/javax/swing/text/DefaultHighlighter.java b/javax/swing/text/DefaultHighlighter.java index 59f77316e..69563e473 100644 --- a/javax/swing/text/DefaultHighlighter.java +++ b/javax/swing/text/DefaultHighlighter.java @@ -1,4 +1,4 @@ -/* DefaultHighlighter.java -- +/* DefaultHighlighter.java -- The default highlight for Swing Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,18 +38,21 @@ exception statement from your version. */ package javax.swing.text; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Graphics; import java.awt.Insets; import java.awt.Rectangle; import java.awt.Shape; import java.util.ArrayList; +import java.util.Iterator; import javax.swing.SwingUtilities; import javax.swing.plaf.TextUI; +/** + * The default highlight for Swing text components. It highlights text + * by filling the background with a rectangle. + */ public class DefaultHighlighter extends LayeredHighlighter { public static class DefaultHighlightPainter @@ -68,11 +71,6 @@ public class DefaultHighlighter extends LayeredHighlighter return color; } - private void paintHighlight(Graphics g, Rectangle rect) - { - g.fillRect(rect.x, rect.y, rect.width, rect.height); - } - public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent t) { @@ -81,30 +79,31 @@ public class DefaultHighlighter extends LayeredHighlighter Rectangle rect = bounds.getBounds(); - if (color == null) - g.setColor(t.getSelectionColor()); - else - g.setColor(color); + Color col = getColor(); + if (col == null) + col = t.getSelectionColor(); + g.setColor(col); TextUI ui = t.getUI(); try - { - - Rectangle l0 = ui.modelToView(t, p0, null); - Rectangle l1 = ui.modelToView(t, p1, null); - - // Note: The computed locations may lie outside of the allocation - // area if the text is scrolled. + { + + Rectangle l0 = ui.modelToView(t, p0, null); + Rectangle l1 = ui.modelToView(t, p1, null); - if (l0.y == l1.y) + // Note: The computed locations may lie outside of the allocation + // area if the text is scrolled. + + if (l0.y == l1.y) { SwingUtilities.computeUnion(l0.x, l0.y, l0.width, l0.height, l1); // Paint only inside the allocation area. - SwingUtilities.computeIntersection(rect.x, rect.y, rect.width, rect.height, l1); + SwingUtilities.computeIntersection(rect.x, rect.y, rect.width, + rect.height, l1); - paintHighlight(g, l1); + g.fillRect(l1.x, l1.y, l1.width, l1.height); } else { @@ -115,77 +114,71 @@ public class DefaultHighlighter extends LayeredHighlighter // out the bounds. // 3. The final line is painted from the left border to the // position of p1. - - // Highlight first line until the end. - // If rect.x is non-zero the calculation will properly adjust the - // area to be painted. - l0.x -= rect.x; - l0.width = rect.width - l0.x - rect.x; - - paintHighlight(g, l0); - - int posBelow = Utilities.getPositionBelow(t, p0, l0.x); - int p1RowStart = Utilities.getRowStart(t, p1); - if (posBelow != -1 - && posBelow != p0 - && Utilities.getRowStart(t, posBelow) - != p1RowStart) - { - Rectangle grow = ui.modelToView(t, posBelow); - grow.x = rect.x; - grow.width = rect.width; - - // Find further lines which have to be highlighted completely. - int nextPosBelow = posBelow; - while (nextPosBelow != -1 - && Utilities.getRowStart(t, nextPosBelow) != p1RowStart) - { - posBelow = nextPosBelow; - nextPosBelow = Utilities.getPositionBelow(t, posBelow, l0.x); - - if (nextPosBelow == posBelow) - break; - } - // Now posBelow is an offset on the last line which has to be painted - // completely. (newPosBelow is on the same line as p1) - - // Retrieve the rectangle of posBelow and use its y and height - // value to calculate the final height of the multiple line - // spanning rectangle. - Rectangle end = ui.modelToView(t, posBelow); - grow.height = end.y + end.height - grow.y; - - paintHighlight(g, grow); - } - - // Paint last line from its beginning to the position of p1. - l1.width = l1.x + l1.width - rect.x; - l1.x = rect.x; - paintHighlight(g, l1); - } + + int firstLineWidth = rect.x + rect.width - l0.x; + g.fillRect(l0.x, l0.y, firstLineWidth, l0.height); + if (l0.y + l0.height != l1.y) + { + g.fillRect(rect.x, l0.y + l0.height, rect.width, + l1.y - l0.y - l0.height); + } + g.fillRect(rect.x, l1.y, l1.x - rect.x, l1.height); + } } catch (BadLocationException ex) { - AssertionError err = new AssertionError("Unexpected bad location exception"); - err.initCause(ex); - throw err; + // Can't render. Comment out for debugging. + // ex.printStackTrace(); } } public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds, JTextComponent c, View view) { - throw new InternalError(); + Color col = getColor(); + if (col == null) + col = c.getSelectionColor(); + g.setColor(col); + + Rectangle rect = null; + if (p0 == view.getStartOffset() && p1 == view.getEndOffset()) + { + // Paint complete bounds region. + rect = bounds instanceof Rectangle ? (Rectangle) bounds + : bounds.getBounds(); + } + else + { + // Only partly inside the view. + try + { + Shape s = view.modelToView(p0, Position.Bias.Forward, + p1, Position.Bias.Backward, + bounds); + rect = s instanceof Rectangle ? (Rectangle) s : s.getBounds(); + } + catch (BadLocationException ex) + { + // Can't render the highlight. + } + } + + if (rect != null) + { + g.fillRect(rect.x, rect.y, rect.width, rect.height); + } + return rect; } } private class HighlightEntry implements Highlighter.Highlight { - int p0; - int p1; + Position p0; + Position p1; Highlighter.HighlightPainter painter; - public HighlightEntry(int p0, int p1, Highlighter.HighlightPainter painter) + public HighlightEntry(Position p0, Position p1, + Highlighter.HighlightPainter painter) { this.p0 = p0; this.p1 = p1; @@ -194,12 +187,12 @@ public class DefaultHighlighter extends LayeredHighlighter public int getStartOffset() { - return p0; + return p0.getOffset(); } public int getEndOffset() { - return p1; + return p1.getOffset(); } public Highlighter.HighlightPainter getPainter() @@ -208,6 +201,58 @@ public class DefaultHighlighter extends LayeredHighlighter } } + /** + * A HighlightEntry that is used for LayerPainter painters. In addition + * to the info maintained by the HighlightEntry, this class maintains + * a painting rectangle. This is used as repaint region when the + * highlight changes and the text component needs repainting. + */ + private class LayerHighlightEntry + extends HighlightEntry + { + + /** + * The paint rectangle. + */ + Rectangle paintRect = new Rectangle(); + + LayerHighlightEntry(Position p0, Position p1, + Highlighter.HighlightPainter p) + { + super(p0, p1, p); + } + + /** + * Paints the highlight by calling the LayerPainter. This + * restricts the area to be painted by startOffset and endOffset + * and manages the paint rectangle. + */ + void paintLayeredHighlight(Graphics g, int p0, int p1, Shape bounds, + JTextComponent tc, View view) + { + p0 = Math.max(getStartOffset(), p0); + p1 = Math.min(getEndOffset(), p1); + + Highlighter.HighlightPainter painter = getPainter(); + if (painter instanceof LayerPainter) + { + LayerPainter layerPainter = (LayerPainter) painter; + Shape area = layerPainter.paintLayer(g, p0, p1, bounds, tc, view); + Rectangle rect; + if (area instanceof Rectangle && paintRect != null) + rect = (Rectangle) area; + else + rect = area.getBounds(); + + if (paintRect.width == 0 || paintRect.height == 0) + paintRect = rect.getBounds(); + else + paintRect = SwingUtilities.computeUnion(rect.x, rect.y, rect.width, + rect.height, paintRect); + } + } + } + /** * @specnote final as of 1.4 */ @@ -254,11 +299,19 @@ public class DefaultHighlighter extends LayeredHighlighter textComponent = null; } - public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter painter) + public Object addHighlight(int p0, int p1, + Highlighter.HighlightPainter painter) throws BadLocationException { checkPositions(p0, p1); - HighlightEntry entry = new HighlightEntry(p0, p1, painter); + HighlightEntry entry; + Document doc = textComponent.getDocument(); + Position pos0 = doc.createPosition(p0); + Position pos1 = doc.createPosition(p1); + if (getDrawsLayeredHighlights() && painter instanceof LayerPainter) + entry = new LayerHighlightEntry(pos0, pos1, painter); + else + entry = new HighlightEntry(pos0, pos1, painter); highlights.add(entry); textComponent.getUI().damageRange(textComponent, p0, p1); @@ -268,16 +321,67 @@ public class DefaultHighlighter extends LayeredHighlighter public void removeHighlight(Object tag) { + HighlightEntry entry = (HighlightEntry) tag; + if (entry instanceof LayerHighlightEntry) + { + LayerHighlightEntry lEntry = (LayerHighlightEntry) entry; + Rectangle paintRect = lEntry.paintRect; + textComponent.repaint(paintRect.x, paintRect.y, paintRect.width, + paintRect.height); + } + else + { + textComponent.getUI().damageRange(textComponent, + entry.getStartOffset(), + entry.getEndOffset()); + } highlights.remove(tag); - HighlightEntry entry = (HighlightEntry) tag; - textComponent.getUI().damageRange(textComponent, - entry.p0, - entry.p1); } public void removeAllHighlights() { + // Repaint damaged region. + int minX = 0; + int maxX = 0; + int minY = 0; + int maxY = 0; + int p0 = -1; + int p1 = -1; + for (Iterator i = highlights.iterator(); i.hasNext();) + { + HighlightEntry e = (HighlightEntry) i.next(); + if (e instanceof LayerHighlightEntry) + { + LayerHighlightEntry le = (LayerHighlightEntry) e; + Rectangle r = le.paintRect; + minX = Math.min(r.x, minX); + maxX = Math.max(r.x + r.width, maxX); + minY = Math.min(r.y, minY); + maxY = Math.max(r.y + r.height, maxY); + } + else + { + if (p0 == -1 || p1 == -1) + { + p0 = e.getStartOffset(); + p1 = e.getEndOffset(); + } + else + { + p0 = Math.min(p0, e.getStartOffset()); + p1 = Math.max(p1, e.getEndOffset()); + } + } + if (minX != maxX && minY != maxY) + textComponent.repaint(minX, minY, maxX - minX, maxY - minY); + if (p0 != -1 && p1 != -1) + { + TextUI ui = textComponent.getUI(); + ui.damageRange(textComponent, p0, p1); + } + + } highlights.clear(); } @@ -290,94 +394,61 @@ public class DefaultHighlighter extends LayeredHighlighter public void changeHighlight(Object tag, int n0, int n1) throws BadLocationException { - int o0, o1; - - checkPositions(n0, n1); - HighlightEntry entry = (HighlightEntry) tag; - o0 = entry.p0; - o1 = entry.p1; - - // Prevent useless write & repaint operations. - if (o0 == n0 && o1 == n1) - return; - - entry.p0 = n0; - entry.p1 = n1; - + Document doc = textComponent.getDocument(); TextUI ui = textComponent.getUI(); - - // Special situation where the old area has to be cleared simply. - if (n0 == n1) - ui.damageRange(textComponent, o0, o1); - // Calculates the areas where a change is really neccessary - else if ((o1 > n0 && o1 <= n1) - || (n1 > o0 && n1 <= o1)) + if (tag instanceof LayerHighlightEntry) { - // [fds, fde) - the first damage region - // [sds, sde] - the second damage region - int fds, sds; - int fde, sde; - - // Calculate first damaged region. - if(o0 < n0) - { - // Damaged region will be cleared as - // the old highlight region starts first. - fds = o0; - fde = n0; - } - else - { - // Damaged region will be painted as - // the new highlight region starts first. - fds = n0; - fde = o0; - } - - if (o1 < n1) + LayerHighlightEntry le = (LayerHighlightEntry) tag; + Rectangle r = le.paintRect; + if (r.width > 0 && r.height > 0) + textComponent.repaint(r.x, r.y, r.width, r.height); + r.width = 0; + r.height = 0; + le.p0 = doc.createPosition(n0); + le.p1 = doc.createPosition(n1); + ui.damageRange(textComponent, Math.min(n0, n1), Math.max(n0, n1)); + } + else if (tag instanceof HighlightEntry) + { + HighlightEntry e = (HighlightEntry) tag; + int p0 = e.getStartOffset(); + int p1 = e.getEndOffset(); + if (p0 == n0) { - // Final region will be painted as the - // old highlight region finishes first - sds = o1; - sde = n1; + ui.damageRange(textComponent, Math.min(p1, n1), + Math.max(p1, n1)); } - else + else if (n1 == p1) { - // Final region will be cleared as the - // new highlight region finishes first. - sds = n1; - sde = o1; + ui.damageRange(textComponent, Math.min(p0, n0), + Math.max(p0, n0)); } - - // If there is no undamaged region in between - // call damageRange only once. - if (fde == sds) - ui.damageRange(textComponent, fds, sde); else { - if (fds != fde) - ui.damageRange(textComponent, fds, fde); - - if (sds != sde) - ui.damageRange(textComponent, sds, sde); + ui.damageRange(textComponent, p0, p1); + ui.damageRange(textComponent, n0, n1); } + e.p0 = doc.createPosition(n0); + e.p1 = doc.createPosition(n1); } - else - { - // The two regions do not overlap. So mark - // both areas as damaged. - ui.damageRange(textComponent, o0, o1); - ui.damageRange(textComponent, n0, n1); - } - } public void paintLayeredHighlights(Graphics g, int p0, int p1, Shape viewBounds, JTextComponent editor, View view) - throws NotImplementedException { - // TODO: Implement this properly. + for (Iterator i = highlights.iterator(); i.hasNext();) + { + Object o = i.next(); + if (o instanceof LayerHighlightEntry) + { + LayerHighlightEntry entry = (LayerHighlightEntry) o; + int start = entry.getStartOffset(); + int end = entry.getEndOffset(); + if ((p0 < start && p1 > start) || (p0 >= start && p0 < end)) + entry.paintLayeredHighlight(g, p0, p1, viewBounds, editor, view); + } + } } public void paint(Graphics g) @@ -399,7 +470,9 @@ public class DefaultHighlighter extends LayeredHighlighter for (int index = 0; index < size; ++index) { HighlightEntry entry = (HighlightEntry) highlights.get(index); - entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent); + if (! (entry instanceof LayerHighlightEntry)) + entry.painter.paint(g, entry.getStartOffset(), entry.getEndOffset(), + bounds, textComponent); } } } diff --git a/javax/swing/text/DefaultStyledDocument.java b/javax/swing/text/DefaultStyledDocument.java index 8aee51e5c..5705bde17 100644 --- a/javax/swing/text/DefaultStyledDocument.java +++ b/javax/swing/text/DefaultStyledDocument.java @@ -41,7 +41,9 @@ package javax.swing.text; import java.awt.Color; import java.awt.Font; import java.io.Serializable; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.Iterator; import java.util.Stack; import java.util.Vector; @@ -424,6 +426,58 @@ public class DefaultStyledDocument extends AbstractDocument implements */ public class ElementBuffer implements Serializable { + /** + * Instance of all editing information for an object in the Vector. This class + * is used to add information to the DocumentEvent associated with an + * insertion/removal/change as well as to store the changes that need to be + * made so they can be made all at the same (appropriate) time. + */ + class Edit + { + /** The element to edit . */ + Element e; + + /** The index of the change. */ + int index; + + /** The removed elements. */ + ArrayList removed = new ArrayList(); + + /** The added elements. */ + ArrayList added = new ArrayList(); + + /** + * Indicates if this edit contains a fracture. + */ + boolean isFracture; + + /** + * Creates a new Edit for the specified element at index i. + * + * @param el the element + * @param i the index + */ + Edit(Element el, int i) + { + this(el, i, false); + } + + /** + * Creates a new Edit for the specified element at index i. + * + * @param el the element + * @param i the index + * @param frac if this is a fracture edit or not + */ + Edit(Element el, int i, boolean frac) + { + e = el; + index = i; + isFracture = frac; + } + + } + /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = 1688745877691146623L; @@ -442,11 +496,25 @@ public class DefaultStyledDocument extends AbstractDocument implements /** Holds the position of the change. */ private int pos; - /** Holds the element that was last fractured. */ - private Element lastFractured; - - /** True if a fracture was not created during a insertFracture call. */ - private boolean fracNotCreated; + /** + * The ElementChange that describes the latest changes. + */ + private DefaultDocumentEvent documentEvent; + + /** + * The parent of the fracture. + */ + private Element fracturedParent; + + /** + * The fractured child. + */ + private Element fracturedChild; + + /** + * Indicates if a fracture has been created. + */ + private boolean createdFracture; /** * The current position in the element tree. This is used for bulk inserts @@ -454,10 +522,17 @@ public class DefaultStyledDocument extends AbstractDocument implements */ private Stack elementStack; + private Edit[] insertPath; + + private boolean recreateLeafs; + /** - * The ElementChange that describes the latest changes. + * Vector that contains all the edits. Maybe replace by a HashMap. */ - DefaultDocumentEvent documentEvent; + private ArrayList edits; + + private boolean offsetLastIndex; + private boolean offsetLastIndexReplace; /** * Creates a new ElementBuffer for the specified @@ -469,7 +544,6 @@ public class DefaultStyledDocument extends AbstractDocument implements public ElementBuffer(Element root) { this.root = root; - elementStack = new Stack(); } /** @@ -495,13 +569,9 @@ public class DefaultStyledDocument extends AbstractDocument implements */ public void remove(int offs, int len, DefaultDocumentEvent ev) { - if (len == 0) - return; - offset = offs; - length = len; - pos = offset; - documentEvent = ev; + prepareEdit(offs, len); removeUpdate(); + finishEdit(ev); } /** @@ -511,109 +581,241 @@ public class DefaultStyledDocument extends AbstractDocument implements */ protected void removeUpdate() { - int startParagraph = root.getElementIndex(offset); - int endParagraph = root.getElementIndex(offset + length); - Element[] empty = new Element[0]; - int removeStart = -1; - int removeEnd = -1; - for (int i = startParagraph; i < endParagraph; i++) + removeElements(root, offset, endOffset); + } + + private boolean removeElements(Element elem, int rmOffs0, int rmOffs1) + { + boolean ret = false; + if (! elem.isLeaf()) { - BranchElement paragraph = (BranchElement) root.getElement(i); - int contentStart = paragraph.getElementIndex(offset); - int contentEnd = paragraph.getElementIndex(offset + length); - if (contentStart == paragraph.getStartOffset() - && contentEnd == paragraph.getEndOffset()) + // Update stack for changes. + int index0 = elem.getElementIndex(rmOffs0); + int index1 = elem.getElementIndex(rmOffs1); + elementStack.push(new Edit(elem, index0)); + Edit ec = (Edit) elementStack.peek(); + + // If the range is contained by one element, + // we just forward the request + if (index0 == index1) { - // In this case we only need to remove the whole paragraph. We - // do this in one go after this loop and only record the indices - // here. - if (removeStart == -1) + Element child0 = elem.getElement(index0); + if(rmOffs0 <= child0.getStartOffset() + && rmOffs1 >= child0.getEndOffset()) { - removeStart = i; - removeEnd = i; + // Element totally removed. + ec.removed.add(child0); + } + else if (removeElements(child0, rmOffs0, rmOffs1)) + { + ec.removed.add(child0); } - else - removeEnd = i; } else { - // In this case we remove a couple of child elements from this - // paragraph. - int removeLen = contentEnd - contentStart; - Element[] removed = new Element[removeLen]; - for (int j = contentStart; j < contentEnd; j++) - removed[j] = paragraph.getElement(j); - Edit edit = getEditForParagraphAndIndex(paragraph, contentStart); - edit.addRemovedElements(removed); + // The removal range spans elements. If we can join + // the two endpoints, do it. Otherwise we remove the + // interior and forward to the endpoints. + Element child0 = elem.getElement(index0); + Element child1 = elem.getElement(index1); + boolean containsOffs1 = (rmOffs1 < elem.getEndOffset()); + if (containsOffs1 && canJoin(child0, child1)) + { + // Remove and join. + for (int i = index0; i <= index1; i++) + { + ec.removed.add(elem.getElement(i)); + } + Element e = join(elem, child0, child1, rmOffs0, rmOffs1); + ec.added.add(e); + } + else + { + // Remove interior and forward. + int rmIndex0 = index0 + 1; + int rmIndex1 = index1 - 1; + if (child0.getStartOffset() == rmOffs0 + || (index0 == 0 && child0.getStartOffset() > rmOffs0 + && child0.getEndOffset() <= rmOffs1)) + { + // Start element completely consumed. + child0 = null; + rmIndex0 = index0; + } + if (! containsOffs1) + { + child1 = null; + rmIndex1++; + } + else if (child1.getStartOffset() == rmOffs1) + { + // End element not touched. + child1 = null; + } + if (rmIndex0 <= rmIndex1) + { + ec.index = rmIndex0; + } + for (int i = rmIndex0; i <= rmIndex1; i++) + { + ec.removed.add(elem.getElement(i)); + } + if (child0 != null) + { + if(removeElements(child0, rmOffs0, rmOffs1)) + { + ec.removed.add(0, child0); + ec.index = index0; + } + } + if (child1 != null) + { + if(removeElements(child1, rmOffs0, rmOffs1)) + { + ec.removed.add(child1); + } + } } + } + + // Perform changes. + pop(); + + // Return true if we no longer have any children. + if(elem.getElementCount() == (ec.removed.size() - ec.added.size())) + ret = true; } - // Now we remove paragraphs from the root that have been tagged for - // removal. - if (removeStart != -1) + return ret; + } + + private boolean canJoin(Element e0, Element e1) + { + boolean ret = false; + if ((e0 != null) && (e1 != null)) { - int removeLen = removeEnd - removeStart; - Element[] removed = new Element[removeLen]; - for (int i = removeStart; i < removeEnd; i++) - removed[i] = root.getElement(i); - Edit edit = getEditForParagraphAndIndex((BranchElement) root, - removeStart); - edit.addRemovedElements(removed); + // Don't join a leaf to a branch. + boolean isLeaf0 = e0.isLeaf(); + boolean isLeaf1 = e1.isLeaf(); + if(isLeaf0 == isLeaf1) + { + if (isLeaf0) + { + // Only join leaves if the attributes match, otherwise + // style information will be lost. + ret = e0.getAttributes().isEqual(e1.getAttributes()); + } + else + { + // Only join non-leafs if the names are equal. This may result + // in loss of style information, but this is typically + // acceptable for non-leafs. + String name0 = e0.getName(); + String name1 = e1.getName(); + if (name0 != null) + ret = name0.equals(name1); + else if (name1 != null) + ret = name1.equals(name0); + else // Both names null. + ret = true; + } + } } + return ret; } - /** - * Performs the actual work for {@link #change}. The elements at the - * interval boundaries are split up (if necessary) so that the interval - * boundaries are located at element boundaries. - */ - protected void changeUpdate() + private Element join(Element p, Element left, Element right, int rmOffs0, + int rmOffs1) { - // Split up the element at the start offset if necessary. - Element el = getCharacterElement(offset); - Element[] res = split(el, offset, 0, el.getElementIndex(offset)); - BranchElement par = (BranchElement) el.getParentElement(); - int index = par.getElementIndex(offset); - Edit edit = getEditForParagraphAndIndex(par, index); - if (res[1] != null) + Element joined = null; + if (left.isLeaf() && right.isLeaf()) + { + joined = createLeafElement(p, left.getAttributes(), + left.getStartOffset(), + right.getEndOffset()); + } + else if ((! left.isLeaf()) && (! right.isLeaf())) { - Element[] removed; - Element[] added; - if (res[0] == null) + // Join two branch elements. This copies the children before + // the removal range on the left element, and after the removal + // range on the right element. The two elements on the edge + // are joined if possible and needed. + joined = createBranchElement(p, left.getAttributes()); + int ljIndex = left.getElementIndex(rmOffs0); + int rjIndex = right.getElementIndex(rmOffs1); + Element lj = left.getElement(ljIndex); + if (lj.getStartOffset() >= rmOffs0) + { + lj = null; + } + Element rj = right.getElement(rjIndex); + if (rj.getStartOffset() == rmOffs1) + { + rj = null; + } + ArrayList children = new ArrayList(); + // Transfer the left. + for (int i = 0; i < ljIndex; i++) + { + children.add(clone(joined, left.getElement(i))); + } + + // Transfer the join/middle. + if (canJoin(lj, rj)) { - removed = new Element[0]; - added = new Element[] { res[1] }; - index++; + Element e = join(joined, lj, rj, rmOffs0, rmOffs1); + children.add(e); } else { - removed = new Element[] { el }; - added = new Element[] { res[0], res[1] }; + if (lj != null) + { + children.add(cloneAsNecessary(joined, lj, rmOffs0, rmOffs1)); + } + if (rj != null) + { + children.add(cloneAsNecessary(joined, rj, rmOffs0, rmOffs1)); + } + } + + // Transfer the right. + int n = right.getElementCount(); + for (int i = (rj == null) ? rjIndex : rjIndex + 1; i < n; i++) + { + children.add(clone(joined, right.getElement(i))); } - edit.addRemovedElements(removed); - edit.addAddedElements(added); + // Install the children. + Element[] c = new Element[children.size()]; + c = (Element[]) children.toArray(c); + ((BranchElement) joined).replace(0, 0, c); + } + else + { + assert false : "Must not happen"; } + return joined; + } - int endOffset = offset + length; - el = getCharacterElement(endOffset); - res = split(el, endOffset, 0, el.getElementIndex(endOffset)); - par = (BranchElement) el.getParentElement(); - if (res[0] != null) + /** + * Performs the actual work for {@link #change}. The elements at the + * interval boundaries are split up (if necessary) so that the interval + * boundaries are located at element boundaries. + */ + protected void changeUpdate() + { + boolean didEnd = split(offset, length); + if (! didEnd) { - Element[] removed; - Element[] added; - if (res[1] == null) - { - removed = new Element[0]; - added = new Element[] { res[1] }; - } - else + // need to do the other end + while (elementStack.size() != 0) { - removed = new Element[] { el }; - added = new Element[] { res[0], res[1] }; + pop(); } - edit.addRemovedElements(removed); - edit.addAddedElements(added); + split(offset + length, 0); + } + while (elementStack.size() != 0) + { + pop(); } } @@ -683,6 +885,39 @@ public class DefaultStyledDocument extends AbstractDocument implements return clone; } + private Element cloneAsNecessary(Element parent, Element clonee, + int rmOffs0, int rmOffs1) + { + Element cloned; + if (clonee.isLeaf()) + { + cloned = createLeafElement(parent, clonee.getAttributes(), + clonee.getStartOffset(), + clonee.getEndOffset()); + } + else + { + Element e = createBranchElement(parent, clonee.getAttributes()); + int n = clonee.getElementCount(); + ArrayList childrenList = new ArrayList(n); + for (int i = 0; i < n; i++) + { + Element elem = clonee.getElement(i); + if (elem.getStartOffset() < rmOffs0 + || elem.getEndOffset() > rmOffs1) + { + childrenList.add(cloneAsNecessary(e, elem, rmOffs0, + rmOffs1)); + } + } + Element[] children = new Element[childrenList.size()]; + children = (Element[]) childrenList.toArray(children); + ((BranchElement) e).replace(0, 0, children); + cloned = e; + } + return cloned; + } + /** * Inserts new Element in the document at the specified * position. Most of the work is done by {@link #insertUpdate}, after some @@ -701,70 +936,98 @@ public class DefaultStyledDocument extends AbstractDocument implements public void insert(int offset, int length, ElementSpec[] data, DefaultDocumentEvent ev) { - if (length == 0) - return; - + if (length > 0) + { + prepareEdit(offset, length); + insertUpdate(data); + finishEdit(ev); + } + } + + /** + * Prepares the state of this object for performing an insert. + * + * @param offset the offset at which is inserted + * @param length the length of the inserted region + */ + private void prepareEdit(int offset, int length) + { this.offset = offset; this.pos = offset; this.endOffset = offset + length; this.length = length; - documentEvent = ev; - - edits.removeAllElements(); - elementStack.removeAllElements(); - lastFractured = null; - fracNotCreated = false; - insertUpdate(data); + + if (edits == null) + edits = new ArrayList(); + else + edits.clear(); + + if (elementStack == null) + elementStack = new Stack(); + else + elementStack.clear(); + + fracturedParent = null; + fracturedChild = null; + offsetLastIndex = false; + offsetLastIndexReplace = false; + } + + /** + * Finishes an insert. This applies all changes and updates + * the DocumentEvent. + * + * @param ev the document event + */ + private void finishEdit(DefaultDocumentEvent ev) + { // This for loop applies all the changes that were made and updates the // DocumentEvent. - int size = edits.size(); - for (int i = 0; i < size; i++) - { - Edit curr = (Edit) edits.get(i); - BranchElement e = (BranchElement) curr.e; - Element[] removed = curr.getRemovedElements(); - Element[] added = curr.getAddedElements(); - // FIXME: We probably shouldn't create the empty Element[] in the - // first place. - if (removed.length > 0 || added.length > 0) - { - if (curr.index + removed.length <= e.getElementCount()) - { - e.replace(curr.index, removed.length, added); - ElementEdit ee = new ElementEdit(e, curr.index, removed, added); - ev.addEdit(ee); - } - else - { - System.err.println("WARNING: Tried to replace elements "); - System.err.print("beyond boundaries: elementCount: "); - System.err.println(e.getElementCount()); - System.err.print("index: " + curr.index); - System.err.println(", removed.length: " + removed.length); - } - } - } + for (Iterator i = edits.iterator(); i.hasNext();) + { + Edit edits = (Edit) i.next(); + Element[] removed = new Element[edits.removed.size()]; + removed = (Element[]) edits.removed.toArray(removed); + Element[] added = new Element[edits.added.size()]; + added = (Element[]) edits.added.toArray(added); + int index = edits.index; + BranchElement parent = (BranchElement) edits.e; + parent.replace(index, removed.length, added); + ElementEdit ee = new ElementEdit(parent, index, removed, added); + ev.addEdit(ee); + } } /** - * Inserts new content + * Inserts new content. * - * @param data - * the element specifications for the elements to be inserted + * @param data the element specifications for the elements to be inserted */ protected void insertUpdate(ElementSpec[] data) { - // Push the root and the paragraph at offset onto the element stack. + // Push the current path to the stack. Element current = root; - int index; - while (!current.isLeaf()) + int index = current.getElementIndex(offset); + while (! current.isLeaf()) { + Element child = current.getElement(index); + int editIndex = child.isLeaf() ? index : index + 1; + Edit edit = new Edit(current, editIndex); + elementStack.push(edit); + current = child; index = current.getElementIndex(offset); - elementStack.push(current); - current = current.getElement(index); } - + + // Create a copy of the original path. + insertPath = new Edit[elementStack.size()]; + insertPath = (Edit[]) elementStack.toArray(insertPath); + + // No fracture yet. + createdFracture = false; + + // Insert first content tag. int i = 0; + recreateLeafs = false; int type = data[0].getType(); if (type == ElementSpec.ContentType) { @@ -784,123 +1047,129 @@ public class DefaultStyledDocument extends AbstractDocument implements // Handle each ElementSpec individually. for (; i < data.length; i++) { - BranchElement paragraph = (BranchElement) elementStack.peek(); - switch (data[i].getType()) + insertElement(data[i]); + } + + // Fracture if we haven't done yet. + if (! createdFracture) + fracture(-1); + + // Pop the remaining stack. + while (elementStack.size() != 0) + pop(); + + // Offset last index if necessary. + if (offsetLastIndex && offsetLastIndexReplace) + insertPath[insertPath.length - 1].index++; + + // Make sure we havea an Edit for each path item that has a change. + for (int p = insertPath.length - 1; p >= 0; p--) + { + Edit edit = insertPath[p]; + if (edit.e == fracturedParent) + edit.added.add(fracturedChild); + if ((edit.added.size() > 0 || edit.removed.size() > 0) + && ! edits.contains(edit)) + edits.add(edit); + } + + // Remove element that would be created by an insert at 0 with + // an initial end tag. + if (offset == 0 && fracturedParent != null + && data[0].getType() == ElementSpec.EndTagType) + { + for (int p = 0; + p < data.length && data[p].getType() == ElementSpec.EndTagType; + p++) { - case ElementSpec.StartTagType: - switch (data[i].getDirection()) - { - case ElementSpec.JoinFractureDirection: - // Fracture the tree and ensure the appropriate element - // is on top of the stack. - fracNotCreated = false; - insertFracture(data[i]); - if (fracNotCreated) - { - if (lastFractured != null) - elementStack.push(lastFractured.getParentElement()); - else - elementStack.push(paragraph.getElement(0)); - } - break; - case ElementSpec.JoinNextDirection: - // Push the next paragraph element onto the stack so - // future insertions are added to it. - int ix = paragraph.getElementIndex(pos) + 1; - elementStack.push(paragraph.getElement(ix)); - break; - default: - Element br = null; - if (data.length > i + 1) - { - // leaves will be added to paragraph later - int x = 0; - if (paragraph.getElementCount() > 0) - x = paragraph.getElementIndex(pos) + 1; - Edit e = getEditForParagraphAndIndex(paragraph, x); - br = (BranchElement) createBranchElement(paragraph, - data[i].getAttributes()); - e.added.add(br); - elementStack.push(br); - } - else - // need to add leaves to paragraph now - br = insertParagraph(paragraph, pos); - break; - } - break; - case ElementSpec.EndTagType: - elementStack.pop(); - break; - case ElementSpec.ContentType: - insertContentTag(data[i]); - offset = pos; - break; + Edit edit = insertPath[insertPath.length - p - 1]; + edit.index--; + edit.removed.add(0, edit.e.getElement(edit.index)); } } } - - /** - * Inserts a new paragraph. - * - * @param par - - * the parent - * @param offset - - * the offset - * @return the new paragraph - */ - private Element insertParagraph(BranchElement par, int offset) + + private void pop() + { + Edit edit = (Edit) elementStack.peek(); + elementStack.pop(); + if ((edit.added.size() > 0) || (edit.removed.size() > 0)) + { + edits.add(edit); + } + else if (! elementStack.isEmpty()) + { + Element e = edit.e; + if (e.getElementCount() == 0) + { + // If we pushed a branch element that didn't get + // used, make sure its not marked as having been added. + edit = (Edit) elementStack.peek(); + edit.added.remove(e); + } + } + } + + private void insertElement(ElementSpec spec) { - int index = par.getElementIndex(offset); - Element current = par.getElement(index); - Element[] res = split(current, offset, 0, 0); - Edit e = getEditForParagraphAndIndex(par, index + 1); - Element ret; - if (res[1] != null) + Edit edit = (Edit) elementStack.peek(); + switch (spec.getType()) { - Element[] removed; - Element[] added; - if (res[0] == null) + case ElementSpec.StartTagType: + switch (spec.getDirection()) { - removed = new Element[0]; - if (res[1] instanceof BranchElement) + case ElementSpec.JoinFractureDirection: + // Fracture the tree and ensure the appropriate element + // is on top of the stack. + if (! createdFracture) { - added = new Element[] { res[1] }; - ret = res[1]; + fracture(elementStack.size() - 1); } - else + if (! edit.isFracture) { - ret = createBranchElement(par, null); - added = new Element[] { ret, res[1] }; + // If the parent isn't a fracture, then the fracture is + // in fracturedChild. + Edit newEdit = new Edit(fracturedChild, 0, true); + elementStack.push(newEdit); } - index++; - } - else - { - removed = new Element[] { current }; - if (res[1] instanceof BranchElement) + else { - ret = res[1]; - added = new Element[] { res[0], res[1] }; + // Otherwise use the parent's first child. + Element el = edit.e.getElement(0); + Edit newEdit = new Edit(el, 0, true); + elementStack.push(newEdit); } - else + break; + case ElementSpec.JoinNextDirection: + // Push the next paragraph element onto the stack so + // future insertions are added to it. + Element parent = edit.e.getElement(edit.index); + if (parent.isLeaf()) { - ret = createBranchElement(par, null); - added = new Element[] { res[0], ret, res[1] }; + if (edit.index + 1 < edit.e.getElementCount()) + parent = edit.e.getElement(edit.index + 1); + else + assert false; // Must not happen. } + elementStack.push(new Edit(parent, 0, true)); + break; + default: + Element branch = createBranchElement(edit.e, + spec.getAttributes()); + edit.added.add(branch); + elementStack.push(new Edit(branch, 0)); + break; } - - e.addAddedElements(added); - e.addRemovedElements(removed); - } - else - { - ret = createBranchElement(par, null); - e.addAddedElement(ret); + break; + case ElementSpec.EndTagType: + pop(); + break; + case ElementSpec.ContentType: + insertContentTag(spec, edit); + break; } - return ret; } - + /** * Inserts the first tag into the document. * @@ -910,67 +1179,71 @@ public class DefaultStyledDocument extends AbstractDocument implements private void insertFirstContentTag(ElementSpec[] data) { ElementSpec first = data[0]; - BranchElement paragraph = (BranchElement) elementStack.peek(); - int index = paragraph.getElementIndex(pos); - Element current = paragraph.getElement(index); - int newEndOffset = pos + first.length; + Edit edit = (Edit) elementStack.peek(); + Element current = edit.e.getElement(edit.index); + int firstEndOffset = offset + first.length; boolean onlyContent = data.length == 1; - Edit edit = getEditForParagraphAndIndex(paragraph, index); switch (first.getDirection()) { case ElementSpec.JoinPreviousDirection: - if (current.getEndOffset() != newEndOffset && !onlyContent) + if (current.getEndOffset() != firstEndOffset && ! onlyContent) { - Element newEl1 = createLeafElement(paragraph, + Element newEl1 = createLeafElement(edit.e, current.getAttributes(), current.getStartOffset(), - newEndOffset); - edit.addAddedElement(newEl1); - edit.addRemovedElement(current); - offset = newEndOffset; + firstEndOffset); + edit.added.add(newEl1); + edit.removed.add(current); + if (current.getEndOffset() != endOffset) + recreateLeafs = true; + else + offsetLastIndex = true; + } + else + { + offsetLastIndex = true; + offsetLastIndexReplace = true; } break; case ElementSpec.JoinNextDirection: - if (pos != 0) + if (offset != 0) { - Element newEl1 = createLeafElement(paragraph, + Element newEl1 = createLeafElement(edit.e, current.getAttributes(), current.getStartOffset(), - pos); - edit.addAddedElement(newEl1); - Element next = paragraph.getElement(index + 1); - + offset); + edit.added.add(newEl1); + Element next = edit.e.getElement(edit.index + 1); if (onlyContent) - newEl1 = createLeafElement(paragraph, next.getAttributes(), - pos, next.getEndOffset()); + newEl1 = createLeafElement(edit.e, next.getAttributes(), + offset, next.getEndOffset()); else { - newEl1 = createLeafElement(paragraph, next.getAttributes(), - pos, newEndOffset); - pos = newEndOffset; + newEl1 = createLeafElement(edit.e, next.getAttributes(), + offset, firstEndOffset); } - edit.addAddedElement(newEl1); - edit.addRemovedElement(current); - edit.addRemovedElement(next); + edit.added.add(newEl1); + edit.removed.add(current); + edit.removed.add(next); } break; - default: - if (current.getStartOffset() != pos) + default: // OriginateDirection. + if (current.getStartOffset() != offset) { - Element newEl = createLeafElement(paragraph, + Element newEl = createLeafElement(edit.e, current.getAttributes(), current.getStartOffset(), - pos); - edit.addAddedElement(newEl); + offset); + edit.added.add(newEl); } - edit.addRemovedElement(current); - Element newEl1 = createLeafElement(paragraph, first.getAttributes(), - pos, newEndOffset); - edit.addAddedElement(newEl1); + edit.removed.add(current); + Element newEl1 = createLeafElement(edit.e, first.getAttributes(), + offset, firstEndOffset); + edit.added.add(newEl1); if (current.getEndOffset() != endOffset) - recreateLeaves(newEndOffset, paragraph, onlyContent); + recreateLeafs = true; else - offset = newEndOffset; + offsetLastIndex = true; break; } } @@ -981,391 +1254,353 @@ public class DefaultStyledDocument extends AbstractDocument implements * @param tag - * the element spec */ - private void insertContentTag(ElementSpec tag) + private void insertContentTag(ElementSpec tag, Edit edit) { - BranchElement paragraph = (BranchElement) elementStack.peek(); int len = tag.getLength(); int dir = tag.getDirection(); AttributeSet tagAtts = tag.getAttributes(); if (dir == ElementSpec.JoinNextDirection) { - int index = paragraph.getElementIndex(pos); - Element target = paragraph.getElement(index); - Edit edit = getEditForParagraphAndIndex(paragraph, index); - - if (paragraph.getStartOffset() > pos) - { - Element first = paragraph.getElement(0); - Element newEl = createLeafElement(paragraph, - first.getAttributes(), pos, - first.getEndOffset()); - edit.addAddedElement(newEl); - edit.addRemovedElement(first); - } - else if (paragraph.getElementCount() > (index + 1) - && (pos == target.getStartOffset() && !target.equals(lastFractured))) + if (! edit.isFracture) { - Element next = paragraph.getElement(index + 1); - Element newEl = createLeafElement(paragraph, - next.getAttributes(), pos, - next.getEndOffset()); - edit.addAddedElement(newEl); - edit.addRemovedElement(next); - edit.addRemovedElement(target); + Element first = null; + if (insertPath != null) + { + for (int p = insertPath.length - 1; p >= 0; p--) + { + if (insertPath[p] == edit) + { + if (p != insertPath.length - 1) + first = edit.e.getElement(edit.index); + break; + } + } + } + if (first == null) + first = edit.e.getElement(edit.index + 1); + Element leaf = createLeafElement(edit.e, first.getAttributes(), + pos, first.getEndOffset()); + edit.added.add(leaf); + edit.removed.add(first); } else { - BranchElement parent = (BranchElement) paragraph.getParentElement(); - int i = parent.getElementIndex(pos); - BranchElement next = (BranchElement) parent.getElement(i + 1); - AttributeSet atts = tag.getAttributes(); - - if (next != null) - { - Element nextLeaf = next.getElement(0); - Edit e = getEditForParagraphAndIndex(next, 0); - Element newEl2 = createLeafElement(next, atts, pos, nextLeaf.getEndOffset()); - e.addAddedElement(newEl2); - e.addRemovedElement(nextLeaf); - } + Element first = edit.e.getElement(0); + Element leaf = createLeafElement(edit.e, first.getAttributes(), + pos, first.getEndOffset()); + edit.added.add(leaf); + edit.removed.add(first); } } else { - int end = pos + len; - Element leaf = createLeafElement(paragraph, tag.getAttributes(), pos, end); - - // Check for overlap with other leaves/branches - if (paragraph.getElementCount() > 0) - { - int index = paragraph.getElementIndex(pos); - Element target = paragraph.getElement(index); - boolean onlyContent = target.isLeaf(); - - BranchElement toRec = paragraph; - if (!onlyContent) - toRec = (BranchElement) target; - - // Check if we should place the leaf before or after target - if (pos > target.getStartOffset()) - index++; - - Edit edit = getEditForParagraphAndIndex(paragraph, index); - edit.addAddedElement(leaf); - } - else - paragraph.replace(0, 0, new Element[] { leaf }); + Element leaf = createLeafElement(edit.e, tag.getAttributes(), pos, + pos + len); + edit.added.add(leaf); } - + pos += len; + } /** - * This method fractures the child at offset. + * This method fractures bottomost leaf in the elementStack. This + * happens when the first inserted tag is not content. * * @param data * the ElementSpecs used for the entire insertion */ private void createFracture(ElementSpec[] data) { - BranchElement paragraph = (BranchElement) elementStack.peek(); - int index = paragraph.getElementIndex(offset); - Element child = paragraph.getElement(index); - Edit edit = getEditForParagraphAndIndex(paragraph, index); - AttributeSet atts = child.getAttributes(); - + Edit edit = (Edit) elementStack.peek(); + Element child = edit.e.getElement(edit.index); if (offset != 0) { - Element newEl1 = createLeafElement(paragraph, atts, - child.getStartOffset(), offset); - edit.addAddedElement(newEl1); - edit.addRemovedElement(child); + Element newChild = createLeafElement(edit.e, child.getAttributes(), + child.getStartOffset(), offset); + edit.added.add(newChild); } + edit.removed.add(child); + if (child.getEndOffset() != endOffset) + recreateLeafs = true; + else + offsetLastIndex = true; } - /** - * Recreates a specified part of a the tree after a new leaf - * has been inserted. - * - * @param start - where to start recreating from - * @param paragraph - the paragraph to recreate - * @param onlyContent - true if this is the only content - */ - private void recreateLeaves(int start, BranchElement paragraph, boolean onlyContent) + private void fracture(int depth) { - int index = paragraph.getElementIndex(start); - Element child = paragraph.getElement(index); - AttributeSet atts = child.getAttributes(); - - if (!onlyContent) + int len = insertPath.length; + int lastIndex = -1; + boolean recreate = recreateLeafs; + Edit lastEdit = insertPath[len - 1]; + boolean childChanged = lastEdit.index + 1 < lastEdit.e.getElementCount(); + int deepestChangedIndex = recreate ? len : - 1; + int lastChangedIndex = len - 1; + createdFracture = true; + for (int i = len - 2; i >= 0; i--) { - BranchElement newBranch = (BranchElement) createBranchElement(paragraph, - atts); - Element newLeaf = createLeafElement(newBranch, atts, start, - child.getEndOffset()); - newBranch.replace(0, 0, new Element[] { newLeaf }); - - BranchElement parent = (BranchElement) paragraph.getParentElement(); - int parSize = parent.getElementCount(); - Edit edit = getEditForParagraphAndIndex(parent, parSize); - edit.addAddedElement(newBranch); - - int paragraphSize = paragraph.getElementCount(); - Element[] removed = new Element[paragraphSize - (index + 1)]; - int s = 0; - for (int j = index + 1; j < paragraphSize; j++) - removed[s++] = paragraph.getElement(j); - - edit = getEditForParagraphAndIndex(paragraph, index); - edit.addRemovedElements(removed); - Element[] added = recreateAfterFracture(removed, newBranch, 0, child.getEndOffset()); - newBranch.replace(1, 0, added); - - lastFractured = newLeaf; - pos = newBranch.getEndOffset(); + Edit edit = insertPath[i]; + if (edit.added.size() > 0 || i == depth) + { + lastIndex = i; + if (! recreate && childChanged) + { + recreate = true; + if (deepestChangedIndex == -1) + deepestChangedIndex = lastChangedIndex + 1; + } + } + if (! childChanged && edit.index < edit.e.getElementCount()) + { + childChanged = true; + lastChangedIndex = i; + } } - else + if (recreate) { - Element newLeaf = createLeafElement(paragraph, atts, start, - child.getEndOffset()); - Edit edit = getEditForParagraphAndIndex(paragraph, index); - edit.addAddedElement(newLeaf); + if (lastIndex == -1) + lastIndex = len - 1; + recreate(lastIndex, deepestChangedIndex); } } - - /** - * Splits an element if offset is not already at its - * boundary. - * - * @param el - * the Element to possibly split - * @param offset - * the offset at which to possibly split - * @param space - * the amount of space to create between the splitted parts - * @param editIndex - * the index of the edit to use - * @return An array of elements which represent the split result. This array - * has two elements, the two parts of the split. The first element - * might be null, which means that the element which should be - * splitted can remain in place. The second element might also be - * null, which means that the offset is already at an element - * boundary and the element doesn't need to be splitted. - */ - private Element[] split(Element el, int offset, int space, int editIndex) + + private void recreate(int startIndex, int endIndex) { - // If we are at an element boundary, then return an empty array. - if ((offset == el.getStartOffset() || offset == el.getEndOffset()) - && space == 0 && el.isLeaf()) - return new Element[2]; - - // If the element is an instance of BranchElement, then we - // recursivly - // call this method to perform the split. - Element[] res = new Element[2]; - if (el instanceof BranchElement) + // Recreate the element representing the inserted index. + Edit edit = insertPath[startIndex]; + Element child; + Element newChild; + int changeLength = insertPath.length; + + if (startIndex + 1 == changeLength) + child = edit.e.getElement(edit.index); + else + child = edit.e.getElement(edit.index - 1); + + if(child.isLeaf()) { - int index = el.getElementIndex(offset); - Element child = el.getElement(index); - Element[] result = split(child, offset, space, editIndex); - Element[] removed; - Element[] added; - Element[] newAdded; - - int count = el.getElementCount(); - if (result[1] != null) - { - // This is the case when we can keep the first element. - if (result[0] == null) - { - removed = new Element[count - index - 1]; - newAdded = new Element[count - index - 1]; - added = new Element[] {}; + newChild = createLeafElement(edit.e, child.getAttributes(), + Math.max(endOffset, child.getStartOffset()), + child.getEndOffset()); + } + else + { + newChild = createBranchElement(edit.e, child.getAttributes()); + } + fracturedParent = edit.e; + fracturedChild = newChild; - } - // This is the case when we may not keep the first - // element. + // Recreate all the elements to the right of the insertion point. + Element parent = newChild; + while (++startIndex < endIndex) + { + boolean isEnd = (startIndex + 1) == endIndex; + boolean isEndLeaf = (startIndex + 1) == changeLength; + + // Create the newChild, a duplicate of the elment at + // index. This isn't done if isEnd and offsetLastIndex are true + // indicating a join previous was done. + edit = insertPath[startIndex]; + + // Determine the child to duplicate, won't have to duplicate + // if at end of fracture, or offseting index. + if(isEnd) + { + if(offsetLastIndex || ! isEndLeaf) + child = null; else + child = edit.e.getElement(edit.index); + } + else + { + child = edit.e.getElement(edit.index - 1); + } + + // Duplicate it. + if(child != null) + { + if(child.isLeaf()) { - removed = new Element[count - index]; - newAdded = new Element[count - index]; - added = new Element[] { result[0] }; + newChild = createLeafElement(parent, child.getAttributes(), + Math.max(endOffset, child.getStartOffset()), + child.getEndOffset()); } - newAdded[0] = result[1]; - for (int i = index; i < count; i++) + else { - Element el2 = el.getElement(i); - int ind = i - count + removed.length; - removed[ind] = el2; - if (ind != 0) - newAdded[ind] = el2; + newChild = createBranchElement(parent, + child.getAttributes()); } - - Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex); - edit.addRemovedElements(removed); - edit.addAddedElements(added); - - BranchElement newPar = - (BranchElement) createBranchElement(el.getParentElement(), - el.getAttributes()); - newPar.replace(0, 0, newAdded); - res = new Element[] { null, newPar }; } else - { - removed = new Element[count - index]; - for (int i = index; i < count; ++i) - removed[i - index] = el.getElement(i); - - Edit edit = getEditForParagraphAndIndex((BranchElement) el, editIndex); - edit.addRemovedElements(removed); - - BranchElement newPar = (BranchElement) createBranchElement(el.getParentElement(), - el.getAttributes()); - newPar.replace(0, 0, removed); - res = new Element[] { null, newPar }; + newChild = null; + + // Recreate the remaining children (there may be none). + int childrenToMove = edit.e.getElementCount() - edit.index; + Element[] children; + int moveStartIndex; + int childStartIndex = 1; + + if (newChild == null) + { + // Last part of fracture. + if (isEndLeaf) + { + childrenToMove--; + moveStartIndex = edit.index + 1; + } + else + { + moveStartIndex = edit.index; + } + childStartIndex = 0; + children = new Element[childrenToMove]; + } + else + { + if (! isEnd) + { + // Branch. + childrenToMove++; + moveStartIndex = edit.index; } + else + { + // Last leaf, need to recreate part of it. + moveStartIndex = edit.index + 1; + } + children = new Element[childrenToMove]; + children[0] = newChild; } - else if (el instanceof LeafElement) - { - BranchElement par = (BranchElement) el.getParentElement(); - Element el1 = createLeafElement(par, el.getAttributes(), - el.getStartOffset(), offset); - - Element el2 = createLeafElement(par, el.getAttributes(), - offset + space, - el.getEndOffset()); - res = new Element[] { el1, el2 }; - } - return res; + + for (int c = childStartIndex; c < childrenToMove; c++) + { + Element toMove = edit.e.getElement(moveStartIndex++); + children[c] = recreateFracturedElement(parent, toMove); + edit.removed.add(toMove); + } + ((BranchElement) parent).replace(0, 0, children); + parent = newChild; + } + } - /** - * Inserts a fracture into the document structure. - * - * @param tag - - * the element spec. - */ - private void insertFracture(ElementSpec tag) + private Element recreateFracturedElement(Element parent, Element toCopy) { - // insert the fracture at offset. - BranchElement parent = (BranchElement) elementStack.peek(); - int parentIndex = parent.getElementIndex(pos); - AttributeSet parentAtts = parent.getAttributes(); - Element toFracture = parent.getElement(parentIndex); - int parSize = parent.getElementCount(); - Edit edit = getEditForParagraphAndIndex(parent, parentIndex); - Element frac = toFracture; - int leftIns = 0; - int indexOfFrac = toFracture.getElementIndex(pos); - int size = toFracture.getElementCount(); - - // gets the leaf that falls along the fracture - frac = toFracture.getElement(indexOfFrac); - while (!frac.isLeaf()) - frac = frac.getElement(frac.getElementIndex(pos)); - - AttributeSet atts = frac.getAttributes(); - int fracStart = frac.getStartOffset(); - int fracEnd = frac.getEndOffset(); - if (pos >= fracStart && pos < fracEnd) + Element recreated; + if(toCopy.isLeaf()) { - // recreate left-side of branch and all its children before offset - // add the fractured leaves to the right branch - BranchElement rightBranch = - (BranchElement) createBranchElement(parent, parentAtts); - - // Check if left branch has already been edited. If so, we only - // need to create the right branch. - BranchElement leftBranch = null; - Element[] added = null; - if (edit.added.size() > 0 || edit.removed.size() > 0) + recreated = createLeafElement(parent, toCopy.getAttributes(), + Math.max(toCopy.getStartOffset(), endOffset), + toCopy.getEndOffset()); + } + else + { + Element newParent = createBranchElement(parent, + toCopy.getAttributes()); + int childCount = toCopy.getElementCount(); + Element[] newChildren = new Element[childCount]; + for (int i = 0; i < childCount; i++) { - added = new Element[] { rightBranch }; - - // don't try to remove left part of tree - parentIndex++; + newChildren[i] = recreateFracturedElement(newParent, + toCopy.getElement(i)); } - else - { - leftBranch = - (BranchElement) createBranchElement(parent, parentAtts); - added = new Element[] { leftBranch, rightBranch }; + ((BranchElement) newParent).replace(0, 0, newChildren); + recreated = newParent; + } + return recreated; + } - // add fracture to leftBranch - if (fracStart != pos) - { - Element leftFracturedLeaf = - createLeafElement(leftBranch, atts, fracStart, pos); - leftBranch.replace(leftIns, 0, - new Element[] { leftFracturedLeaf }); - } - } + private boolean split(int offs, int len) + { + boolean splitEnd = false; + // Push the path to the stack. + Element e = root; + int index = e.getElementIndex(offs); + while (! e.isLeaf()) + { + elementStack.push(new Edit(e, index)); + e = e.getElement(index); + index = e.getElementIndex(offs); + } - if (!toFracture.isLeaf()) + Edit ec = (Edit) elementStack.peek(); + Element child = ec.e.getElement(ec.index); + // Make sure there is something to do. If the + // offset is already at a boundary then there is + // nothing to do. + if (child.getStartOffset() < offs && offs < child.getEndOffset()) + { + // We need to split, now see if the other end is within + // the same parent. + int index0 = ec.index; + int index1 = index0; + if (((offs + len) < ec.e.getEndOffset()) && (len != 0)) { - // add all non-fracture elements to the branches - if (indexOfFrac > 0 && leftBranch != null) + // It's a range split in the same parent. + index1 = ec.e.getElementIndex(offs+len); + if (index1 == index0) { - Element[] add = new Element[indexOfFrac]; - for (int i = 0; i < indexOfFrac; i++) - add[i] = toFracture.getElement(i); - leftIns = add.length; - leftBranch.replace(0, 0, add); + // It's a three-way split. + ec.removed.add(child); + e = createLeafElement(ec.e, child.getAttributes(), + child.getStartOffset(), offs); + ec.added.add(e); + e = createLeafElement(ec.e, child.getAttributes(), + offs, offs + len); + ec.added.add(e); + e = createLeafElement(ec.e, child.getAttributes(), + offs + len, child.getEndOffset()); + ec.added.add(e); + return true; } - - int count = size - indexOfFrac - 1; - if (count > 0) + else { - Element[] add = new Element[count]; - int j = 0; - int i = indexOfFrac + 1; - while (j < count) - add[j++] = toFracture.getElement(i++); - rightBranch.replace(0, 0, add); + child = ec.e.getElement(index1); + if ((offs + len) == child.getStartOffset()) + { + // End is already on a boundary. + index1 = index0; + } } + splitEnd = true; } - - // add to fracture to rightBranch - // Check if we can join the right frac leaf with the next leaf - int rm = 0; - int end = fracEnd; - Element next = rightBranch.getElement(0); - if (next != null && next.isLeaf() - && next.getAttributes().isEqual(atts)) + + // Split the first location. + pos = offs; + child = ec.e.getElement(index0); + ec.removed.add(child); + e = createLeafElement(ec.e, child.getAttributes(), + child.getStartOffset(), pos); + ec.added.add(e); + e = createLeafElement(ec.e, child.getAttributes(), + pos, child.getEndOffset()); + ec.added.add(e); + + // Pick up things in the middle. + for (int i = index0 + 1; i < index1; i++) { - end = next.getEndOffset(); - rm = 1; + child = ec.e.getElement(i); + ec.removed.add(child); + ec.added.add(child); } - Element rightFracturedLeaf = createLeafElement(rightBranch, atts, - pos, end); - rightBranch.replace(0, rm, new Element[] { rightFracturedLeaf }); - - // recreate those elements after parentIndex and add/remove all - // new/old elements to parent - int remove = parSize - parentIndex; - Element[] removed = new Element[0]; - Element[] added2 = new Element[0]; - if (remove > 0) + if (index1 != index0) { - removed = new Element[remove]; - int s = 0; - for (int j = parentIndex; j < parSize; j++) - removed[s++] = parent.getElement(j); - edit.addRemovedElements(removed); - added2 = recreateAfterFracture(removed, parent, 1, - rightBranch.getEndOffset()); + child = ec.e.getElement(index1); + pos = offs + len; + ec.removed.add(child); + e = createLeafElement(ec.e, child.getAttributes(), + child.getStartOffset(), pos); + ec.added.add(e); + e = createLeafElement(ec.e, child.getAttributes(), + pos, child.getEndOffset()); + + ec.added.add(e); } - - edit.addAddedElements(added); - edit.addAddedElements(added2); - elementStack.push(rightBranch); - lastFractured = rightFracturedLeaf; } - else - fracNotCreated = true; + return splitEnd; + } /** @@ -1420,190 +1655,6 @@ public class DefaultStyledDocument extends AbstractDocument implements } } - /** - * This method looks through the Vector of Edits to see if there is already an - * Edit object associated with the given paragraph. If there is, then we - * return it. Otherwise we create a new Edit object, add it to the vector, and - * return it. Note: this method is package private to avoid accessors. - * - * @param index - * the index associated with the Edit we want to create - * @param para - * the paragraph associated with the Edit we want - * @return the found or created Edit object - */ - Edit getEditForParagraphAndIndex(BranchElement para, int index) - { - Edit curr; - int size = edits.size(); - for (int i = 0; i < size; i++) - { - curr = (Edit) edits.elementAt(i); - if (curr.e.equals(para)) - return curr; - } - curr = new Edit(para, index, null, null); - edits.add(curr); - - return curr; - } - /** - * Instance of all editing information for an object in the Vector. This class - * is used to add information to the DocumentEvent associated with an - * insertion/removal/change as well as to store the changes that need to be - * made so they can be made all at the same (appropriate) time. - */ - class Edit - { - /** The element to edit . */ - Element e; - - /** The index of the change. */ - int index; - - /** The removed elements. */ - Vector removed = new Vector(); - - /** The added elements. */ - Vector added = new Vector(); - - /** - * Return an array containing the Elements that have been removed from the - * paragraph associated with this Edit. - * - * @return an array of removed Elements - */ - public Element[] getRemovedElements() - { - int size = removed.size(); - Element[] removedElements = new Element[size]; - for (int i = 0; i < size; i++) - removedElements[i] = (Element) removed.elementAt(i); - return removedElements; - } - - /** - * Return an array containing the Elements that have been added to the - * paragraph associated with this Edit. - * - * @return an array of added Elements - */ - public Element[] getAddedElements() - { - int size = added.size(); - Element[] addedElements = new Element[size]; - for (int i = 0; i < size; i++) - addedElements[i] = (Element) added.elementAt(i); - return addedElements; - } - - /** - * Checks if e is already in the vector. - * - * @param e - the Element to look for - * @param v - the vector to search - * @return true if e is in v. - */ - private boolean contains(Vector v, Element e) - { - if (e == null) - return false; - - int i = v.size(); - for (int j = 0; j < i; j++) - { - Element e1 = (Element) v.get(j); - if ((e1 != null) && (e1.getAttributes().isEqual(e.getAttributes())) - && (e1.getName().equals(e.getName())) - && (e1.getStartOffset() == e.getStartOffset()) - && (e1.getEndOffset() == e.getEndOffset()) - && (e1.getParentElement().equals(e.getParentElement())) - && (e1.getElementCount() == e.getElementCount())) - return true; - } - return false; - } - - /** - * Adds one Element to the vector of removed Elements. - * - * @param e - * the Element to add - */ - public void addRemovedElement(Element e) - { - if (!contains(removed, e)) - removed.add(e); - } - - /** - * Adds each Element in the given array to the vector of removed Elements - * - * @param e - * the array containing the Elements to be added - */ - public void addRemovedElements(Element[] e) - { - if (e == null || e.length == 0) - return; - for (int i = 0; i < e.length; i++) - { - if (!contains(removed, e[i])) - removed.add(e[i]); - } - } - - /** - * Adds one Element to the vector of added Elements. - * - * @param e - * the Element to add - */ - public void addAddedElement(Element e) - { - if (!contains(added, e)) - added.add(e); - } - - /** - * Adds each Element in the given array to the vector of added Elements. - * - * @param e - * the array containing the Elements to be added - */ - public void addAddedElements(Element[] e) - { - if (e == null || e.length == 0) - return; - for (int i = 0; i < e.length; i++) - { - if (!contains(added, e[i])) - added.add(e[i]); - } - } - - /** - * Creates a new Edit object with the given parameters - * - * @param e - * the paragraph Element associated with this Edit - * @param i - * the index within the paragraph where changes are started - * @param removed - * an array containing Elements that should be removed from the - * paragraph Element - * @param added - * an array containing Elements that should be added to the - * paragraph Element - */ - public Edit(Element e, int i, Element[] removed, Element[] added) - { - this.e = e; - this.index = i; - addRemovedElements(removed); - addAddedElements(added); - } - } /** * An element type for sections. This is a simple BranchElement with a unique @@ -1673,11 +1724,6 @@ public class DefaultStyledDocument extends AbstractDocument implements */ private StyleChangeListener styleChangeListener; - /** - * Vector that contains all the edits. Maybe replace by a HashMap. - */ - Vector edits = new Vector(); - /** * Creates a new DefaultStyledDocument. */ @@ -2079,147 +2125,220 @@ public class DefaultStyledDocument extends AbstractDocument implements */ protected void insertUpdate(DefaultDocumentEvent ev, AttributeSet attr) { - super.insertUpdate(ev, attr); - // If the attribute set is null, use an empty attribute set. + int offs = ev.getOffset(); + int len = ev.getLength(); + int endOffs = offs + len; if (attr == null) attr = SimpleAttributeSet.EMPTY; - int offset = ev.getOffset(); - int length = ev.getLength(); - int endOffset = offset + length; - AttributeSet paragraphAttributes = getParagraphElement(endOffset).getAttributes(); - Segment txt = new Segment(); + + // Paragraph attributes are fetched from the point _after_ the insertion. + Element paragraph = getParagraphElement(endOffs); + AttributeSet pAttr = paragraph.getAttributes(); + // Character attributes are fetched from the actual insertion point. + Element paragraph2 = getParagraphElement(offs); + int contIndex = paragraph2.getElementIndex(offs); + Element content = paragraph2.getElement(contIndex); + AttributeSet cAttr = content.getAttributes(); + + boolean insertAtBoundary = content.getEndOffset() == endOffs; try { - getText(offset, length, txt); - } - catch (BadLocationException ex) - { - AssertionError ae = new AssertionError("Unexpected bad location"); - ae.initCause(ex); - throw ae; - } + Segment s = new Segment(); + ArrayList buf = new ArrayList(); + ElementSpec lastStartTag = null; + boolean insertAfterNewline = false; + short lastStartDir = ElementSpec.OriginateDirection; + + // Special handle if we are inserting after a newline. + if (offs > 0) + { + getText(offs - 1, 1, s); + if (s.array[s.offset] == '\n') + { + insertAfterNewline = true; + lastStartDir = insertAfterNewline(paragraph, paragraph2, + pAttr, buf, offs, + endOffs); + // Search last start tag. + for (int i = buf.size() - 1; i >= 0 && lastStartTag == null; + i--) + { + ElementSpec tag = (ElementSpec) buf.get(i); + if (tag.getType() == ElementSpec.StartTagType) + { + lastStartTag = tag; + } + } + } - int len = 0; - Vector specs = new Vector(); - ElementSpec finalStartTag = null; - short finalStartDirection = ElementSpec.OriginateDirection; - boolean prevCharWasNewline = false; - Element prev = getCharacterElement(offset); - Element next = getCharacterElement(endOffset); - Element prevParagraph = getParagraphElement(offset); - Element paragraph = getParagraphElement(endOffset); + } - int segmentEnd = txt.offset + txt.count; + // If we are not inserting after a newline, the paragraph attributes + // come from the paragraph under the insertion point. + if (! insertAfterNewline) + pAttr = paragraph2.getAttributes(); - // Check to see if we're inserting immediately after a newline. - if (offset > 0) - { - try + // Scan text and build up the specs. + getText(offs, len, s); + int end = s.offset + s.count; + int last = s.offset; + for (int i = s.offset; i < end; i++) { - String s = getText(offset - 1, 1); - if (s.equals("\n")) + if (s.array[i] == '\n') { - finalStartDirection = handleInsertAfterNewline(specs, offset, - endOffset, - prevParagraph, - paragraph, - paragraphAttributes); - - prevCharWasNewline = true; - // Find the final start tag from the ones just created. - for (int i = 0; i < specs.size(); i++) - if (((ElementSpec) specs.get(i)).getType() == ElementSpec.StartTagType) - finalStartTag = (ElementSpec) specs.get(i); + int breakOffs = i + 1; + buf.add(new ElementSpec(attr, ElementSpec.ContentType, + breakOffs - last)); + buf.add(new ElementSpec(null, ElementSpec.EndTagType)); + lastStartTag = new ElementSpec(pAttr, + ElementSpec.StartTagType); + buf.add(lastStartTag); + last = breakOffs; } } - catch (BadLocationException ble) + + // Need to add a tailing content tag if we didn't finish at a boundary. + if (last < end) { - // This shouldn't happen. - AssertionError ae = new AssertionError(); - ae.initCause(ble); - throw ae; + buf.add(new ElementSpec(attr, ElementSpec.ContentType, + end - last)); } - } - for (int i = txt.offset; i < segmentEnd; ++i) - { - len++; - if (txt.array[i] == '\n') + // Now we need to fix up the directions of the specs. + ElementSpec first = (ElementSpec) buf.get(0); + int doclen = getLength(); + + // Maybe join-previous the first tag if it is content and has + // the same attributes as the previous character run. + if (first.getType() == ElementSpec.ContentType && cAttr.isEqual(attr)) + first.setDirection(ElementSpec.JoinPreviousDirection); + + // Join-fracture or join-next the last start tag if necessary. + if (lastStartTag != null) + { + if (insertAfterNewline) + lastStartTag.setDirection(lastStartDir); + else if (paragraph2.getEndOffset() != endOffs) + lastStartTag.setDirection(ElementSpec.JoinFractureDirection); + else + { + Element par = paragraph2.getParentElement(); + int par2Index = par.getElementIndex(offs); + if (par2Index + 1 < par.getElementCount() + && ! par.getElement(par2Index + 1).isLeaf()) + lastStartTag.setDirection(ElementSpec.JoinNextDirection); + } + } + + // Join-next last tag if possible. + if (insertAtBoundary && endOffs < doclen) { - // Add the ElementSpec for the content. - specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); - - // Add ElementSpecs for the newline. - specs.add(new ElementSpec(null, ElementSpec.EndTagType)); - finalStartTag = new ElementSpec(paragraphAttributes, - ElementSpec.StartTagType); - specs.add(finalStartTag); - len = 0; + ElementSpec lastTag = (ElementSpec) buf.get(buf.size() - 1); + if (lastTag.getType() == ElementSpec.ContentType + && ((lastStartTag == null + && (paragraph == paragraph2 || insertAfterNewline)) + || (lastStartTag != null + && lastStartTag.getDirection() != ElementSpec.OriginateDirection))) + { + int nextIndex = paragraph.getElementIndex(endOffs); + Element nextRun = paragraph.getElement(nextIndex); + if (nextRun.isLeaf() && attr.isEqual(nextRun.getAttributes())) + lastTag.setDirection(ElementSpec.JoinNextDirection); + } + } + + else if (! insertAtBoundary && lastStartTag != null + && lastStartTag.getDirection() == ElementSpec.JoinFractureDirection) + { + ElementSpec lastTag = (ElementSpec) buf.get(buf.size() - 1); + if (lastTag.getType() == ElementSpec.ContentType + && lastTag.getDirection() != ElementSpec.JoinPreviousDirection + && attr.isEqual(cAttr)) + { + lastTag.setDirection(ElementSpec.JoinNextDirection); + } } - } - // Create last element if last character hasn't been a newline. - if (len > 0) - specs.add(new ElementSpec(attr, ElementSpec.ContentType, len)); + ElementSpec[] specs = new ElementSpec[buf.size()]; + specs = (ElementSpec[]) buf.toArray(specs); + buffer.insert(offs, len, specs, ev); + } + catch (BadLocationException ex) + { + // Ignore this. Comment out for debugging. + ex.printStackTrace(); + } + super.insertUpdate(ev, attr); + } - // Set the direction of the last spec of type StartTagType. - // If we are inserting after a newline then this value comes from - // handleInsertAfterNewline. - if (finalStartTag != null) + private short insertAfterNewline(Element par1, Element par2, + AttributeSet attr, ArrayList buf, + int offs, int endOffs) + { + short dir = 0; + if (par1.getParentElement() == par2.getParentElement()) { - if (prevCharWasNewline) - finalStartTag.setDirection(finalStartDirection); - else if (prevParagraph.getEndOffset() != endOffset) - finalStartTag.setDirection(ElementSpec.JoinFractureDirection); + ElementSpec tag = new ElementSpec(attr, ElementSpec.EndTagType); + buf.add(tag); + tag = new ElementSpec(attr, ElementSpec.StartTagType); + buf.add(tag); + if (par2.getEndOffset() != endOffs) + dir = ElementSpec.JoinFractureDirection; else { - // If there is an element AFTER this one, then set the - // direction to JoinNextDirection. - Element parent = prevParagraph.getParentElement(); - int index = parent.getElementIndex(offset); - if (index + 1 < parent.getElementCount() - && !parent.getElement(index + 1).isLeaf()) - finalStartTag.setDirection(ElementSpec.JoinNextDirection); + Element par = par2.getParentElement(); + if (par.getElementIndex(offs) + 1 < par.getElementCount()) + dir = ElementSpec.JoinNextDirection; } } - - // If we are at the last index, then check if we could probably be - // joined with the next element. - // This means: - // - we must be a ContentTag - // - if there is a next Element, we must have the same attributes - // - if there is no next Element, but one will be created, - // we must have the same attributes as the higher-level run. - ElementSpec last = (ElementSpec) specs.lastElement(); - if (last.getType() == ElementSpec.ContentType) + else { - Element currentRun = prevParagraph.getElement(prevParagraph.getElementIndex(offset)); - if (currentRun.getEndOffset() == endOffset) + // For text with more than 2 levels, find the common parent of + // par1 and par2. + ArrayList parentsLeft = new ArrayList(); + ArrayList parentsRight = new ArrayList(); + Element e = par2; + while (e != null) { - if (endOffset < getLength() && next.getAttributes().isEqual(attr) - && last.getType() == ElementSpec.ContentType) - last.setDirection(ElementSpec.JoinNextDirection); + parentsLeft.add(e); + e = e.getParentElement(); } - else + e = par1; + int leftIndex = -1; + while (e != null && (leftIndex = parentsLeft.indexOf(e)) == 1) + { + parentsRight.add(e); + e = e.getParentElement(); + } + + if (e != null) + { - if (finalStartTag != null - && finalStartTag.getDirection() == ElementSpec.JoinFractureDirection - && currentRun.getAttributes().isEqual(attr)) + // e is now the common parent. + // Insert the end tags. + for (int c = 0; c < leftIndex; c++) + { + buf.add(new ElementSpec(null, ElementSpec.EndTagType)); + } + // Insert the start tags. + for (int c = parentsRight.size() - 1; c >= 0; c--) { - last.setDirection(ElementSpec.JoinNextDirection); + Element el = (Element) parentsRight.get(c); + ElementSpec tag = new ElementSpec(el.getAttributes(), + ElementSpec.StartTagType); + if (c > 0) + tag.setDirection(ElementSpec.JoinNextDirection); + buf.add(tag); } + if (parentsRight.size() > 0) + dir = ElementSpec.JoinNextDirection; + else + dir = ElementSpec.JoinFractureDirection; } + else + assert false; } - - // If we are at the first new element, then check if it could be - // joined with the previous element. - ElementSpec first = (ElementSpec) specs.firstElement(); - if (prev.getAttributes().isEqual(attr) - && first.getType() == ElementSpec.ContentType) - first.setDirection(ElementSpec.JoinPreviousDirection); - - ElementSpec[] elSpecs = (ElementSpec[]) specs.toArray(new ElementSpec[specs.size()]); - buffer.insert(offset, length, elSpecs, ev); + return dir; } /** diff --git a/javax/swing/text/GapContent.java b/javax/swing/text/GapContent.java index 760e396a2..7b1502777 100644 --- a/javax/swing/text/GapContent.java +++ b/javax/swing/text/GapContent.java @@ -195,10 +195,52 @@ public class GapContent } } + /** + * Stores a reference to a mark that can be resetted to the original value + * after a mark has been moved. This is used for undoing actions. + */ + private class UndoPosRef + { + /** + * The mark that might need to be reset. + */ + private Mark mark; + + /** + * The original offset to reset the mark to. + */ + private int undoOffset; + + /** + * Creates a new UndoPosRef. + * + * @param m the mark + */ + UndoPosRef(Mark m) + { + mark = m; + undoOffset = mark.getOffset(); + } + + /** + * Resets the position of the mark to the value that it had when + * creating this UndoPosRef. + */ + void reset() + { + if (undoOffset <= gapStart) + mark.mark = undoOffset; + else + mark.mark = (gapEnd - gapStart) + undoOffset; + } + } + private class InsertUndo extends AbstractUndoableEdit { public int where, length; String text; + private Vector positions; + public InsertUndo(int start, int len) { where = start; @@ -209,27 +251,33 @@ public class GapContent { super.undo(); try - { - text = getString(where, length); - remove(where, length); - } + { + positions = getPositionsInRange(null, where, length); + text = getString(where, length); + remove(where, length); + } catch (BadLocationException ble) - { - throw new CannotUndoException(); - } + { + throw new CannotUndoException(); + } } public void redo () throws CannotUndoException { super.redo(); try - { - insertString(where, text); - } + { + insertString(where, text); + if (positions != null) + { + updateUndoPositions(positions, where, length); + positions = null; + } + } catch (BadLocationException ble) - { - throw new CannotRedoException(); - } + { + throw new CannotRedoException(); + } } } @@ -238,10 +286,17 @@ public class GapContent { public int where; String text; + + /** + * The positions in the removed range. + */ + private Vector positions; + public UndoRemove(int start, String removedText) { where = start; text = removedText; + positions = getPositionsInRange(null, start, removedText.length()); } public void undo () throws CannotUndoException @@ -250,6 +305,8 @@ public class GapContent try { insertString(where, text); + if (positions != null) + updateUndoPositions(positions, where, text.length()); } catch (BadLocationException ble) { @@ -261,13 +318,15 @@ public class GapContent { super.redo(); try - { - remove(where, text.length()); - } + { + text = getString(where, text.length()); + positions = getPositionsInRange(null, where, text.length()); + remove(where, text.length()); + } catch (BadLocationException ble) - { - throw new CannotRedoException(); - } + { + throw new CannotRedoException(); + } } } @@ -403,9 +462,10 @@ public class GapContent throw new BadLocationException("The where argument cannot be greater" + " than the content length", where); + InsertUndo undo = new InsertUndo(where, strLen); replace(where, 0, str.toCharArray(), strLen); - return new InsertUndo(where, strLen); + return undo; } /** @@ -429,9 +489,10 @@ public class GapContent + " than the content length", where + nitems); String removedText = getString(where, nitems); + UndoRemove undoRemove = new UndoRemove(where, removedText); replace(where, nitems, null, 0); - return new UndoRemove(where, removedText); + return undoRemove; } /** @@ -495,29 +556,43 @@ public class GapContent if (len < 0) throw new BadLocationException("negative length not allowed: ", len); - // check if requested segment is contiguous - if ((where < gapStart) && ((gapStart - where) < len)) - { - // requested segment is not contiguous -> copy the pieces together - char[] copy = new char[len]; - int lenFirst = gapStart - where; // the length of the first segment - System.arraycopy(buffer, where, copy, 0, lenFirst); - System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst); - txt.array = copy; - txt.offset = 0; - txt.count = len; - } - else - { - // requested segment is contiguous -> we can simply return the - // actual content - txt.array = buffer; - if (where < gapStart) + // Optimized to copy only when really needed. + if (where + len <= gapStart) + { + // Simple case: completely before gap. + txt.array = buffer; txt.offset = where; - else - txt.offset = where + (gapEnd - gapStart); - txt.count = len; - } + txt.count = len; + } + else if (where > gapStart) + { + // Completely after gap, adjust offset. + txt.array = buffer; + txt.offset = gapEnd + where - gapStart; + txt.count = len; + } + else + { + // Spans the gap. + int beforeGap = gapStart - where; + if (txt.isPartialReturn()) + { + // Return the part before the gap when partial return is allowed. + txt.array = buffer; + txt.offset = where; + txt.count = beforeGap; + } + else + { + // Copy pieces together otherwise. + txt.array = new char[len]; + txt.offset = 0; + System.arraycopy(buffer, where, txt.array, 0, beforeGap); + System.arraycopy(buffer, gapEnd, txt.array, beforeGap, + len - beforeGap); + txt.count = len; + } + } } /** @@ -736,8 +811,6 @@ public class GapContent Vector res = v; if (res == null) res = new Vector(); - else - res.clear(); int endOffs = offset + length; @@ -746,8 +819,8 @@ public class GapContent { GapContentPosition p = (GapContentPosition) i.next(); int offs = p.getOffset(); - if (offs >= offset && offs < endOffs) - res.add(p); + if (offs >= offset && offs <= endOffs) + res.add(new UndoPosRef(p.mark)); } return res; @@ -844,14 +917,26 @@ public class GapContent } /** - * @specnote This method is not very well specified and the positions vector - * is implementation specific. The undo positions are managed - * differently in this implementation, this method is only here - * for binary compatibility. + * Resets the positions in the specified range to their original offset + * after a undo operation is performed. For example, after removing some + * content, the positions in the removed range will all be set to one + * offset. This method restores the positions to their original offsets + * after an undo. + * + * @param positions the positions to update + * @param offset + * @param length */ protected void updateUndoPositions(Vector positions, int offset, int length) { - // We do nothing here. + for (Iterator i = positions.iterator(); i.hasNext();) + { + UndoPosRef undoPosRef = (UndoPosRef) i.next(); + undoPosRef.reset(); + } + + // Resort marks. + Collections.sort(marks); } /** diff --git a/javax/swing/text/GlyphView.java b/javax/swing/text/GlyphView.java index d505274c9..65025dd08 100644 --- a/javax/swing/text/GlyphView.java +++ b/javax/swing/text/GlyphView.java @@ -39,6 +39,7 @@ exception statement from your version. */ package javax.swing.text; import java.awt.Color; +import java.awt.Container; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; @@ -354,11 +355,14 @@ public class GlyphView extends View implements TabableView, Cloneable Font font = view.getFont(); FontMetrics fm = view.getContainer().getFontMetrics(font); Segment txt = view.getText(el.getStartOffset(), pos); - int width = fm.charsWidth(txt.array, txt.offset, txt.count); + Rectangle bounds = a instanceof Rectangle ? (Rectangle) a + : a.getBounds(); + TabExpander expander = view.getTabExpander(); + int width = Utilities.getTabbedTextWidth(txt, fm, bounds.x, expander, + view.getStartOffset()); int height = fm.getHeight(); - Rectangle bounds = a.getBounds(); Rectangle result = new Rectangle(bounds.x + width, bounds.y, - bounds.x + width, height); + 0, height); return result; } @@ -536,9 +540,24 @@ public class GlyphView extends View implements TabableView, Cloneable */ public void paint(Graphics g, Shape a) { - Element el = getElement(); checkPainter(); - getGlyphPainter().paint(this, g, a, getStartOffset(), getEndOffset()); + int p0 = getStartOffset(); + int p1 = getEndOffset(); + + Container c = getContainer(); + // Paint layered highlights if there are any. + if (c instanceof JTextComponent) + { + JTextComponent tc = (JTextComponent) c; + Highlighter h = tc.getHighlighter(); + if (h instanceof LayeredHighlighter) + { + LayeredHighlighter lh = (LayeredHighlighter) h; + lh.paintLayeredHighlights(g, p0, p1, a, tc, this); + } + } + + getGlyphPainter().paint(this, g, a, p0, p1); } diff --git a/javax/swing/text/JTextComponent.java b/javax/swing/text/JTextComponent.java index 6da84bfe7..68ba1f428 100644 --- a/javax/swing/text/JTextComponent.java +++ b/javax/swing/text/JTextComponent.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.text; -import gnu.classpath.NotImplementedException; - import java.awt.AWTEvent; import java.awt.Color; import java.awt.Container; @@ -47,6 +45,7 @@ import java.awt.Dimension; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; +import java.awt.Shape; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; @@ -59,6 +58,7 @@ import java.awt.event.MouseEvent; import java.io.IOException; import java.io.Reader; import java.io.Writer; +import java.text.BreakIterator; import java.util.Enumeration; import java.util.Hashtable; @@ -67,6 +67,7 @@ import javax.accessibility.AccessibleAction; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleEditableText; import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleText; import javax.swing.Action; @@ -105,12 +106,7 @@ public abstract class JTextComponent extends JComponent /** * The caret's offset. */ - int dot = 0; - - /** - * The current JTextComponent. - */ - JTextComponent textComp = JTextComponent.this; + private int caretDot; /** * Construct an AccessibleJTextComponent. @@ -118,7 +114,8 @@ public abstract class JTextComponent extends JComponent public AccessibleJTextComponent() { super(); - textComp.addCaretListener(this); + JTextComponent.this.addCaretListener(this); + caretDot = getCaretPosition(); } /** @@ -129,8 +126,7 @@ public abstract class JTextComponent extends JComponent */ public int getCaretPosition() { - dot = textComp.getCaretPosition(); - return dot; + return JTextComponent.this.getCaretPosition(); } /** @@ -141,7 +137,7 @@ public abstract class JTextComponent extends JComponent */ public String getSelectedText() { - return textComp.getSelectedText(); + return JTextComponent.this.getSelectedText(); } /** @@ -156,9 +152,10 @@ public abstract class JTextComponent extends JComponent */ public int getSelectionStart() { - if (getSelectedText() == null || (textComp.getText().equals(""))) + if (getSelectedText() == null + || (JTextComponent.this.getText().equals(""))) return 0; - return textComp.getSelectionStart(); + return JTextComponent.this.getSelectionStart(); } /** @@ -173,9 +170,7 @@ public abstract class JTextComponent extends JComponent */ public int getSelectionEnd() { - if (getSelectedText() == null || (textComp.getText().equals(""))) - return 0; - return textComp.getSelectionEnd(); + return JTextComponent.this.getSelectionEnd(); } /** @@ -185,10 +180,20 @@ public abstract class JTextComponent extends JComponent * @param e - the caret update event */ public void caretUpdate(CaretEvent e) - throws NotImplementedException { - // TODO: fire appropriate event. - dot = e.getDot(); + int dot = e.getDot(); + int mark = e.getMark(); + if (caretDot != dot) + { + firePropertyChange(ACCESSIBLE_CARET_PROPERTY, new Integer(caretDot), + new Integer(dot)); + caretDot = dot; + } + if (mark != dot) + { + firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null, + getSelectedText()); + } } /** @@ -197,10 +202,10 @@ public abstract class JTextComponent extends JComponent * @return the accessible state set of this component */ public AccessibleStateSet getAccessibleStateSet() - throws NotImplementedException { AccessibleStateSet state = super.getAccessibleStateSet(); - // TODO: Figure out what state must be added here to the super's state. + if (isEditable()) + state.add(AccessibleState.EDITABLE); return state; } @@ -248,9 +253,9 @@ public abstract class JTextComponent extends JComponent * @param e - the insertion event */ public void insertUpdate(DocumentEvent e) - throws NotImplementedException { - // TODO + firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, + new Integer(e.getOffset())); } /** @@ -261,9 +266,9 @@ public abstract class JTextComponent extends JComponent * @param e - the removal event */ public void removeUpdate(DocumentEvent e) - throws NotImplementedException { - // TODO + firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, + new Integer(e.getOffset())); } /** @@ -274,9 +279,9 @@ public abstract class JTextComponent extends JComponent * @param e - text change event */ public void changedUpdate(DocumentEvent e) - throws NotImplementedException { - // TODO + firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, + new Integer(e.getOffset())); } /** @@ -289,9 +294,8 @@ public abstract class JTextComponent extends JComponent * @return a character index, or -1 */ public int getIndexAtPoint(Point p) - throws NotImplementedException { - return 0; // TODO + return viewToModel(p); } /** @@ -305,9 +309,51 @@ public abstract class JTextComponent extends JComponent * @return a character's bounding box, or null */ public Rectangle getCharacterBounds(int index) - throws NotImplementedException { - return null; // TODO + // This is basically the same as BasicTextUI.modelToView(). + + Rectangle bounds = null; + if (index >= 0 && index < doc.getLength() - 1) + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + TextUI ui = getUI(); + if (ui != null) + { + // Get editor rectangle. + Rectangle rect = new Rectangle(); + Insets insets = getInsets(); + rect.x = insets.left; + rect.y = insets.top; + rect.width = getWidth() - insets.left - insets.right; + rect.height = getHeight() - insets.top - insets.bottom; + View rootView = ui.getRootView(JTextComponent.this); + if (rootView != null) + { + rootView.setSize(rect.width, rect.height); + Shape s = rootView.modelToView(index, + Position.Bias.Forward, + index + 1, + Position.Bias.Backward, + rect); + if (s != null) + bounds = s.getBounds(); + } + } + } + catch (BadLocationException ex) + { + // Ignore (return null). + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + } + return bounds; } /** @@ -317,7 +363,7 @@ public abstract class JTextComponent extends JComponent */ public int getCharCount() { - return textComp.getText().length(); + return JTextComponent.this.getText().length(); } /** @@ -329,9 +375,26 @@ public abstract class JTextComponent extends JComponent * @return the character's attributes */ public AttributeSet getCharacterAttribute(int index) - throws NotImplementedException { - return null; // TODO + AttributeSet atts; + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + Element el = doc.getDefaultRootElement(); + while (! el.isLeaf()) + { + int i = el.getElementIndex(index); + el = el.getElement(i); + } + atts = el.getAttributes(); + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + return atts; } /** @@ -344,9 +407,8 @@ public abstract class JTextComponent extends JComponent * @return the part of text at that index, or null */ public String getAtIndex(int part, int index) - throws NotImplementedException { - return null; // TODO + return getAtIndexImpl(part, index, 0); } /** @@ -359,9 +421,8 @@ public abstract class JTextComponent extends JComponent * @return the part of text after that index, or null */ public String getAfterIndex(int part, int index) - throws NotImplementedException { - return null; // TODO + return getAtIndexImpl(part, index, 1); } /** @@ -374,11 +435,84 @@ public abstract class JTextComponent extends JComponent * @return the part of text before that index, or null */ public String getBeforeIndex(int part, int index) - throws NotImplementedException { - return null; // TODO + return getAtIndexImpl(part, index, -1); } - + + /** + * Implements getAtIndex(), getBeforeIndex() and getAfterIndex(). + * + * @param part the part to return, either CHARACTER, WORD or SENTENCE + * @param index the index + * @param dir the direction, -1 for backwards, 0 for here, +1 for forwards + * + * @return the resulting string + */ + private String getAtIndexImpl(int part, int index, int dir) + { + String ret = null; + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readLock(); + try + { + BreakIterator iter = null; + switch (part) + { + case CHARACTER: + iter = BreakIterator.getCharacterInstance(getLocale()); + break; + case WORD: + iter = BreakIterator.getWordInstance(getLocale()); + break; + case SENTENCE: + iter = BreakIterator.getSentenceInstance(getLocale()); + break; + default: + break; + } + String text = doc.getText(0, doc.getLength() - 1); + iter.setText(text); + int start = index; + int end = index; + switch (dir) + { + case 0: + if (iter.isBoundary(index)) + { + start = index; + end = iter.following(index); + } + else + { + start = iter.preceding(index); + end = iter.next(); + } + break; + case 1: + start = iter.following(index); + end = iter.next(); + break; + case -1: + end = iter.preceding(index); + start = iter.previous(); + break; + default: + assert false; + } + ret = text.substring(start, end); + } + catch (BadLocationException ex) + { + // Ignore (return null). + } + finally + { + if (doc instanceof AbstractDocument) + ((AbstractDocument) doc).readUnlock(); + } + return ret; + } + /** * Returns the number of actions for this object. The zero-th * object represents the default action. @@ -386,9 +520,8 @@ public abstract class JTextComponent extends JComponent * @return the number of actions (0-based). */ public int getAccessibleActionCount() - throws NotImplementedException { - return 0; // TODO + return getActions().length; } /** @@ -400,10 +533,12 @@ public abstract class JTextComponent extends JComponent * @return description of the i-th action */ public String getAccessibleActionDescription(int i) - throws NotImplementedException { - // TODO: Not implemented fully - return super.getAccessibleDescription(); + String desc = null; + Action[] actions = getActions(); + if (i >= 0 && i < actions.length) + desc = (String) actions[i].getValue(Action.NAME); + return desc; } /** @@ -415,9 +550,17 @@ public abstract class JTextComponent extends JComponent * @return true if the action was performed successfully */ public boolean doAccessibleAction(int i) - throws NotImplementedException { - return false; // TODO + boolean ret = false; + Action[] actions = getActions(); + if (i >= 0 && i < actions.length) + { + ActionEvent ev = new ActionEvent(JTextComponent.this, + ActionEvent.ACTION_PERFORMED, null); + actions[i].actionPerformed(ev); + ret = true; + } + return ret; } /** @@ -426,9 +569,8 @@ public abstract class JTextComponent extends JComponent * @param s - the new text contents. */ public void setTextContents(String s) - throws NotImplementedException { - // TODO + setText(s); } /** @@ -438,9 +580,16 @@ public abstract class JTextComponent extends JComponent * @param s - the new text */ public void insertTextAtIndex(int index, String s) - throws NotImplementedException { - replaceText(index, index, s); + try + { + doc.insertString(index, s, null); + } + catch (BadLocationException ex) + { + // What should we do with this? + ex.printStackTrace(); + } } /** @@ -453,7 +602,7 @@ public abstract class JTextComponent extends JComponent { try { - return textComp.getText(start, end - start); + return JTextComponent.this.getText(start, end - start); } catch (BadLocationException ble) { @@ -481,8 +630,8 @@ public abstract class JTextComponent extends JComponent */ public void cut(int start, int end) { - textComp.select(start, end); - textComp.cut(); + JTextComponent.this.select(start, end); + JTextComponent.this.cut(); } /** @@ -492,8 +641,8 @@ public abstract class JTextComponent extends JComponent */ public void paste(int start) { - textComp.setCaretPosition(start); - textComp.paste(); + JTextComponent.this.setCaretPosition(start); + JTextComponent.this.paste(); } /** @@ -506,8 +655,8 @@ public abstract class JTextComponent extends JComponent */ public void replaceText(int start, int end, String s) { - textComp.select(start, end); - textComp.replaceSelection(s); + JTextComponent.this.select(start, end); + JTextComponent.this.replaceSelection(s); } /** @@ -518,7 +667,7 @@ public abstract class JTextComponent extends JComponent */ public void selectText(int start, int end) { - textComp.select(start, end); + JTextComponent.this.select(start, end); } /** @@ -529,9 +678,12 @@ public abstract class JTextComponent extends JComponent * @param s - the new attribute set for the text in the range */ public void setAttributes(int start, int end, AttributeSet s) - throws NotImplementedException { - // TODO + if (doc instanceof StyledDocument) + { + StyledDocument sdoc = (StyledDocument) doc; + sdoc.setCharacterAttributes(start, end - start, s, true); + } } } diff --git a/javax/swing/text/LabelView.java b/javax/swing/text/LabelView.java index 03279c4b2..a00a49c24 100644 --- a/javax/swing/text/LabelView.java +++ b/javax/swing/text/LabelView.java @@ -39,9 +39,11 @@ exception statement from your version. */ package javax.swing.text; import java.awt.Color; +import java.awt.Container; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Shape; +import java.awt.Toolkit; import javax.swing.event.DocumentEvent; @@ -89,6 +91,11 @@ public class LabelView extends GlyphView */ boolean superscript; + /** + * Indicates if the attributes must be refetched. + */ + private boolean valid; + /** * Creates a new GlyphView for the given Element. * @@ -97,7 +104,7 @@ public class LabelView extends GlyphView public LabelView(Element element) { super(element); - setPropertiesFromAttributes(); + valid = false; } /** @@ -115,10 +122,10 @@ public class LabelView extends GlyphView // when background == null anyway. background = (Color) atts.getAttribute(StyleConstants.Background); foreground = StyleConstants.getForeground(atts); - strikeThrough = StyleConstants.isStrikeThrough(atts); - subscript = StyleConstants.isSubscript(atts); - superscript = StyleConstants.isSuperscript(atts); - underline = StyleConstants.isUnderline(atts); + setStrikeThrough(StyleConstants.isStrikeThrough(atts)); + setSubscript(StyleConstants.isSubscript(atts)); + setSuperscript(StyleConstants.isSuperscript(atts)); + setUnderline(StyleConstants.isUnderline(atts)); // Determine the font. String family = StyleConstants.getFontFamily(atts); @@ -129,6 +136,7 @@ public class LabelView extends GlyphView if (StyleConstants.isItalic(atts)) style |= Font.ITALIC; font = new Font(family, style, size); + valid = true; } /** @@ -142,7 +150,8 @@ public class LabelView extends GlyphView */ public void changedUpdate(DocumentEvent e, Shape a, ViewFactory vf) { - setPropertiesFromAttributes(); + valid = false; + super.changedUpdate(e, a, vf); } /** @@ -152,6 +161,8 @@ public class LabelView extends GlyphView */ public Color getBackground() { + if (! valid) + setPropertiesFromAttributes(); return background; } @@ -175,6 +186,8 @@ public class LabelView extends GlyphView */ public Color getForeground() { + if (! valid) + setPropertiesFromAttributes(); return foreground; } @@ -185,6 +198,8 @@ public class LabelView extends GlyphView */ public Font getFont() { + if (! valid) + setPropertiesFromAttributes(); return font; } @@ -197,7 +212,16 @@ public class LabelView extends GlyphView */ protected FontMetrics getFontMetrics() { - return getContainer().getGraphics().getFontMetrics(font); + if (! valid) + setPropertiesFromAttributes(); + + Container c = getContainer(); + FontMetrics fm; + if (c != null) + fm = c.getFontMetrics(font); + else + fm = Toolkit.getDefaultToolkit().getFontMetrics(font); + return fm; } /** @@ -209,6 +233,8 @@ public class LabelView extends GlyphView */ public boolean isUnderline() { + if (! valid) + setPropertiesFromAttributes(); return underline; } @@ -255,6 +281,8 @@ public class LabelView extends GlyphView */ public boolean isSuperscript() { + if (! valid) + setPropertiesFromAttributes(); return superscript; } @@ -278,6 +306,8 @@ public class LabelView extends GlyphView */ public boolean isStrikeThrough() { + if (! valid) + setPropertiesFromAttributes(); return strikeThrough; } diff --git a/javax/swing/text/PlainView.java b/javax/swing/text/PlainView.java index 48fe37ce8..5d0ce4a37 100644 --- a/javax/swing/text/PlainView.java +++ b/javax/swing/text/PlainView.java @@ -87,6 +87,16 @@ public class PlainView extends View implements TabExpander */ private transient Segment lineBuffer; + /** + * The base offset for tab calculations. + */ + private int tabBase; + + /** + * The tab size. + */ + private int tabSize; + public PlainView(Element elem) { super(elem); @@ -104,6 +114,7 @@ public class PlainView extends View implements TabExpander { this.font = font; metrics = component.getFontMetrics(font); + tabSize = getTabSize() * metrics.charWidth('m'); } } @@ -115,7 +126,7 @@ public class PlainView extends View implements TabExpander // Ensure metrics are up-to-date. updateMetrics(); - Rectangle rect = a.getBounds(); + Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); int fontHeight = metrics.getHeight(); return new Rectangle(rect.x, rect.y + (line * fontHeight), rect.width, fontHeight); @@ -132,13 +143,14 @@ public class PlainView extends View implements TabExpander // Get rectangle of the line containing position. int lineIndex = getElement().getElementIndex(position); Rectangle rect = lineToRect(a, lineIndex); + tabBase = rect.x; // Get the rectangle for position. Element line = getElement().getElement(lineIndex); int lineStart = line.getStartOffset(); Segment segment = getLineBuffer(); document.getText(lineStart, position - lineStart, segment); - int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x, + int xoffset = Utilities.getTabbedTextWidth(segment, metrics, tabBase, this, lineStart); // Calc the real rectangle. @@ -262,17 +274,39 @@ public class PlainView extends View implements TabExpander selectionStart = textComponent.getSelectionStart(); selectionEnd = textComponent.getSelectionEnd(); - Rectangle rect = s.getBounds(); + Rectangle rect = s instanceof Rectangle ? (Rectangle) s : s.getBounds(); + tabBase = rect.x; // FIXME: Text may be scrolled. Document document = textComponent.getDocument(); - Element root = document.getDefaultRootElement(); + Element root = getElement(); int y = rect.y + metrics.getAscent(); int height = metrics.getHeight(); - + + // For layered highlighters we need to paint the layered highlights + // before painting any text. + LayeredHighlighter hl = null; + Highlighter h = textComponent.getHighlighter(); + if (h instanceof LayeredHighlighter) + hl = (LayeredHighlighter) h; + int count = root.getElementCount(); + for (int i = 0; i < count; i++) { + if (hl != null) + { + Element lineEl = root.getElement(i); + // Exclude the trailing newline from beeing highlighted. + if (i == count) + hl.paintLayeredHighlights(g, lineEl.getStartOffset(), + lineEl.getEndOffset(), s, textComponent, + this); + else + hl.paintLayeredHighlights(g, lineEl.getStartOffset(), + lineEl.getEndOffset() - 1, s, + textComponent, this); + } drawLine(i, g, rect.x, y); y += height; } @@ -303,8 +337,13 @@ public class PlainView extends View implements TabExpander */ public float nextTabStop(float x, int tabStop) { - float tabSizePixels = getTabSize() * metrics.charWidth('m'); - return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels; + float next = x; + if (tabSize != 0) + { + int numTabs = (((int) x) - tabBase) / tabSize; + next = tabBase + (numTabs + 1) * tabSize; + } + return next; } /** @@ -390,41 +429,58 @@ public class PlainView extends View implements TabExpander */ public int viewToModel(float x, float y, Shape a, Position.Bias[] b) { - Rectangle rec = a.getBounds(); - Document doc = getDocument(); - Element root = doc.getDefaultRootElement(); - - // PlainView doesn't support line-wrapping so we can find out which - // Element was clicked on just by the y-position. - // Since the coordinates may be outside of the coordinate space - // of the allocation area (e.g. user dragged mouse outside - // the component) we have to limit the values. - // This has the nice effect that the user can drag the - // mouse above or below the component and it will still - // react to the x values (e.g. when selecting). - int lineClicked - = Math.min(Math.max((int) (y - rec.y) / metrics.getHeight(), 0), - root.getElementCount() - 1); - - Element line = root.getElement(lineClicked); - - Segment s = getLineBuffer(); - int start = line.getStartOffset(); - // We don't want the \n at the end of the line. - int end = line.getEndOffset() - 1; - try - { - doc.getText(start, end - start, s); - } - catch (BadLocationException ble) + Rectangle rec = a instanceof Rectangle ? (Rectangle) a : a.getBounds(); + tabBase = rec.x; + + int pos; + if ((int) y < rec.y) + // Above our area vertically. Return start offset. + pos = getStartOffset(); + else if ((int) y > rec.y + rec.height) + // Below our area vertically. Return end offset. + pos = getEndOffset() - 1; + else { - AssertionError ae = new AssertionError("Unexpected bad location"); - ae.initCause(ble); - throw ae; + // Inside the allocation vertically. Determine line and X offset. + Document doc = getDocument(); + Element root = doc.getDefaultRootElement(); + int line = Math.abs(((int) y - rec.y) / metrics.getHeight()); + if (line >= root.getElementCount()) + pos = getEndOffset() - 1; + else + { + Element lineEl = root.getElement(line); + if (x < rec.x) + // To the left of the allocation area. + pos = lineEl.getStartOffset(); + else if (x > rec.x + rec.width) + // To the right of the allocation area. + pos = lineEl.getEndOffset() - 1; + else + { + try + { + int p0 = lineEl.getStartOffset(); + int p1 = lineEl.getEndOffset(); + Segment s = new Segment(); + doc.getText(p0, p1 - p0, s); + tabBase = rec.x; + pos = p0 + Utilities.getTabbedTextOffset(s, metrics, + tabBase, (int) x, + this, p0); + } + catch (BadLocationException ex) + { + // Should not happen. + pos = -1; + } + } + + } } - - int pos = Utilities.getTabbedTextOffset(s, metrics, rec.x, (int)x, this, start); - return Math.max (0, pos); + // Bias is always forward. + b[0] = Position.Bias.Forward; + return pos; } /** @@ -654,7 +710,7 @@ public class PlainView extends View implements TabExpander throw err; } - return Utilities.getTabbedTextWidth(buffer, metrics, 0, this, + return Utilities.getTabbedTextWidth(buffer, metrics, tabBase, this, lineEl.getStartOffset()); } } diff --git a/javax/swing/text/Utilities.java b/javax/swing/text/Utilities.java index 36361f497..f75906a0f 100644 --- a/javax/swing/text/Utilities.java +++ b/javax/swing/text/Utilities.java @@ -43,7 +43,6 @@ import java.awt.Graphics; import java.awt.Point; import java.text.BreakIterator; -import javax.swing.SwingConstants; import javax.swing.text.Position.Bias; /** @@ -109,7 +108,7 @@ public class Utilities for (int offset = s.offset; offset < end; ++offset) { char c = buffer[offset]; - if (c == '\t' || c == '\n') + if (c == '\t') { if (len > 0) { g.drawChars(buffer, pos, len, pixelX, pixelY + ascent); @@ -131,11 +130,6 @@ public class Utilities else pixelX += metrics.charWidth(' '); break; - case '\n': - // In case we have a newline, we must jump to the next line. - pixelY += metrics.getHeight(); - pixelX = x; - break; default: ++len; pixelWidth += metrics.charWidth(buffer[offset]); diff --git a/javax/swing/text/WrappedPlainView.java b/javax/swing/text/WrappedPlainView.java index a6c369a4c..8cb2f4fb5 100644 --- a/javax/swing/text/WrappedPlainView.java +++ b/javax/swing/text/WrappedPlainView.java @@ -449,10 +449,34 @@ public class WrappedPlainView extends BoxView implements TabExpander int currStart = getStartOffset(); int currEnd; int count = 0; + + // Determine layered highlights. + Container c = getContainer(); + LayeredHighlighter lh = null; + JTextComponent tc = null; + if (c instanceof JTextComponent) + { + tc = (JTextComponent) c; + Highlighter h = tc.getHighlighter(); + if (h instanceof LayeredHighlighter) + lh = (LayeredHighlighter) h; + } + while (currStart < end) { currEnd = calculateBreakPosition(currStart, end); + // Paint layered highlights, if any. + if (lh != null) + { + // Exclude trailing newline in last line. + if (currEnd == end) + lh.paintLayeredHighlights(g, currStart, currEnd - 1, s, tc, + this); + else + lh.paintLayeredHighlights(g, currStart, currEnd, s, tc, this); + + } drawLine(currStart, currEnd, g, rect.x, rect.y + metrics.getAscent()); rect.y += lineHeight; diff --git a/native/jni/gtk-peer/GtkDragSourceContextPeer.c b/native/jni/gtk-peer/GtkDragSourceContextPeer.c index 6dfbfcce4..62ffa1395 100644 --- a/native/jni/gtk-peer/GtkDragSourceContextPeer.c +++ b/native/jni/gtk-peer/GtkDragSourceContextPeer.c @@ -42,7 +42,8 @@ exception statement from your version. */ #include static GtkWidget * get_widget (GtkWidget *widget); - +static void connect_signals_for_widget (GtkWidget *widget); + #define ACTION_COPY 1 #define ACTION_MOVE 2 #define ACTION_COPY_OR_MOVE 3 @@ -63,21 +64,35 @@ static GtkWidget * get_widget (GtkWidget *widget); #define AWT_HAND_CURSOR 12 #define AWT_MOVE_CURSOR 13 +static jmethodID dragEnterID; +static jmethodID dragExitID; +static jmethodID dragDropEndID; +static jmethodID dragMouseMovedID; +static jmethodID dragOverID; +static jmethodID dragActionChangedID; +static jmethodID acceptDragID; +static jmethodID rejectDragID; +static jmethodID acceptDropID; +static jmethodID rejectDropID; +static jmethodID dropCompleteID; + GtkWidget *widget; +GtkWidget *tgt; +jobject *gref; +jobject javaObj; JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_create (JNIEnv *env, jobject obj, jobject comp) -{ - void *ptr; - +{ gdk_threads_enter (); - + + javaObj = obj; NSA_SET_GLOBAL_REF (env, obj); NSA_SET_GLOBAL_REF (env, comp); - ptr = NSA_GET_PTR (env, comp); - widget = get_widget (GTK_WIDGET (ptr)); + gref = NSA_GET_PTR (env, comp); + widget = get_widget (GTK_WIDGET (gref)); gdk_threads_leave (); } @@ -93,6 +108,7 @@ Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_nativeSetCursor gdk_threads_enter (); + javaObj = obj; ptr = NSA_GET_GLOBAL_REF (env, obj); switch (type) @@ -158,31 +174,81 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_connectSignals (JNIEnv *env, jobject obj, jobject comp) { - jobject *gref; - void *ptr; + jclass gtkdragsourcecontextpeer; + jclass gtkdroptargetcontextpeer; gdk_threads_enter (); - ptr = NSA_GET_GLOBAL_REF (env, obj); + javaObj = obj; gref = NSA_GET_GLOBAL_REF (env, comp); + + connect_signals_for_widget (widget); + + gtkdragsourcecontextpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer"); + + dragEnterID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdragsourcecontextpeer, + "dragEnter", "(II)V"); + dragExitID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdragsourcecontextpeer, + "dragExit", "(III)V"); + dragDropEndID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdragsourcecontextpeer, + "dragDropEnd", "(IZII)V"); + dragMouseMovedID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdragsourcecontextpeer, + "dragMouseMoved", "(II)V"); + dragOverID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdragsourcecontextpeer, + "dragOver", "(II)V"); + dragActionChangedID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdragsourcecontextpeer, + "dragActionChanged", "(II)V"); + + + gtkdroptargetcontextpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(), + "gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer"); + + acceptDragID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdroptargetcontextpeer, + "acceptDrag", "(I)V"); + rejectDragID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdroptargetcontextpeer, + "rejectDrag", "()V"); + acceptDropID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdroptargetcontextpeer, + "acceptDrop", "(I)V"); + rejectDropID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdroptargetcontextpeer, + "rejectDrop", "()V"); + dropCompleteID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), + gtkdroptargetcontextpeer, + "dropComplete", "(Z)V"); + + gdk_threads_leave (); +} + +static void +connect_signals_for_widget (GtkWidget *w) +{ + /* FIXME: Not implemented. */ + w = NULL; +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_setTarget + (JNIEnv *env, jobject obj, jobject target) +{ + void *ptr; + + gdk_threads_enter (); + + javaObj = obj; + ptr = NSA_GET_PTR (env, target); + tgt = get_widget (GTK_WIDGET (ptr)); + connect_signals_for_widget (tgt); - /* Uncomment when needed: - g_signal_connect (G_OBJECT (widget), "drag_motion", - G_CALLBACK (drag_motion_cb), *gref); - g_signal_connect (G_OBJECT (widget), "drag_begin", - G_CALLBACK (drag_begin_cb), *gref); - g_signal_connect (G_OBJECT (widget), "drag_end", - G_CALLBACK (drag_end_cb), *gref); - g_signal_connect (G_OBJECT (widget), "drag_data_get", - G_CALLBACK (drag_data_get_cb), *gref); - g_signal_connect (G_OBJECT (widget), "drag_drop", - G_CALLBACK (drag_drop_cb), *gref); - g_signal_connect (G_OBJECT (widget), "drag_data_delete", - G_CALLBACK (drag_data_delete_cb), *gref); - g_signal_connect (G_OBJECT (widget), "drag_data_received", - G_CALLBACK (drag_data_received_cb), *gref); - */ - gdk_threads_leave (); } @@ -200,7 +266,8 @@ Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_nativeStartDrag GdkDragAction action = GDK_ACTION_DEFAULT; gdk_threads_enter (); - + + javaObj = obj; ptr = NSA_GET_GLOBAL_REF (env, obj); data = (*env)->GetStringUTFChars (env, target, NULL); @@ -225,7 +292,9 @@ Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_nativeStartDrag action = GDK_ACTION_DEFAULT; } - gtk_drag_highlight (widget); + gtk_drag_dest_set (widget, GTK_DEST_DEFAULT_ALL, tar, + sizeof (tar) / sizeof (GtkTargetEntry), + action); context = gtk_drag_begin (widget, gtk_target_list_new (tar, sizeof (tar) / sizeof (GtkTargetEntry)), action, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, event); @@ -235,6 +304,11 @@ Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_nativeStartDrag image = cp_gtk_image_get_pixbuf (env, img); gtk_drag_set_icon_pixbuf (context, image, x, y); } + + if (tgt != NULL) + gtk_drag_dest_set (tgt, GTK_DEST_DEFAULT_ALL, tar, + sizeof (tar) / sizeof (GtkTargetEntry), + action); gdk_event_free (event); (*env)->ReleaseStringUTFChars (env, target, data); diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c index 965fb5a23..4053ad8b6 100644 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c +++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice.c @@ -248,8 +248,8 @@ Java_gnu_java_awt_peer_gtk_GdkScreenGraphicsDevice_nativeGetDisplayModes /* Retrieves refresh rate information. */ rates = XRRConfigRates(config, i, &nrates); - /* Create a Java int array and put them in. */ - shortArray = (*env)->NewIntArray(env, nrates); + /* Create a Java short array and put them in. */ + shortArray = (*env)->NewShortArray(env, nrates); (*env)->SetShortArrayRegion(env, shortArray, 0, nrates, (jshort *) rates); /* Create a GdkScreenGraphicsDevice.X11DisplayMode instance. */ diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c index 46949d99a..ac4df69f4 100644 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c +++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkChoicePeer.c @@ -1,5 +1,5 @@ /* gtkchoicepeer.c -- Native implementation of GtkChoicePeer - Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -52,7 +52,7 @@ cp_gtk_choice_init_jni (void) postChoiceItemEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkchoicepeer, "postChoiceItemEvent", - "(Ljava/lang/String;I)V"); + "(I)V"); } static void selection_changed_cb (GtkComboBox *combobox, jobject peer); @@ -106,39 +106,7 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_connectSignals } JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkChoicePeer_append - (JNIEnv *env, jobject obj, jobjectArray items) -{ - gpointer ptr; - jsize count, i; - GtkWidget *bin; - - gdk_threads_enter (); - - ptr = NSA_GET_PTR (env, obj); - bin = choice_get_widget (GTK_WIDGET (ptr)); - - count = (*env)->GetArrayLength (env, items); - - for (i = 0; i < count; i++) - { - jobject item; - const char *label; - - item = (*env)->GetObjectArrayElement (env, items, i); - label = (*env)->GetStringUTFChars (env, item, NULL); - - gtk_combo_box_append_text (GTK_COMBO_BOX (bin), label); - - (*env)->ReleaseStringUTFChars (env, item, label); - (*env)->DeleteLocalRef(env, item); - } - - gdk_threads_leave (); -} - -JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeAdd +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_add (JNIEnv *env, jobject obj, jstring item, jint index) { void *ptr; @@ -170,14 +138,16 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemove ptr = NSA_GET_PTR (env, obj); bin = choice_get_widget (GTK_WIDGET (ptr)); - + + /* First, unselect everything, to avoid problems when removing items. */ + gtk_combo_box_set_active (GTK_COMBO_BOX (bin), -1); gtk_combo_box_remove_text (GTK_COMBO_BOX (bin), index); gdk_threads_leave (); } -JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemoveAll +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeRemoveAll (JNIEnv *env, jobject obj) { void *ptr; @@ -224,8 +194,7 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_selectNativeUnlocked ptr = NSA_GET_PTR (env, obj); bin = choice_get_widget (GTK_WIDGET (ptr)); - - gtk_combo_box_set_active (GTK_COMBO_BOX (bin), index); + gtk_combo_box_set_active (GTK_COMBO_BOX (bin), (gint)index); } JNIEXPORT jint JNICALL @@ -251,26 +220,11 @@ Java_gnu_java_awt_peer_gtk_GtkChoicePeer_nativeGetSelected static void selection_changed_cb (GtkComboBox *combobox, jobject peer) { - jstring label; - GtkTreeModel *model; - GtkTreeIter iter; - gchar *selected; - gint index; - - index = gtk_combo_box_get_active(combobox); + gint index = gtk_combo_box_get_active(combobox); if (index >= 0) - { - model = gtk_combo_box_get_model (combobox); - gtk_combo_box_get_active_iter (combobox, &iter); - gtk_tree_model_get (model, &iter, 0, &selected, -1); - label = (*cp_gtk_gdk_env())->NewStringUTF (cp_gtk_gdk_env(), selected); - - (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, - postChoiceItemEventID, - label, - (jint) AWT_ITEM_SELECTED); - } + (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, + postChoiceItemEventID, (jint)index ); } static GtkWidget * diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c index 8949fa927..969b7bc5c 100644 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c +++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c @@ -329,6 +329,17 @@ Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkMain gdk_threads_leave (); } +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkQuit +(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused))) +{ + gdk_threads_enter (); + + gtk_main_quit (); + + gdk_threads_leave (); +} + static jint gdk_color_to_java_color (GdkColor color); diff --git a/tools/.cvsignore b/tools/.cvsignore index 8dce53527..49dfefd00 100644 --- a/tools/.cvsignore +++ b/tools/.cvsignore @@ -11,3 +11,4 @@ gkeytool gjar gnative2ascii gserialver +gjavah diff --git a/tools/Makefile.am b/tools/Makefile.am index 37f2c7acd..2c1ceacce 100755 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,6 +1,6 @@ ## Input file for automake to generate the Makefile.in used by configure -GLIBJ_CLASSPATH='$(top_builddir)/lib':'$(top_builddir)/lib/glibj.zip' +GLIBJ_CLASSPATH='$(top_builddir)/lib':'$(top_builddir)/lib/glibj.zip':$(PATH_TO_ASM) # Setup the compiler to use the GNU Classpath library we just build if FOUND_GCJX @@ -13,10 +13,14 @@ error dunno how to setup the JCOMPILER and compile endif endif +if USE_ASM +javah = gjavah +endif + if CREATE_WRAPPERS bin_SCRIPTS = bin_PROGRAMS = gappletviewer gjarsigner gkeytool \ - gjar gnative2ascii gserialver + gjar gnative2ascii gserialver $(javah) #if FOUND_GCJ #LIBJVM = -lgcj @@ -68,13 +72,21 @@ gserialver_CFLAGS = \ -DTOOLNAME="\"gserialver\"" gserialver_LDFLAGS = -L$(libdir) $(LIBJVM) +if USE_ASM +gjavah_SOURCES = toolwrapper.c +gjavah_CFLAGS = \ + -DTOOLPACKAGE="\"javah\"" \ + -DTOOLNAME="\"gjavah\"" +gjavah_LDFLAGS = -L$(libdir) $(LIBJVM) +endif + else bin_SCRIPTS = gappletviewer gjarsigner gkeytool \ - gjar gnative2ascii gserialver + gjar gnative2ascii gserialver $(javah) bin_PROGRAMS = endif EXTRA_DIST = toolwrapper.c gappletviewer.in gjarsigner.in gkeytool.in \ - gjar.in gnative2ascii.in gserialver.in + gjar.in gnative2ascii.in gserialver.in gjavah.in # All our example java source files TOOLS_JAVA_FILES = $(srcdir)/gnu/classpath/tools/*.java $(srcdir)/gnu/classpath/tools/*/*.java $(srcdir)/gnu/classpath/tools/*/*/*.java @@ -137,12 +149,18 @@ $(TOOLS_ZIP): $(TOOLS_JAVA_FILES) cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates cp $(RMI_HELPS) classes/gnu/classpath/tools/rmi/ cp $(GIOP_HELPS) classes/gnu/classpath/tools/giop/ - $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES) + find $(srcdir)/gnu/classpath/tools -name '*.java' -print > classes.lst + if test -z "$(PATH_TO_ASM)"; then \ + mv classes.lst classes.tmp; \ + fgrep -v /javah/ classes.tmp > classes.lst; \ + rm -f classes.tmp;\ + fi + $(JCOMPILER) -d classes @classes.lst (cd classes; \ if test "$(ZIP)" != ""; then $(ZIP) -r ../$(TOOLS_ZIP) .; fi; \ if test "$(FASTJAR)" != ""; then $(FASTJAR) cf ../$(TOOLS_ZIP) .; fi; \ cd ..) - rm -rf classes + rm -rf classes classes.lst # Zip file be gone! (and make sure the classes are gone too) clean-local: diff --git a/tools/gjavah.in b/tools/gjavah.in new file mode 100644 index 000000000..0505bdbc2 --- /dev/null +++ b/tools/gjavah.in @@ -0,0 +1,47 @@ +#!/bin/sh + +## Copyright (C) 2006 Free Software Foundation, Inc. +## +## This file is a part of GNU Classpath. +## +## GNU Classpath is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or (at +## your option) any later version. +## +## GNU Classpath is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Classpath; if not, write to the Free Software +## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +## USA. +## +## Linking this library statically or dynamically with other modules is +## making a combined work based on this library. Thus, the terms and +## conditions of the GNU General Public License cover the whole +## combination. +## +## As a special exception, the copyright holders of this library give you +## permission to link this library with independent modules to produce an +## executable, regardless of the license terms of these independent +## modules, and to copy and distribute the resulting executable under +## terms of your choice, provided that you also meet, for each linked +## independent module, the terms and conditions of the license of that +## module. An independent module is a module which is not derived from +## or based on this library. If you modify this library, you may extend +## this exception to your version of the library, but you are not +## obligated to do so. If you do not wish to do so, delete this +## exception statement from your version. +## +## +## A simple shell script to launch the GNU Classpath javah tool. +## + +prefix=@prefix@ +tools_dir=@datadir@/@PACKAGE@ +tools_cp=${tools_dir}/tools.zip:@PATH_TO_ASM@ + +exec @VM_BINARY@ -Xbootclasspath/p:"${tools_cp}" gnu.classpath.tools.javah.Main "$@" diff --git a/tools/gnu/classpath/tools/javah/ClassWrapper.java b/tools/gnu/classpath/tools/javah/ClassWrapper.java new file mode 100644 index 000000000..778896395 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/ClassWrapper.java @@ -0,0 +1,341 @@ +/* ClassWrapper.java - wrap ASM class objects + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public class ClassWrapper + extends ClassNode +{ + Main classpath; + + ClassWrapper superClass; + + ArrayList interfaceClasses; + + // The virtual table for this class. + ArrayList vtable; + + // A set of all the bridge method targets we've found. + HashSet bridgeTargets; + + // A set of all the method names in this class. + HashSet methodNames = new HashSet(); + + public ClassWrapper(Main classpath) + { + this.classpath = classpath; + } + + public boolean hasNativeMethod() + { + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (Modifier.isNative(method.access)) + return true; + } + return false; + } + + public boolean isThrowable() throws IOException + { + linkSupers(); + ClassWrapper self = this; + while (self != null) + { + if (self.name.equals("java/lang/Throwable")) + return true; + self = self.superClass; + } + return false; + } + + private void linkSupers() throws IOException + { + if (superName == null) + { + // Object, do nothing. + return; + } + if (superClass == null) + { + superClass = classpath.getClass(superName); + assert interfaceClasses == null; + interfaceClasses = new ArrayList(); + for (int i = 0; i < interfaces.size(); ++i) + { + String ifname = (String) interfaces.get(i); + ClassWrapper iface = classpath.getClass(ifname); + iface.linkSupers(); + interfaceClasses.add(iface); + } + } + superClass.linkSupers(); + } + + private int findSlot(MethodNode method) + { + for (int i = vtable.size() - 1; i >= 0; --i) + { + MethodNode base = (MethodNode) vtable.get(i); + if (MethodHelper.overrides(method, base)) + return i; + } + return - 1; + } + + private void addInterfaceMethods(ClassWrapper iface) + { + Iterator i = iface.methods.iterator(); + while (i.hasNext()) + { + MethodNode im = (MethodNode) i.next(); + int slot = findSlot(im); + if (slot == - 1) + { + vtable.add(im); + // Also add it to our local methods. + methods.add(im); + } + } + addInterfaces(iface); + } + + private void addInterfaces(ClassWrapper base) + { + if (base.interfaceClasses == null) + return; + Iterator i = base.interfaceClasses.iterator(); + while (i.hasNext()) + { + ClassWrapper iface = (ClassWrapper) i.next(); + addInterfaceMethods(iface); + } + } + + private void addLocalMethods() + { + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode meth = (MethodNode) i.next(); + methodNames.add(meth.name); + if (Modifier.isStatic(meth.access)) + continue; + int slot = findSlot(meth); + if (slot == - 1) + vtable.add(meth); + else + vtable.set(slot, meth); + } + } + + private void makeVtable() throws IOException + { + if (vtable != null) + return; + if (superClass != null) + { + superClass.makeVtable(); + vtable = new ArrayList(superClass.vtable); + bridgeTargets = new HashSet(superClass.bridgeTargets); + } + else + { + // Object. + vtable = new ArrayList(); + bridgeTargets = new HashSet(); + } + addLocalMethods(); + addInterfaces(this); + + // Make a set of all the targets of bridge methods. + // We rename bridge methods to avoid problems with C++. + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode m = (MethodNode) i.next(); + String desc = MethodHelper.getBridgeTarget(m); + if (desc != null) + bridgeTargets.add(m.name + desc); + } + } + + private void printFields(CniPrintStream out) + { + Iterator i = fields.iterator(); + ClassWrapper self = superClass; + while (i.hasNext()) + { + FieldNode f = (FieldNode) i.next(); + boolean hasMethodName = methodNames.contains(f.name); + if (FieldHelper.print(out, f, self, hasMethodName)) + self = null; + } + } + + private void printMethods(CniPrintStream out) throws IOException + { + makeVtable(); + + // A given method is either static, overrides a super method, or + // is already in vtable order. + Iterator i = methods.iterator(); + while (i.hasNext()) + { + MethodNode m = (MethodNode) i.next(); + boolean isTarget = bridgeTargets.contains(m.name + m.desc); + MethodHelper.print(out, m, this, isTarget); + } + } + + private void printTextList(PrintStream out, int what, ArrayList textList) + { + if (textList == null) + return; + Iterator i = textList.iterator(); + boolean first = true; + while (i.hasNext()) + { + Text item = (Text) i.next(); + if (item.type == what) + { + if (first) + { + out.println(); + first = false; + } + if (what == Text.FRIEND) + out.print(" friend "); + out.println(item.text); + } + } + } + + public void print(CniPrintStream out) + { + out.print("::" + name.replaceAll("/", "::")); + } + + // This prints the body of a class to a CxxPrintStream. + private void printContents(CniPrintStream out, ArrayList textList) + throws IOException + { + printTextList(out, Text.PREPEND, textList); + out.println(); + + out.print("class "); + // Don't use our print() -- we don't want the leading "::". + out.print(name.replaceAll("/", "::")); + if (superClass != null) + { + out.print(" : public "); + superClass.print(out); + } + out.println(); + out.println("{"); + + printTextList(out, Text.ADD, textList); + out.println(); + + // Note: methods must come first, as we build the list + // of method names while printing them. + printMethods(out); + printFields(out); + + out.setModifiers(Modifier.PUBLIC); + out.println(" static ::java::lang::Class class$;"); + + printTextList(out, Text.FRIEND, textList); + + out.print("}"); + if (Modifier.isInterface(access)) + out.print(" __attribute__ ((java_interface))"); + out.println(";"); + + printTextList(out, Text.APPEND, textList); + } + + public void printFully(PrintStream out) throws IOException + { + linkSupers(); + + ArrayList textList = classpath.getClassTextList(name); + + out.println("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-"); + out.println(); + String xname = "__" + name.replaceAll("/", "_") + "__"; + out.println("#ifndef " + xname); + out.println("#define " + xname); + out.println(); + out.println("#pragma interface"); + out.println(); + + if (superClass != null) + { + out.print("#include <"); + out.print(superName); + out.println(".h>"); + } + + // Write the body of the stream here. This lets + // us emit the namespaces without a second pass. + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + CniPrintStream cxxOut = new CniPrintStream(bytes); + cxxOut.addClass(this); + printContents(cxxOut, textList); + cxxOut.printNamespaces(out); + bytes.writeTo(out); + + out.println(); + out.println("#endif // " + xname); + } +} diff --git a/tools/gnu/classpath/tools/javah/CniIncludePrinter.java b/tools/gnu/classpath/tools/javah/CniIncludePrinter.java new file mode 100644 index 000000000..6561169bb --- /dev/null +++ b/tools/gnu/classpath/tools/javah/CniIncludePrinter.java @@ -0,0 +1,69 @@ +/* CniIncludePrinter.java - generate CNI header files + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +public class CniIncludePrinter + extends Printer +{ + + protected CniIncludePrinter(Main classpath) + { + super(classpath); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + // Never write Object or Class. This is a hack, maybe + // the user would like to see what they look like... + if (klass.name.equals("java/lang/Object") + || klass.name.equals("java/lang/Class")) + return; + File klassFile = new File(outputDir, klass.name + ".h"); + klassFile.getParentFile().mkdirs(); + PrintStream ps = new PrintStream(new FileOutputStream(klassFile)); + klass.printFully(ps); + ps.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/CniPrintStream.java b/tools/gnu/classpath/tools/javah/CniPrintStream.java new file mode 100644 index 000000000..574d7fd5f --- /dev/null +++ b/tools/gnu/classpath/tools/javah/CniPrintStream.java @@ -0,0 +1,243 @@ +/* CniPrintStream.java - PrintStream that emits CNI declarations + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashSet; + +import org.objectweb.asm.Type; + +public class CniPrintStream + extends PrintStream +{ + int currentModifiers = Modifier.PRIVATE; + + // True if we saw an array type. + boolean sawArray; + + // All the classes referenced by this header. + HashSet allClasses = new HashSet(); + + String[] previousPackage = new String[0]; + + public CniPrintStream(OutputStream out) + { + super(out); + } + + public void addClass(ClassWrapper cw) + { + allClasses.add(cw.name); + } + + public void setModifiers(int newMods) + { + newMods &= (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE); + if (newMods != currentModifiers) + { + switch (newMods) + { + case Modifier.PUBLIC: + println("public:"); + break; + case Modifier.PROTECTED: + println("public: // actually protected"); + break; + case Modifier.PRIVATE: + println("private:"); + break; + default: + println("public: // actually package-private"); + break; + } + currentModifiers = newMods; + } + } + + private String getName(Type type) + { + if (type == Type.BOOLEAN_TYPE) + return "jboolean"; + else if (type == Type.BYTE_TYPE) + return "jbyte"; + else if (type == Type.CHAR_TYPE) + return "jchar"; + else if (type == Type.SHORT_TYPE) + return "jshort"; + else if (type == Type.INT_TYPE) + return "jint"; + else if (type == Type.LONG_TYPE) + return "jlong"; + else if (type == Type.FLOAT_TYPE) + return "jfloat"; + else if (type == Type.DOUBLE_TYPE) + return "jdouble"; + else + { + assert type == Type.VOID_TYPE; + return "void"; + } + } + + public String getClassName(Type type) + { + String name = type.toString(); + name = name.substring(1, name.length() - 1); + // Add the plain class name; we'll handle it when + // we process namespaces. + allClasses.add(name); + return "::" + name.replaceAll("/", "::") + " *"; + } + + public void print(Type type) + { + int arrayCount = 0; + if (type.getSort() == Type.ARRAY) + { + arrayCount = type.getDimensions(); + for (int i = 0; i < arrayCount; ++i) + print("JArray< "); + type = type.getElementType(); + sawArray = true; + } + if (type.getSort() == Type.OBJECT) + { + print(getClassName(type)); + } + else + { + print(getName(type)); + } + if (arrayCount > 0) + { + while (arrayCount-- > 0) + { + print(" > *"); + } + } + } + + private void indent(PrintStream out, int n) + { + for (int i = 0; i < n; ++i) + { + out.print(" "); + } + } + + private void moveToPackage(PrintStream out, String[] pkgParts) + { + // Find greatest common part. + int commonIndex; + for (commonIndex = 0; commonIndex < previousPackage.length; ++commonIndex) + { + if (commonIndex >= pkgParts.length) + break; + if (! previousPackage[commonIndex].equals(pkgParts[commonIndex])) + break; + } + // Close old parts after the common part. + for (int j = previousPackage.length - 1; j >= commonIndex; --j) + { + indent(out, j + 1); + out.println("}"); + } + // Open new parts. + for (int j = commonIndex; j < pkgParts.length; ++j) + { + indent(out, j + 1); + out.print("namespace "); + out.println(pkgParts[j]); + indent(out, j + 1); + out.println("{"); + } + previousPackage = pkgParts; + } + + private void writeClass(PrintStream out, String klass) + { + int index = klass.lastIndexOf('/'); + String pkg = klass.substring(0, index); + String[] pkgParts = pkg.split("/"); + String className = klass.substring(index + 1); + moveToPackage(out, pkgParts); + indent(out, pkgParts.length + 2); + out.print("class "); + out.print(className); + out.println(";"); + } + + public void printNamespaces(PrintStream out) + { + if (sawArray) + { + out.println("#include "); + out.println(); + } + + String[] classes = (String[]) allClasses.toArray(new String[0]); + Arrays.sort(classes); + + boolean first = true; + boolean seen = false; + for (int i = 0; i < classes.length; ++i) + { + String klass = classes[i]; + if (klass.startsWith("java/lang/") || klass.startsWith("java/io/") + || klass.startsWith("java/util/")) + continue; + if (first) + { + out.println("extern \"Java\""); + out.println("{"); + first = false; + seen = true; + } + writeClass(out, klass); + } + if (seen) + { + moveToPackage(out, new String[0]); + out.println("}"); + } + } +} diff --git a/tools/gnu/classpath/tools/javah/CniStubPrinter.java b/tools/gnu/classpath/tools/javah/CniStubPrinter.java new file mode 100644 index 000000000..9732e2941 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/CniStubPrinter.java @@ -0,0 +1,119 @@ +/* CniStubPrinter.java - Generate a CNI stub file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +public class CniStubPrinter + extends Printer +{ + + protected CniStubPrinter(Main classpath) + { + super(classpath); + } + + private void printDecl(CniPrintStream out, String className, MethodNode method) + { + out.print(className); + out.print("::"); + out.print(method.name); + out.print("("); + Type[] argTypes = Type.getArgumentTypes(method.desc); + for (int j = 0; j < argTypes.length; ++j) + { + if (j > 0) + out.print(", "); + out.print(argTypes[j]); + } + out.print(")"); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + if (! klass.hasNativeMethod()) + return; + File klassFile = new File(outputDir, klass.name + ".cc"); + klassFile.getParentFile().mkdirs(); + String className = klass.name.replaceAll("/", "::"); + + CniPrintStream out = new CniPrintStream(new FileOutputStream(klassFile)); + out.println("// This file is intended to give you a head start on implementing native"); + out.println("// methods using CNI."); + out.println("// Be aware: running 'gcjh -stubs' once more for this class may"); + out.println("// overwrite any edits you have made to this file."); + out.println(); + + out.println("#include <" + klass.name + ".h>"); + out.println("#include "); + out.println("#include "); + out.println(); + + Iterator i = klass.methods.iterator(); + boolean first = true; + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + if (! first) + out.println(); + first = false; + out.print(Type.getReturnType(method.desc)); + out.println(); + printDecl(out, className, method); + out.println(); + out.println("{"); + out.print(" throw new ::java::lang::UnsupportedOperationException("); + out.print("JvNewStringLatin1 (\""); + printDecl(out, className, method); + out.println("\"));"); + out.println("}"); + } + out.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/FieldHelper.java b/tools/gnu/classpath/tools/javah/FieldHelper.java new file mode 100644 index 000000000..ecc82e3c1 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/FieldHelper.java @@ -0,0 +1,97 @@ +/* FieldHelper.java - field helper methods for CNI + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.lang.reflect.Modifier; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.FieldNode; + +public class FieldHelper +{ + public static boolean print(CniPrintStream out, FieldNode field, + ClassWrapper superType, boolean hasMethodName) + { + out.setModifiers(field.access); + out.print(" "); + if (Modifier.isStatic(field.access)) + out.print("static "); + if ((field.value instanceof Integer) || (field.value instanceof Long)) + out.print("const "); + out.print(Type.getType(field.desc)); + out.print(" "); + boolean result = false; + if (superType != null && ! Modifier.isStatic(field.access)) + { + out.print("__attribute__((aligned(__alignof__( "); + superType.print(out); + out.print(")))) "); + result = true; + } + out.print(Keywords.getCxxName(field.name)); + if (hasMethodName) + out.print("__"); + if (Modifier.isStatic(field.access)) + { + if (field.value instanceof Integer) + { + out.print(" = "); + int val = ((Integer) field.value).intValue(); + if (val == Integer.MIN_VALUE) + out.print("-" + Integer.MAX_VALUE + " - 1"); + else + out.print(val); + } + else if (field.value instanceof Long) + { + out.print(" = "); + long val = ((Long) field.value).longValue(); + if (val == Long.MIN_VALUE) + out.print("-" + Long.MAX_VALUE + "LL - 1"); + else + { + out.print(val); + out.print("LL"); + } + } + } + out.println(";"); + return result; + } +} diff --git a/tools/gnu/classpath/tools/javah/JniHelper.java b/tools/gnu/classpath/tools/javah/JniHelper.java new file mode 100644 index 000000000..7c508997e --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniHelper.java @@ -0,0 +1,120 @@ +/* JniHelper.java - name mangling and other JNI support + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.IOException; + +import org.objectweb.asm.Type; + +public class JniHelper +{ + public static String getName(Main classpath, Type type) throws IOException + { + if (type == Type.BOOLEAN_TYPE) + return "jboolean"; + else if (type == Type.BYTE_TYPE) + return "jbyte"; + else if (type == Type.CHAR_TYPE) + return "jchar"; + else if (type == Type.SHORT_TYPE) + return "jshort"; + else if (type == Type.INT_TYPE) + return "jint"; + else if (type == Type.LONG_TYPE) + return "jlong"; + else if (type == Type.FLOAT_TYPE) + return "jfloat"; + else if (type == Type.DOUBLE_TYPE) + return "jdouble"; + else if (type == Type.VOID_TYPE) + return "void"; + + if (type.getSort() == Type.ARRAY) + { + Type elt = type.getElementType(); + int eltSort = elt.getSort(); + if (type.getDimensions() == 1 && eltSort != Type.OBJECT) + return getName(classpath, elt) + "Array"; + return "jobjectArray"; + } + + // assert type.getSort() == Type.OBJECT; + String className = type.getClassName(); + // FIXME: is this correct? + if (className.equals("java/lang/Class") + || className.equals("java.lang.Class")) + return "jclass"; + if (className.equals("java/lang/String") + || className.equals("java.lang.String")) + return "jstring"; + + ClassWrapper klass = classpath.getClass(className); + if (klass.isThrowable()) + return "jthrowable"; + return "jobject"; + } + + public static String mangle(String name) + { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < name.length(); ++i) + { + char c = name.charAt(i); + if (c == '_') + result.append("_1"); + else if (c == ';') + result.append("_2"); + else if (c == '[') + result.append("_3"); + else if (c == '/') + result.append("_"); + else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) + result.append(c); + else + { + result.append("_0"); + // Sigh. + String hex = "0000" + Integer.toHexString(c); + result.append(hex.substring(hex.length() - 4)); + } + } + return result.toString(); + } +} diff --git a/tools/gnu/classpath/tools/javah/JniIncludePrinter.java b/tools/gnu/classpath/tools/javah/JniIncludePrinter.java new file mode 100644 index 000000000..c01634007 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniIncludePrinter.java @@ -0,0 +1,151 @@ +/* JniIncludePrinter.java - Generate a JNI header file + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +public class JniIncludePrinter + extends Printer +{ + + protected JniIncludePrinter(Main classpath) + { + super(classpath); + } + + private void writeFields(ClassWrapper klass, JniPrintStream out) + { + boolean wroteAny = false; + for (; klass != null; klass = klass.superClass) + { + Iterator i = klass.fields.iterator(); + while (i.hasNext()) + { + FieldNode field = (FieldNode) i.next(); + if (! Modifier.isStatic(field.access) + || ! Modifier.isFinal(field.access)) + continue; + if (! (field.value instanceof Integer) + && ! (field.value instanceof Long)) + continue; + + // Note that we don't want to mangle the field name. + String name = (JniHelper.mangle(klass.name) + "_" + field.name); + out.print("#undef "); + out.println(name); + out.print("#define "); + out.print(name); + out.print(" "); + out.print(field.value); + if (field.value instanceof Integer) + out.print("L"); + else if (field.value instanceof Long) + out.print("LL"); + out.println(); + wroteAny = true; + } + } + if (wroteAny) + out.println(); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + if (! klass.hasNativeMethod()) + return; + String xname = JniHelper.mangle(klass.name); + File outFile = new File(outputDir, xname + ".h"); + + JniPrintStream out = new JniPrintStream(classpath, + new FileOutputStream(outFile), + klass); + out.println("/* DO NOT EDIT THIS FILE - it is machine generated */"); + out.println(); + out.print("#ifndef __"); + out.print(xname); + out.println("__"); + out.print("#define __"); + out.print(xname); + out.println("__"); + out.println(); + out.println("#include "); + out.println(); + out.println("#ifdef __cplusplus"); + out.println("extern \"C\""); + out.println("{"); + out.println("#endif"); + out.println(); + + Iterator i = klass.methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + out.print("JNIEXPORT "); + out.print(Type.getReturnType(method.desc)); + out.print(" JNICALL "); + out.print(method, xname); + out.println(";"); + } + + out.println(); + + writeFields(klass, out); + + out.println("#ifdef __cplusplus"); + out.println("}"); + out.println("#endif"); + out.println(); + out.print("#endif /* __"); + out.print(xname); + out.println("__ */"); + + out.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/JniPrintStream.java b/tools/gnu/classpath/tools/javah/JniPrintStream.java new file mode 100644 index 000000000..a0461f475 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniPrintStream.java @@ -0,0 +1,115 @@ +/* JniPrintStream.java - PrintStream that emits JNI declarations + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +public class JniPrintStream + extends PrintStream +{ + Main classpath; + + // This is used to determine whether a method has an overload. + HashMap methodNameMap = new HashMap(); + + public JniPrintStream(Main classpath, OutputStream out, ClassWrapper klass) + { + super(out); + this.classpath = classpath; + computeOverloads(klass); + } + + private void computeOverloads(ClassWrapper klass) + { + Iterator i = klass.methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + if (methodNameMap.containsKey(method.name)) + { + Integer val = (Integer) methodNameMap.get(method.name); + methodNameMap.put(method.name, new Integer(val.intValue() + 1)); + } + else + methodNameMap.put(method.name, new Integer(1)); + } + } + + public void print(Type type) throws IOException + { + print(JniHelper.getName(classpath, type)); + } + + public void print(MethodNode method, String className) throws IOException + { + print("Java_"); + print(className); + print("_"); + print(JniHelper.mangle(method.name)); + Integer overloadCount = (Integer) methodNameMap.get(method.name); + if (overloadCount.intValue() > 1) + { + print("__"); + int lastOffset = method.desc.lastIndexOf(')'); + print(JniHelper.mangle(method.desc.substring(1, lastOffset))); + } + print(" (JNIEnv *env"); + if (Modifier.isStatic(method.access)) + print(", jclass"); + else + print(", jobject"); + Type[] types = Type.getArgumentTypes(method.desc); + for (int i = 0; i < types.length; ++i) + { + print(", "); + print(types[i]); + } + print(")"); + } +} diff --git a/tools/gnu/classpath/tools/javah/JniStubPrinter.java b/tools/gnu/classpath/tools/javah/JniStubPrinter.java new file mode 100644 index 000000000..d590a5cd1 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/JniStubPrinter.java @@ -0,0 +1,98 @@ +/* JniStubPrinter.java - Generate JNI stub files + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.MethodNode; + +public class JniStubPrinter + extends Printer +{ + + protected JniStubPrinter(Main classpath) + { + super(classpath); + } + + public void printClass(File outputDir, ClassWrapper klass) throws IOException + { + if (! klass.hasNativeMethod()) + return; + String xname = JniHelper.mangle(klass.name); + File outFile = new File(outputDir, xname + ".c"); + + JniPrintStream out = new JniPrintStream(classpath, + new FileOutputStream(outFile), + klass); + out.println("/* This file is intended to give you a head start on implementing native"); + out.println(" methods using CNI."); + out.println(" Be aware: running 'gcjh -stubs' once more for this class may"); + out.println(" overwrite any edits you have made to this file. */"); + out.println(); + out.print("#include <"); + out.print(xname); + out.println(".h>"); + + Iterator i = klass.methods.iterator(); + while (i.hasNext()) + { + MethodNode method = (MethodNode) i.next(); + if (! Modifier.isNative(method.access)) + continue; + out.println(); + out.print(Type.getReturnType(method.desc)); + out.println(); + out.print(method, xname); + out.println(); + out.println("{"); + out.print(" (*env)->FatalError (env, \""); + out.print(method, xname); + out.println(" not implemented\");"); + out.println("}"); + } + out.close(); + } + +} diff --git a/tools/gnu/classpath/tools/javah/Keywords.java b/tools/gnu/classpath/tools/javah/Keywords.java new file mode 100644 index 000000000..46543ba45 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Keywords.java @@ -0,0 +1,85 @@ +/* Keywords.java - List of C++ keywords + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.util.HashSet; + +public class Keywords +{ + private static final String[] words = { "and", "and_eq", "asm", "auto", + "bitand", "bitor", "bool", "break", + "case", "catch", "char", "class", + "compl", "const", "const_cast", + "continue", "default", "delete", "do", + "double", "dynamic_cast", "else", + "enum", "explicit", "export", + "extern", "false", "float", "for", + "friend", "goto", "if", "inline", + "int", "long", "mutable", "namespace", + "new", "not", "not_eq", "operator", + "or", "or_eq", "private", "protected", + "public", "register", + "reinterpret_cast", "return", "short", + "signed", "sizeof", "static", + "static_cast", "struct", "switch", + "template", "this", "throw", "true", + "try", "typedef", "typeid", + "typename", "typeof", "union", + "unsigned", "using", "virtual", + "void", "volatile", "wchar_t", + "while", "xor", "xor_eq" }; + + private static final HashSet keywords; + static + { + keywords = new HashSet(); + for (int i = 0; i < words.length; ++i) + keywords.add(words[i]); + } + + public static String getCxxName(String name) + { + int i; + for (i = name.length() - 1; i >= 0 && name.charAt(i) == '$'; --i) + ; + if (keywords.contains(name.substring(0, i + 1))) + return name + "$"; + return name; + } +} diff --git a/tools/gnu/classpath/tools/javah/Main.java b/tools/gnu/classpath/tools/javah/Main.java new file mode 100644 index 000000000..f342d4ae1 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Main.java @@ -0,0 +1,375 @@ +/* Main.java - javah main program + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.Parser; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +import org.objectweb.asm.ClassReader; + +public class Main +{ + // This is an option group for classpath-related options, + // and also is used for loading classes. + PathOptionGroup classpath = new PathOptionGroup(); + + // The output directory. + String outputDir; + + // The loader that we use to load class files. + URLClassLoader loader; + + // In -all mode, the name of the directory to scan. + String allDirectory; + + // True for verbose mode. + boolean verbose; + + // True if we're emitting stubs. + boolean stubs; + + // True if we're emitting CNI code. + boolean cni; + + // Map class names to class wrappers. + HashMap classMap = new HashMap(); + + // Map class names to lists of Text objects. + HashMap textMap = new HashMap(); + + void readCommandFile(String textFileName) throws OptionException + { + FileInputStream fis; + try + { + fis = new FileInputStream(textFileName); + } + catch (FileNotFoundException ignore) + { + throw new OptionException("file \"" + textFileName + "\" not found"); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(fis)); + String currentClass = null; + ArrayList currentValues = null; + while (true) + { + String line; + try + { + line = reader.readLine(); + } + catch (IOException _) + { + break; + } + if (line == null) + break; + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') + continue; + int index = line.indexOf(' '); + String cmd = line.substring(0, index); + String value = line.substring(index + 1); + int cmdValue; + if ("class".equals(cmd)) + { + if (currentClass != null) + { + textMap.put(currentClass, currentValues); + } + currentClass = value; + currentValues = new ArrayList(); + continue; + } + if (currentClass == null) + throw new OptionException("no class set"); + if ("add".equals(cmd)) + cmdValue = Text.ADD; + else if ("append".equals(cmd)) + cmdValue = Text.APPEND; + else if ("prepend".equals(cmd)) + cmdValue = Text.PREPEND; + else if ("friend".equals(cmd)) + cmdValue = Text.FRIEND; + else + throw new OptionException("unrecognized command: " + cmd); + currentValues.add(new Text(cmdValue, value)); + } + if (currentClass != null) + { + textMap.put(currentClass, currentValues); + } + } + + void scanDirectory(File dir, final HashSet results) + { + File[] files = dir.listFiles(new FileFilter() + { + public boolean accept(File pathname) + { + if (pathname.isDirectory()) + { + scanDirectory(pathname, results); + return false; + } + return pathname.getName().endsWith(".class"); + } + }); + if (files != null) + results.addAll(Arrays.asList(files)); + } + + private Parser getParser() + { + ClasspathToolParser result = new ClasspathToolParser("javah", true); + result.setHeader("usage: javah [OPTIONS] CLASS..."); + result.add(classpath); + result.add(new Option('d', "Set output directory", "DIR") + { + public void parsed(String dir) throws OptionException + { + if (outputDir != null) + throw new OptionException("-d already seen"); + outputDir = dir; + } + }); + result.add(new Option("cmdfile", "Read command file", "FILE") + { + public void parsed(String file) throws OptionException + { + readCommandFile(file); + } + }); + result.add(new Option("all", "Operate on all class files under directory", + "DIR") + { + public void parsed(String arg) throws OptionException + { + // FIXME: lame restriction... + if (allDirectory != null) + throw new OptionException("-all already specified"); + allDirectory = arg; + } + }); + result.add(new Option("stubs", "Emit stub implementation") + { + public void parsed(String arg0) throws OptionException + { + stubs = true; + } + }); + result.add(new Option("cni", "Emit CNI stubs or header (default JNI)") + { + public void parsed(String arg0) throws OptionException + { + cni = true; + } + }); + result.add(new Option("verbose", "Set verbose mode") + { + public void parsed(String arg0) throws OptionException + { + verbose = true; + } + }); + return result; + } + + private File makeOutputDirectory() throws IOException + { + File outputFile; + if (outputDir == null) + outputFile = new File("."); + else + { + outputFile = new File(outputDir); + outputFile.mkdirs(); + } + return outputFile; + } + + private void writeHeaders(ArrayList klasses, Printer printer, + File outputDirFile) throws IOException + { + Iterator i = klasses.iterator(); + while (i.hasNext()) + { + ClassWrapper klass = (ClassWrapper) i.next(); + if (verbose) + System.err.println("[writing " + klass + "]"); + printer.printClass(outputDirFile, klass); + } + } + + private void run(String[] args) throws IOException + { + Parser p = getParser(); + String[] classNames = p.parse(args); + loader = classpath.getLoader(); + + File outputFile = makeOutputDirectory(); + Printer printer; + if (! cni) + { + if (stubs) + printer = new JniStubPrinter(this); + else + printer = new JniIncludePrinter(this); + } + else + { + if (stubs) + printer = new CniStubPrinter(this); + else + printer = new CniIncludePrinter(this); + } + + // First we load all of the files. That way if + // there are references between the files we will + // be loading the set that the user asked for. + HashSet klasses = new HashSet(); + if (allDirectory != null) + scanDirectory(new File(allDirectory), klasses); + // Add the command-line arguments. We use the type of + // an item in 'klasses' to decide how to load each class. + for (int i = 0; i < classNames.length; ++i) + { + if (classNames[i].endsWith(".class")) + { + klasses.add(new File(classNames[i])); + } + else + { + klasses.add(classNames[i]); + } + } + + Iterator i = klasses.iterator(); + ArrayList results = new ArrayList(); + while (i.hasNext()) + { + // Let user specify either kind of class name or a + // file name. + Object item = i.next(); + ClassWrapper klass; + if (item instanceof File) + { + // Load class from file. + if (verbose) + System.err.println("[reading file " + item + "]"); + klass = getClass((File) item); + } + else + { + // Load class given the class name. + String className = ((String) item).replace('.', '/'); + if (verbose) + System.err.println("[reading class " + className + "]"); + klass = getClass(className); + } + results.add(klass); + } + + writeHeaders(results, printer, outputFile); + } + + public ArrayList getClassTextList(String name) + { + return (ArrayList) textMap.get(name); + } + + private ClassWrapper readClass(InputStream is) throws IOException + { + ClassReader r = new ClassReader(is); + ClassWrapper result = new ClassWrapper(this); + r.accept(result, true); + is.close(); + return result; + } + + private ClassWrapper getClass(File fileName) throws IOException + { + InputStream is = new FileInputStream(fileName); + ClassWrapper result = readClass(is); + if (classMap.containsKey(result.name)) + throw new IllegalArgumentException("class " + result.name + + " already loaded"); + classMap.put(result.name, result); + return result; + } + + public ClassWrapper getClass(String name) throws IOException + { + if (! classMap.containsKey(name)) + { + String resource = name.replace('.', '/') + ".class"; + URL url = loader.findResource(resource); + if (url == null) + throw new IOException("can't find class file " + resource); + InputStream is = url.openStream(); + ClassWrapper result = readClass(is); + classMap.put(name, result); + } + return (ClassWrapper) classMap.get(name); + } + + public static void main(String[] args) throws IOException + { + Main m = new Main(); + m.run(args); + } +} diff --git a/tools/gnu/classpath/tools/javah/MethodHelper.java b/tools/gnu/classpath/tools/javah/MethodHelper.java new file mode 100644 index 000000000..6657f115a --- /dev/null +++ b/tools/gnu/classpath/tools/javah/MethodHelper.java @@ -0,0 +1,130 @@ +/* MethodHelper.java - helper class for manipulating methods + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; + +public class MethodHelper +{ + + public static boolean overrides(MethodNode derived, MethodNode base) + { + if (! derived.name.equals(base.name)) + return false; + if (! derived.desc.equals(base.desc)) + return false; + // FIXME: permission madness? + return true; + } + + public static String getBridgeTarget(MethodNode meth) + { + if ((meth.access & Opcodes.ACC_BRIDGE) == 0) + return null; + Iterator i = meth.instructions.iterator(); + while (i.hasNext()) + { + AbstractInsnNode insn = (AbstractInsnNode) i.next(); + if (! (insn instanceof MethodInsnNode)) + continue; + return ((MethodInsnNode) insn).desc; + } + return null; + } + + public static void print(CniPrintStream out, MethodNode meth, + ClassWrapper declarer, boolean isBridgeTarget) + { + if ("".equals(meth.name)) + return; + boolean isInit = "".equals(meth.name); + out.setModifiers(meth.access); + out.print(" "); + if (Modifier.isStatic(meth.access)) + out.print("static "); + // If a class is final then we might as well skip 'virtual'. + // The reason here is that it is safe in this case for C++ + // ABI code to generate a direct call. The method does end + // up in the vtable (for BC code) but we don't care. Also, + // the class can't be derived from anyway. + else if (! isInit && ! Modifier.isPrivate(meth.access) + && ! Modifier.isFinal(declarer.access)) + out.print("virtual "); + if (! isInit) + { + out.print(Type.getReturnType(meth.desc)); + out.print(" "); + if (isBridgeTarget) + { + out.print("target$"); + out.print(meth.name); + } + else + { + out.print(Keywords.getCxxName(meth.name)); + } + } + else + { + String name = declarer.name; + int index = name.lastIndexOf('/'); + name = name.substring(index + 1); + out.print(name); + } + out.print("("); + Type[] argTypes = Type.getArgumentTypes(meth.desc); + for (int i = 0; i < argTypes.length; ++i) + { + if (i > 0) + out.print(", "); + out.print(argTypes[i]); + } + out.print(")"); + if (Modifier.isAbstract(meth.access)) + out.print(" = 0"); + out.println(";"); + } +} diff --git a/tools/gnu/classpath/tools/javah/PackageWrapper.java b/tools/gnu/classpath/tools/javah/PackageWrapper.java new file mode 100644 index 000000000..11b38b20f --- /dev/null +++ b/tools/gnu/classpath/tools/javah/PackageWrapper.java @@ -0,0 +1,54 @@ +/* PackageWrapper.java - represent a package + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +public class PackageWrapper +{ + // This is null if there is no parent package. + PackageWrapper parent; + + // Name of this package relative to its parent's name. + String name; + + public PackageWrapper(PackageWrapper parent, String name) + { + this.parent = parent; + this.name = name; + } +} diff --git a/tools/gnu/classpath/tools/javah/PathOptionGroup.java b/tools/gnu/classpath/tools/javah/PathOptionGroup.java new file mode 100644 index 000000000..f11077fa0 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/PathOptionGroup.java @@ -0,0 +1,135 @@ +/* PathOptionGroup.java - handle classpath-setting options + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; + +import java.io.File; +import java.io.FilenameFilter; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.StringTokenizer; + +public class PathOptionGroup + extends OptionGroup +{ + ArrayList classpath = new ArrayList(); + + ArrayList bootclasspath = new ArrayList(); + + void setPath(ArrayList list, String path) + { + list.clear(); + StringTokenizer st = new StringTokenizer(path, File.pathSeparator); + while (st.hasMoreTokens()) + { + list.add(st.nextToken()); + } + } + + void addExtDirs(ArrayList list, String path) + { + StringTokenizer tok = new StringTokenizer(path, File.pathSeparator); + while (tok.hasMoreTokens()) + { + File dir = new File(tok.nextToken()); + list.addAll(Arrays.asList(dir.list(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return name.endsWith(".zip") || name.endsWith(".jar"); + } + }))); + } + } + + public PathOptionGroup() + { + super("Class path options"); + + add(new Option("classpath", "Set the class path", "PATH") + { + public void parsed(String path) throws OptionException + { + setPath(classpath, path); + } + }); + add(new Option('I', "Add directory to class path", "DIR") + { + public void parsed(String path) throws OptionException + { + classpath.add(path); + } + }); + add(new Option("bootclasspath", "Set the boot class path", "PATH") + { + public void parsed(String path) throws OptionException + { + setPath(bootclasspath, path); + } + }); + add(new Option("extdirs", "Set the extension directory path", "PATH") + { + public void parsed(String path) throws OptionException + { + addExtDirs(classpath, path); + } + }); + } + + public URLClassLoader getLoader() throws MalformedURLException + { + ArrayList urls = new ArrayList(); + classpath.addAll(bootclasspath); + Iterator i = classpath.iterator(); + while (i.hasNext()) + { + String f = (String) i.next(); + urls.add(new File(f).toURL()); + } + URL[] urlArray = (URL[]) urls.toArray(new URL[0]); + return new URLClassLoader(urlArray); + } +} diff --git a/tools/gnu/classpath/tools/javah/Printer.java b/tools/gnu/classpath/tools/javah/Printer.java new file mode 100644 index 000000000..0c25934e2 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Printer.java @@ -0,0 +1,55 @@ +/* Print.java - abstract base class for printing classes + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +import java.io.File; +import java.io.IOException; + +public abstract class Printer +{ + protected Main classpath; + + protected Printer(Main classpath) + { + this.classpath = classpath; + } + + public abstract void printClass(File outputDir, ClassWrapper klass) + throws IOException; +} diff --git a/tools/gnu/classpath/tools/javah/Text.java b/tools/gnu/classpath/tools/javah/Text.java new file mode 100644 index 000000000..37a1ad669 --- /dev/null +++ b/tools/gnu/classpath/tools/javah/Text.java @@ -0,0 +1,60 @@ +/* Text.java - convenience class for CNI header text insertions + Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.classpath.tools.javah; + +public class Text +{ + public static final int ADD = 0; + + public static final int APPEND = 1; + + public static final int FRIEND = 2; + + public static final int PREPEND = 3; + + public int type; + + public String text; + + public Text(int type, String text) + { + this.type = type; + this.text = text; + } +} diff --git a/tools/gnu/classpath/tools/keytool/Command.java b/tools/gnu/classpath/tools/keytool/Command.java index bc5cff2aa..af91e4a71 100644 --- a/tools/gnu/classpath/tools/keytool/Command.java +++ b/tools/gnu/classpath/tools/keytool/Command.java @@ -56,7 +56,6 @@ import gnu.java.security.hash.MD5; import gnu.java.security.hash.Sha160; import gnu.java.security.util.Util; import gnu.java.security.x509.X500DistinguishedName; -import gnu.javax.security.auth.callback.ConsoleCallbackHandler; import java.io.ByteArrayOutputStream; import java.io.File; @@ -1203,7 +1202,8 @@ abstract class Command *

    * If no installed providers were found, this method falls back on the GNU * provider, by-passing the Security search mechanism. The default console - * callback handler implementation is {@link ConsoleCallbackHandler}. + * callback handler implementation is + * {@link gnu.javax.security.auth.callback.ConsoleCallbackHandler}. * * @return a console-based {@link CallbackHandler}. */ diff --git a/tools/gnu/classpath/tools/keytool/GenKeyCmd.java b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java index 03a1555a8..e2048b223 100644 --- a/tools/gnu/classpath/tools/keytool/GenKeyCmd.java +++ b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java @@ -217,7 +217,6 @@ class GenKeyCmd extends Command protected String _providerClassName; private int keySize; private X500DistinguishedName distinguishedName; - private Parser cmdOptionsParser; // default 0-arguments constructor diff --git a/tools/gnu/classpath/tools/keytool/ImportCmd.java b/tools/gnu/classpath/tools/keytool/ImportCmd.java index 3a6ed872b..1eaf6b337 100644 --- a/tools/gnu/classpath/tools/keytool/ImportCmd.java +++ b/tools/gnu/classpath/tools/keytool/ImportCmd.java @@ -207,7 +207,6 @@ class ImportCmd extends Command protected String _ksPassword; protected String _providerClassName; private CertificateFactory x509Factory; - private boolean imported; /** * Pathname to a GKR-type cacerts file to use when trustCACerts is true. This * is usually a file named "cacerts.gkr" located in lib/security in the folder diff --git a/tools/gnu/classpath/tools/keytool/Main.java b/tools/gnu/classpath/tools/keytool/Main.java index 08d55556e..7c3ebd053 100644 --- a/tools/gnu/classpath/tools/keytool/Main.java +++ b/tools/gnu/classpath/tools/keytool/Main.java @@ -296,14 +296,6 @@ public class Main log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$ } - private void printHelp() - { - if (helpPrinted) - return; - - helpPrinted = true; - } - // Inner class(es) // ========================================================================== diff --git a/vm/reference/gnu/java/lang/management/VMMemoryMXBeanImpl.java b/vm/reference/gnu/java/lang/management/VMMemoryMXBeanImpl.java index 193e33535..43b9ae1a1 100644 --- a/vm/reference/gnu/java/lang/management/VMMemoryMXBeanImpl.java +++ b/vm/reference/gnu/java/lang/management/VMMemoryMXBeanImpl.java @@ -90,7 +90,7 @@ final class VMMemoryMXBeanImpl * information when memory is allocated and deallocated. The * format of the output is left up to the virtual machine. * - * @return true if verbose class loading output is on. + * @return true if verbose memory usage output is on. */ static native boolean isVerbose(); @@ -101,7 +101,7 @@ final class VMMemoryMXBeanImpl * may be called by multiple threads concurrently, but there * is only one global setting of verbosity that is affected. * - * @param verbose the new setting for verbose class loading + * @param verbose the new setting for verbose memory usage * output. */ static native void setVerbose(boolean verbose); -- cgit v1.2.1