Overview | Package | Class | Use | Tree | Deprecated | Index | Help
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

## org.jgroups
Class Channel

    java.lang.Object
      org.jgroups.Channel

All Implemented Interfaces:
  Transport

Direct Known Subclasses:
  JChannel

    public abstract class Channel

extends java.lang.Object
implements Transport

A channel represents a group communication endpoint (like BSD datagram sockets). A client joins a group by connecting the channel to a group address and leaves it by disconnecting. Messages sent over the channel are received by all group members that are connected to the same group (that is, all members that have the same group address).

The FSM for a channel is roughly as follows: a channel is created (unconnected). The channel is connected to a group (connected). Messages can now be sent and received. The channel is disconnected from the group (unconnected). The channel could now be connected to a different group again. The channel is closed (closed).

Only a single sender is allowed to be connected to a channel at a time, but there can be more than one channel in an application.

Messages can be sent to the group members using the send method and messages can be received using receive (pull approach).

A channel instance is created using either a ChannelFactory or the public constructor. Each implementation of a channel must provide a subclass of `Channel` and an implementation of `ChannelFactory`.

Various degrees of sophistication in message exchange can be achieved using building blocks on top of channels; e.g., light-weight groups, synchronous message invocation, or remote method calls. Channels are on the same abstraction level as sockets, and should really be simple to use. Higher-level abstractions are all built on top of channels.

Author:
  Bela Ban
See Also:
  `DatagramPacket`, `MulticastSocket`

Field Summary
`static int` | `AUTO_GETSTATE` Deprecated.
`static int` | `AUTO_RECONNECT` Deprecated.
`static int` | `BLOCK` Deprecated.
`protected java.util.Set<ChannelListener>` | `channel_listeners`
`static int` | `GET_STATE_EVENTS` Deprecated.
`static int` | `LOCAL`
`protected Receiver` | `receiver`
`protected SocketFactory` | `socket_factory`
`static int` | `SUSPECT` Deprecated.
`protected UpHandler` | `up_handler`
`static int` | `VIEW` Deprecated.

Constructor Summary
`Channel()`

Method Summary
`void` | `addChannelListener(ChannelListener listener)` Allows to be notified when a channel event such as connect, disconnect or close occurs.
`abstract void` | `blockOk()` Called to acknowledge a block() (callback in `MembershipListener` or `BlockEvent` received from call to `Receive`).
`void` | `clearChannelListeners()`
`abstract void` | `close()` Destroys the channel and its associated resources (e.g., the protocol stack).
`abstract void` | `connect(java.lang.String cluster_name)` Connects the channel to a group.
`abstract void` | `connect(java.lang.String cluster_name, Address target, java.lang.String state_id, long timeout)` Connects the channel to a group and fetches the state
`abstract void` | `disconnect()` Disconnects the channel from the current group (if connected), leaving the group.
`void` | `down(Event evt)` Access to event mechanism of channels.
`java.lang.Object` | `downcall(Event evt)` Can be used instead of down() when a return value is expected.
`java.lang.String` | `dumpQueue()`
`abstract java.util.Map<java.lang.String,java.lang.Object>` | `dumpStats()` Returns a map of statistics of the various protocols and of the channel itself.
`abstract boolean` | `flushSupported()`
`abstract Address` | `getAddress()` Returns the channel's own address.
`abstract boolean` | `getAllStates(java.util.Vector targets, long timeout)` Deprecated. Not really needed - we always want to get the state from a single member
`abstract java.lang.String` | `getChannelName()` Deprecated. Use `getClusterName()` instead
`abstract java.lang.String` | `getClusterName()` Returns the cluster name of the group of which the channel is a member.
`abstract java.util.Map<java.lang.String,java.lang.Object>` | `getInfo()`
`abstract Address` | `getLocalAddress()` Deprecated. Use `getAddress()` instead
`protected abstract Log` | `getLog()`
`abstract java.lang.String` | `getName()` Returns the logical name of this channel if set.
`abstract java.lang.String` | `getName(Address member)` Returns the logical name of a given member.
`int` | `getNumMessages()` Returns the number of messages that are waiting.
`abstract java.lang.Object` | `getOpt(int option)` Gets an option.
`java.lang.String` | `getProperties()`
`abstract ProtocolStack` | `getProtocolStack()`
`Receiver` | `getReceiver()`
`SocketFactory` | `getSocketFactory()`
`abstract boolean` | `getState(Address target, long timeout)` Retrieve the state of the group.
`abstract boolean` | `getState(Address target, java.lang.String state_id, long timeout)` Fetches a partial state identified by state_id.
`UpHandler` | `getUpHandler()`
`abstract View` | `getView()` Gets the current view.
`abstract boolean` | `isConnected()` Determines whether the channel is connected to a group.
`abstract boolean` | `isOpen()` Determines whether the channel is open; i.e., the protocol stack has been created (may not be connected though).
`protected void` | `notifyChannelClosed(Channel c)`
`protected void` | `notifyChannelConnected(Channel c)`
`protected void` | `notifyChannelDisconnected(Channel c)`
`void` | `open()` Re-opens a closed channel.
`static java.lang.String` | `option2String(int option)`
`abstract java.lang.Object` | `peek(long timeout)` Deprecated. Use a `Receiver` instead, this method will not be available in JGroups 3.0
`abstract java.lang.Object` | `receive(long timeout)` Deprecated. Use a `Receiver` instead
`void` | `removeChannelListener(ChannelListener listener)`
`abstract void` | `returnState(byte[] state)` Called by the application is response to receiving a `getState()` object when calling `receive()`.
`abstract void` | `returnState(byte[] state, java.lang.String state_id)` Returns a given substate (state_id of null means return entire state)
`abstract void` | `send(Address dst, Address src, byte[] buf)`
`abstract void` | `send(Address dst, Address src, byte[] buf, int offset, int length)`
`abstract void` | `send(Address dst, Address src, java.io.Serializable obj)` Helper method.
`abstract void` | `send(Message msg)` Sends a message to a (unicast) destination.
`void` | `setChannelListener(ChannelListener channel_listener)` Deprecated. Use addChannelListener() instead
`abstract void` | `setInfo(java.lang.String key, java.lang.Object value)`
`abstract void` | `setName(java.lang.String name)` Sets the logical name for the channel.
`abstract void` | `setOpt(int option, java.lang.Object value)` Sets an option.
`void` | `setReceiver(Receiver r)` Sets the receiver, which will handle all messages, view changes etc
`void` | `setSocketFactory(SocketFactory factory)`
`void` | `setUpHandler(UpHandler up_handler)` When up_handler is set, all events will be passed to it directly.
`abstract void` | `shutdown()` Deprecated.
`abstract boolean` | `startFlush(boolean automatic_resume)`
`abstract boolean` | `startFlush(java.util.List<Address> flushParticipants, boolean automatic_resume)`
`abstract boolean` | `startFlush(long timeout, boolean automatic_resume)`
`abstract void` | `stopFlush()`
`abstract void` | `stopFlush(java.util.List<Address> flushParticipants)`

Methods inherited from class java.lang.Object
`clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

Field Detail

### BLOCK

    @Deprecated
    public static final int BLOCK

  Deprecated.
  See Also:
    Constant Field Values

### VIEW

    @Deprecated
    public static final int VIEW

  Deprecated.
  See Also:
    Constant Field Values

### SUSPECT

    @Deprecated
    public static final int SUSPECT

  Deprecated.
  See Also:
    Constant Field Values

### LOCAL

    public static final int LOCAL

See Also:
  Constant Field Values

### GET_STATE_EVENTS

    @Deprecated
    public static final int GET_STATE_EVENTS

  Deprecated.
  See Also:
    Constant Field Values

### AUTO_RECONNECT

    @Deprecated
    public static final int AUTO_RECONNECT

  Deprecated.
  See Also:
    Constant Field Values

### AUTO_GETSTATE

    @Deprecated
    public static final int AUTO_GETSTATE

  Deprecated.
  See Also:
    Constant Field Values

### up_handler

    protected UpHandler up_handler

### channel_listeners

    protected java.util.Set<ChannelListener> channel_listeners

### receiver

    protected Receiver receiver

### socket_factory

    protected SocketFactory socket_factory

Constructor Detail

### Channel

    public Channel()

Method Detail

### getLog

    protected abstract Log getLog()

### getProtocolStack

    public abstract ProtocolStack getProtocolStack()

### getSocketFactory

    public SocketFactory getSocketFactory()

### setSocketFactory

    public void setSocketFactory(SocketFactory factory)

### connect

    public abstract void connect(java.lang.String cluster_name)
                          throws ChannelException

  Connects the channel to a group. The client is now able to receive group messages, views and block events (depending on the options set) and to send messages to (all or single) group members. This is a null operation if already connected.

  All channels with the same name form a group, that means all messages sent to the group will be received by all channels connected to the same channel name.

  Parameters:
    `cluster_name` - The name of the chanel to connect to.
  Throws:
    `ChannelException` - The protocol stack cannot be started
    `ChannelClosedException` - The channel is closed and therefore cannot be used any longer. A new channel has to be created first.
  See Also:
    `disconnect()`

### connect

    public abstract void connect(java.lang.String cluster_name,
                                 Address target,
                                 java.lang.String state_id,
                                 long timeout)
                          throws ChannelException

  Connects the channel to a group and fetches the state

  Parameters:
    `cluster_name` - The name of the cluster to connect to.
    `target` - The address of the member from which the state is to be retrieved. If it is null, the state is retrieved from coordinator is contacted.
    `state_id` - The ID of a substate. If the full state is to be fetched, set this parameter to null
    `timeout` - Milliseconds to wait for the state response (0 = wait indefinitely).
  Throws:
    `ChannelException` - thrown if connecting to cluster was not successful
    `StateTransferException` - thrown if state transfer was not successful

### disconnect

    public abstract void disconnect()

  Disconnects the channel from the current group (if connected), leaving the group. It is a null operation if not connected. It is a null operation if the channel is closed.

  See Also:
    `connect(String)`

### close

    public abstract void close()

  Destroys the channel and its associated resources (e.g., the protocol stack). After a channel has been closed, invoking methods on it throws the `ChannelClosed` exception (or results in a null operation). It is a null operation if the channel is already closed.

  If the channel is connected to a group, `disconnec()t` will be called first.

### shutdown

    @Deprecated
    public abstract void shutdown()

  Deprecated.

  Shuts down the channel without disconnecting if connected, stops all the threads

### open

    public void open()
              throws ChannelException

  Re-opens a closed channel. Throws an exception if the channel is already open. After this method returns, connect() may be called to join a group. The address of this member will be different from the previous incarnation.

  Throws:
    `ChannelException`

### isOpen

    public abstract boolean isOpen()

  Determines whether the channel is open; i.e., the protocol stack has been created (may not be connected though).

### isConnected

    public abstract boolean isConnected()

  Determines whether the channel is connected to a group. This implies it is open. If true is returned, then the channel can be used to send and receive messages.

### getNumMessages

    public int getNumMessages()

  Returns the number of messages that are waiting. Those messages can be removed by `receive(long)`. Note that this number could change after calling this method and before calling `receive()` (e.g. the latter method might be called by a different thread).

  Returns:
    The number of messages on the queue, or -1 if the queue/channel is closed/disconnected.

### dumpQueue

    public java.lang.String dumpQueue()

### dumpStats

    public abstract java.util.Map<java.lang.String,java.lang.Object> dumpStats()

  Returns a map of statistics of the various protocols and of the channel itself.

  Returns:
    Map. A map where the keys are the protocols ("channel" pseudo key is used for the channel itself") and the values are property maps.

### send

    public abstract void send(Message msg)
                       throws ChannelNotConnectedException,
                              ChannelClosedException

  Sends a message to a (unicast) destination. The message contains
  1. a destination address (Address). A `null` address sends the message to all group members.
  2. a source address. Can be left empty. Will be filled in by the protocol stack.
  3. a byte buffer. The message contents.
  4. several additional fields. They can be used by application programs (or patterns). E.g. a message ID, a `oneway` field which determines whether a response is expected etc.

  Specified by:
    `send` in interface `Transport`
  Parameters:
    `msg` - The message to be sent. Destination and buffer should be set. A null destination means to send to all group members.
  Throws:
    `ChannelNotConnectedException` - The channel must be connected to send messages.
    `ChannelClosedException` - The channel is closed and therefore cannot be used any longer. A new channel has to be created first.

### send

    public abstract void send(Address dst,
                              Address src,
                              java.io.Serializable obj)
                       throws ChannelNotConnectedException,
                              ChannelClosedException

  Helper method. Will create a Message(dst, src, obj) and use send(Message).

  Parameters:
    `dst` - Destination address for message. If null, message will be sent to all current group members
    `src` - Source (sender's) address. If null, it will be set by the protocol's transport layer before being put on the wire. Can usually be set to null.
    `obj` - Serializable object. Will be serialized into the byte buffer of the Message. If it is not serializable, the byte buffer will be null.
  Throws:
    `ChannelNotConnectedException`
    `ChannelClosedException`

### send

    public abstract void send(Address dst,
                              Address src,
                              byte[] buf)
                       throws ChannelNotConnectedException,
                              ChannelClosedException

  Throws:
    `ChannelNotConnectedException`
    `ChannelClosedException`

### send

    public abstract void send(Address dst,
                              Address src,
                              byte[] buf,
                              int offset,
                              int length)
                       throws ChannelNotConnectedException,
                              ChannelClosedException

  Throws:
    `ChannelNotConnectedException`
    `ChannelClosedException`

### down

    public void down(Event evt)

  Access to event mechanism of channels. Enables to send and receive events, used by building blocks to communicate with (building block) specific protocol layers. Currently useful only with JChannel.

### downcall

    public java.lang.Object downcall(Event evt)

  Can be used instead of down() when a return value is expected. This will be removed in 3.0 when we change the signature of down() to return Object rather than void

  Parameters:
    `evt` -
  Returns:

### receive

    public abstract java.lang.Object receive(long timeout)
                                      throws ChannelNotConnectedException,
                                             ChannelClosedException,
                                             TimeoutException

  Deprecated. Use a `Receiver` instead

  Receives a message, a view change or a block event. By using `setOpt`, the type of objects to be received can be determined (e.g., not views and blocks, just messages). The possible types returned can be:
  1. `Message`. Normal message
  2. `Event`. All other events (used by JChannel)
  3. `View`. A view change.
  4. `BlockEvent`. A block event indicating that a flush protocol has been started, and we should not send any more messages. This event should be ack'ed by calling `blockOk()` . Any messages sent after blockOk() returns might get blocked until the flush protocol has completed.
  5. `UnblockEvent`. An unblock event indicating that the flush protocol has completed and we can resume sending messages
  6. `SuspectEvent`. A notification of a suspected member.
  7. `GetStateEvent`. The current state of the application should be returned using `ReturnState`.
  8. `SetStateEvent`. The state of a single/all members as requested previously by having called `Channel.getState(s).`
  9. `ExitEvent`. Signals that this member was forced to leave the group (e.g., caused by the member being suspected.) The member can rejoin the group by calling open(). If the AUTO_RECONNECT is set (see setOpt()), the reconnect will be done automatically.
  The `instanceof` operator can be used to discriminate between different types returned.

  Specified by:
    `receive` in interface `Transport`
  Parameters:
    `timeout` - Value in milliseconds. Value <= 0 means wait forever
  Returns:
    A Message, View, BlockEvent, SuspectEvent, GetStateEvent, SetStateEvent or ExitEvent, depending on what is on top of the internal queue.
  Throws:
    `ChannelNotConnectedException` - The channel must be connected to receive messages.
    `ChannelClosedException` - The channel is closed and therefore cannot be used any longer. A new channel has to be created first.
    `TimeoutException` - Thrown when a timeout has occurred.

### peek

    public abstract java.lang.Object peek(long timeout)
                                   throws ChannelNotConnectedException,
                                          ChannelClosedException,
                                          TimeoutException

  Deprecated. Use a `Receiver` instead, this method will not be available in JGroups 3.0

  Returns the next message, view, block, suspect or other event without removing it from the queue.

  Parameters:
    `timeout` - Value in milliseconds. Value <= 0 means wait forever
  Returns:
    A Message, View, BlockEvent, SuspectEvent, GetStateEvent or SetStateEvent object, depending on what is on top of the internal queue.
  Throws:
    `ChannelNotConnectedException` - The channel must be connected to receive messages.
    `ChannelClosedException` - The channel is closed and therefore cannot be used any longer. A new channel has to be created first.
    `TimeoutException` - Thrown when a timeout has occurred.
  See Also:
    `receive(long)`

### getView

    public abstract View getView()

  Gets the current view. This does not retrieve a new view, use `receive()` to do so. The view may only be available after a successful `connect()`. The result of calling this method on an unconnected channel is implementation defined (may return null). Calling it on a channel that is not enabled to receive view events (via `setOpt`) returns `null`. Calling this method on a closed channel returns a null view.

  Returns:
    The current view.

### getLocalAddress

    public abstract Address getLocalAddress()

  Deprecated. Use `getAddress()` instead

  Returns the channel's own address. The result of calling this method on an unconnected channel is implementation defined (may return null). Calling this method on a closed channel returns null. Addresses can be used as destination in the `send()` operation.

  Returns:
    The channel's address (opaque)

### getAddress

    public abstract Address getAddress()

  Returns the channel's own address. The result of calling this method on an unconnected channel is implementation defined (may return null). Calling this method on a closed channel returns null. Successor to `getAddress()`. Addresses can be used as destination in the `send()` operation.

  Returns:
    The channel's address (opaque)

### getName

    public abstract java.lang.String getName()

  Returns the logical name of this channel if set.

  Returns:
    The logical name or null (if not set)

### getName

    public abstract java.lang.String getName(Address member)

  Returns the logical name of a given member. The lookup is from the local cache of logical address / logical name mappings and no remote communication is performed.

  Parameters:
    `member` -
  Returns:

### setName

    public abstract void setName(java.lang.String name)

  Sets the logical name for the channel. The name will stay associated with this channel for the channel's lifetime (until close() is called). This method should be called before calling connect().

  Parameters:
    `name` -

### getChannelName

    public abstract java.lang.String getChannelName()

  Deprecated. Use `getClusterName()` instead

  Returns the group address of the group of which the channel is a member. This is the object that was the argument to `connect()`. Calling this method on a closed channel returns `null`.

  Returns:
    The group address

### getClusterName

    public abstract java.lang.String getClusterName()

  Returns the cluster name of the group of which the channel is a member. This is the object that was the argument to `connect()`. Calling this method on a closed channel returns `null`.

  Returns:
    The cluster name

### getProperties

    public java.lang.String getProperties()

### setUpHandler

    public void setUpHandler(UpHandler up_handler)

  When up_handler is set, all events will be passed to it directly. These will not be received by the channel (except connect/disconnect, state retrieval and the like). This can be used by building blocks on top of a channel; thus the channel is used as a pass-through medium, and the building blocks take over some of the channel's tasks. However, tasks such as connection management and state transfer is still handled by the channel.

### getUpHandler

    public UpHandler getUpHandler()

### setChannelListener

    public void setChannelListener(ChannelListener channel_listener)

  Deprecated. Use addChannelListener() instead

  Allows to be notified when a channel event such as connect, disconnect or close occurs. E.g. a PullPushAdapter may choose to stop when the channel is closed, or to start when it is opened.

### addChannelListener

    public void addChannelListener(ChannelListener listener)

  Allows to be notified when a channel event such as connect, disconnect or close occurs. E.g. a PullPushAdapter may choose to stop when the channel is closed, or to start when it is opened.

### removeChannelListener

    public void removeChannelListener(ChannelListener listener)

### clearChannelListeners

    public void clearChannelListeners()

### setReceiver

    public void setReceiver(Receiver r)

  Sets the receiver, which will handle all messages, view changes etc

### getReceiver

    public Receiver getReceiver()

### setOpt

    public abstract void setOpt(int option,
                                java.lang.Object value)

  Sets an option. The following options are currently recognized:
  1. `BLOCK`. Turn the reception of BLOCK events on/off (value is Boolean). Default is off
  2. `LOCAL`. Receive its own broadcast messages to the group (value is Boolean). Default is on.
  3. `AUTO_RECONNECT`. Turn auto-reconnection on/off. If on, when a member if forced out of a group (EXIT event), then we will reconnect.
  4. `AUTO_GETSTATE`. Turn automatic fetching of state after an auto-reconnect on/off. This also sets AUTO_RECONNECT to true (if not yet set).
  This method can be called on an unconnected channel. Calling this method on a closed channel has no effect.

### getOpt

    public abstract java.lang.Object getOpt(int option)

  Gets an option. This method can be called on an unconnected channel. Calling this method on a closed channel returns `null`.

  Parameters:
    `option` - The option to be returned.
  Returns:
    The object associated with an option.

### flushSupported

    public abstract boolean flushSupported()

### startFlush

    public abstract boolean startFlush(java.util.List<Address> flushParticipants,
                                       boolean automatic_resume)

### startFlush

    public abstract boolean startFlush(boolean automatic_resume)

### startFlush

    public abstract boolean startFlush(long timeout,
                                       boolean automatic_resume)

### stopFlush

    public abstract void stopFlush()

### stopFlush

    public abstract void stopFlush(java.util.List<Address> flushParticipants)

### blockOk

    public abstract void blockOk()

  Called to acknowledge a block() (callback in `MembershipListener` or `BlockEvent` received from call to `Receive`). After sending BlockOk, no messages should be sent until a new view has been received. Calling this method on a closed channel has no effect.

### getState

    public abstract boolean getState(Address target,
                                     long timeout)
                              throws ChannelNotConnectedException,
                                     ChannelClosedException

  Retrieve the state of the group. Will usually contact the oldest group member to get the state. When the method returns true, a `SetStateEvent` will have been added to the channel's queue, causing `receive()` to return the state in one of the next invocations. If false, no state will be retrieved by `receive()`.

  Parameters:
    `target` - The address of the member from which the state is to be retrieved. If it is null, the coordinator is contacted.
    `timeout` - Milliseconds to wait for the response (0 = wait indefinitely).
  Returns:
    boolean True if the state was retrieved successfully, otherwise false.
  Throws:
    `ChannelNotConnectedException` - The channel must be connected to receive messages.
    `ChannelClosedException` - The channel is closed and therefore cannot be used any longer. A new channel has to be created first.

### getState

    public abstract boolean getState(Address target,
                                     java.lang.String state_id,
                                     long timeout)
                              throws ChannelNotConnectedException,
                                     ChannelClosedException

  Fetches a partial state identified by state_id.

  Parameters:
    `target` -
    `state_id` -
    `timeout` -
  Returns:
  Throws:
    `ChannelNotConnectedException`
    `ChannelClosedException`

### getAllStates

    public abstract boolean getAllStates(java.util.Vector targets,
                                         long timeout)
                                  throws ChannelNotConnectedException,
                                         ChannelClosedException

  Deprecated. Not really needed - we always want to get the state from a single member

  Retrieve all states of the group members. Will contact all group members to get the states. When the method returns true, a `SetStateEvent` will have been added to the channel's queue, causing `Receive` to return the states in one of the next invocations. If false, no states will be retrieved by `Receive`.

  Parameters:
    `targets` - A list of members which are contacted for states. If the list is null, all the current members of the group will be contacted.
    `timeout` - Milliseconds to wait for the response (0 = wait indefinitely).
  Returns:
    boolean True if the state was retrieved successfully, otherwise false.
  Throws:
    `ChannelNotConnectedException` - The channel must be connected to receive messages.
    `ChannelClosedException` - The channel is closed and therefore cannot be used any longer. A new channel has to be created first.

### returnState

    public abstract void returnState(byte[] state)

  Called by the application is response to receiving a `getState()` object when calling `receive()`.

  Parameters:
    `state` - The state of the application as a byte buffer (to send over the network).

### returnState

    public abstract void returnState(byte[] state,
                                     java.lang.String state_id)

  Returns a given substate (state_id of null means return entire state)

### getInfo

    public abstract java.util.Map<java.lang.String,java.lang.Object> getInfo()

### setInfo

    public abstract void setInfo(java.lang.String key,
                                 java.lang.Object value)

### option2String

    public static java.lang.String option2String(int option)

### notifyChannelConnected

    protected void notifyChannelConnected(Channel c)

### notifyChannelDisconnected

    protected void notifyChannelDisconnected(Channel c)

### notifyChannelClosed

    protected void notifyChannelClosed(Channel c)

Overview | Package | Class | Use | Tree | Deprecated | Index | Help
PREV CLASS NEXT CLASS | FRAMES NO FRAMES
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD

Copyright © 1998-2009 Bela Ban / Red Hat. All Rights Reserved.