Author: markt Date: Mon Oct 23 16:12:17 2006 New Revision: 467173 URL: http://svn.apache.org/viewvc?view=rev&rev=467173 Log: Fix properties.
Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java (contents, props changed) tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java (contents, props changed) tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java (contents, props changed) tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java (contents, props changed) tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java (contents, props changed) tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/XByteBuffer.java (contents, props changed) Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java?view=diff&rev=467173&r1=467172&r2=467173 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java Mon Oct 23 16:12:17 2006 @@ -1,357 +1,357 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.tribes.io; - -import java.util.Arrays; - -import org.apache.catalina.tribes.ChannelMessage; -import org.apache.catalina.tribes.Member; -import org.apache.catalina.tribes.membership.MemberImpl; -import org.apache.catalina.tribes.util.UUIDGenerator; -import org.apache.catalina.tribes.Channel; -import java.sql.Timestamp; - -/** - * The <code>ChannelData</code> object is used to transfer a message through the - * channel interceptor stack and eventually out on a transport to be sent - * to another node. While the message is being processed by the different - * interceptors, the message data can be manipulated as each interceptor seems appropriate. - * @author Peter Rossbach - * @author Filip Hanik - * @version $Revision: 377484 $ $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $ - * - */ -public class ChannelData implements ChannelMessage { - public static ChannelData[] EMPTY_DATA_ARRAY = new ChannelData[0]; - - public static boolean USE_SECURE_RANDOM_FOR_UUID = false; - - /** - * The options this message was sent with - */ - private int options = 0 ; - /** - * The message data, stored in a dynamic buffer - */ - private XByteBuffer message ; - /** - * The timestamp that goes with this message - */ - private long timestamp ; - /** - * A unique message id - */ - private byte[] uniqueId ; - /** - * The source or reply-to address for this message - */ - private Member address; - - /** - * Creates an empty channel data with a new unique Id - * @see #ChannelData(boolean) - */ - public ChannelData() { - this(true); - } - - /** - * Create an empty channel data object - * @param generateUUID boolean - if true, a unique Id will be generated - */ - public ChannelData(boolean generateUUID) { - if ( generateUUID ) generateUUID(); - } - - - - /** - * Creates a new channel data object with data - * @param uniqueId - unique message id - * @param message - message data - * @param timestamp - message timestamp - */ - public ChannelData(byte[] uniqueId, XByteBuffer message, long timestamp) { - this.uniqueId = uniqueId; - this.message = message; - this.timestamp = timestamp; - } - - /** - * @return Returns the message byte buffer - */ - public XByteBuffer getMessage() { - return message; - } - /** - * @param message The message to send. - */ - public void setMessage(XByteBuffer message) { - this.message = message; - } - /** - * @return Returns the timestamp. - */ - public long getTimestamp() { - return timestamp; - } - /** - * @param timestamp The timestamp to send - */ - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - /** - * @return Returns the uniqueId. - */ - public byte[] getUniqueId() { - return uniqueId; - } - /** - * @param uniqueId The uniqueId to send. - */ - public void setUniqueId(byte[] uniqueId) { - this.uniqueId = uniqueId; - } - /** - * @return returns the message options - * see org.apache.catalina.tribes.Channel#sendMessage(org.apache.catalina.tribes.Member[], java.io.Serializable, int) - * - */ - public int getOptions() { - return options; - } - /** - * @param sets the message options - */ - public void setOptions(int options) { - this.options = options; - } - - /** - * Returns the source or reply-to address - * @return Member - */ - public Member getAddress() { - return address; - } - - /** - * Sets the source or reply-to address - * @param address Member - */ - public void setAddress(Member address) { - this.address = address; - } - - /** - * Generates a UUID and invokes setUniqueId - */ - public void generateUUID() { - byte[] data = new byte[16]; - UUIDGenerator.randomUUID(USE_SECURE_RANDOM_FOR_UUID,data,0); - setUniqueId(data); - } - - public int getDataPackageLength() { - int length = - 4 + //options - 8 + //timestamp off=4 - 4 + //unique id length off=12 - uniqueId.length+ //id data off=12+uniqueId.length - 4 + //addr length off=12+uniqueId.length+4 - ((MemberImpl)address).getDataLength()+ //member data off=12+uniqueId.length+4+add.length - 4 + //message length off=12+uniqueId.length+4+add.length+4 - message.getLength(); - return length; - - } - - /** - * Serializes the ChannelData object into a byte[] array - * @return byte[] - */ - public byte[] getDataPackage() { - int length = getDataPackageLength(); - byte[] data = new byte[length]; - int offset = 0; - return getDataPackage(data,offset); - } - - public byte[] getDataPackage(byte[] data, int offset) { - byte[] addr = ((MemberImpl)address).getData(false); - XByteBuffer.toBytes(options,data,offset); - offset += 4; //options - XByteBuffer.toBytes(timestamp,data,offset); - offset += 8; //timestamp - XByteBuffer.toBytes(uniqueId.length,data,offset); - offset += 4; //uniqueId.length - System.arraycopy(uniqueId,0,data,offset,uniqueId.length); - offset += uniqueId.length; //uniqueId data - XByteBuffer.toBytes(addr.length,data,offset); - offset += 4; //addr.length - System.arraycopy(addr,0,data,offset,addr.length); - offset += addr.length; //addr data - XByteBuffer.toBytes(message.getLength(),data,offset); - offset += 4; //message.length - System.arraycopy(message.getBytesDirect(),0,data,offset,message.getLength()); - offset += message.getLength(); //message data - return data; - } - - /** - * Deserializes a ChannelData object from a byte array - * @param b byte[] - * @return ChannelData - */ - public static ChannelData getDataFromPackage(XByteBuffer xbuf) { - ChannelData data = new ChannelData(false); - int offset = 0; - data.setOptions(XByteBuffer.toInt(xbuf.getBytesDirect(),offset)); - offset += 4; //options - data.setTimestamp(XByteBuffer.toLong(xbuf.getBytesDirect(),offset)); - offset += 8; //timestamp - data.uniqueId = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)]; - offset += 4; //uniqueId length - System.arraycopy(xbuf.getBytesDirect(),offset,data.uniqueId,0,data.uniqueId.length); - offset += data.uniqueId.length; //uniqueId data - byte[] addr = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)]; - offset += 4; //addr length - System.arraycopy(xbuf.getBytesDirect(),offset,addr,0,addr.length); - data.setAddress(MemberImpl.getMember(addr)); - offset += addr.length; //addr data - int xsize = XByteBuffer.toInt(xbuf.getBytesDirect(),offset); - offset += 4; //xsize length - System.arraycopy(xbuf.getBytesDirect(),offset,xbuf.getBytesDirect(),0,xsize); - xbuf.setLength(xsize); - data.message = xbuf; - return data; - - } - - public static ChannelData getDataFromPackage(byte[] b) { - ChannelData data = new ChannelData(false); - int offset = 0; - data.setOptions(XByteBuffer.toInt(b,offset)); - offset += 4; //options - data.setTimestamp(XByteBuffer.toLong(b,offset)); - offset += 8; //timestamp - data.uniqueId = new byte[XByteBuffer.toInt(b,offset)]; - offset += 4; //uniqueId length - System.arraycopy(b,offset,data.uniqueId,0,data.uniqueId.length); - offset += data.uniqueId.length; //uniqueId data - byte[] addr = new byte[XByteBuffer.toInt(b,offset)]; - offset += 4; //addr length - System.arraycopy(b,offset,addr,0,addr.length); - data.setAddress(MemberImpl.getMember(addr)); - offset += addr.length; //addr data - int xsize = XByteBuffer.toInt(b,offset); - //data.message = new XByteBuffer(new byte[xsize],false); - data.message = BufferPool.getBufferPool().getBuffer(xsize,false); - offset += 4; //message length - System.arraycopy(b,offset,data.message.getBytesDirect(),0,xsize); - data.message.append(b,offset,xsize); - offset += xsize; //message data - return data; - } - - public int hashCode() { - return XByteBuffer.toInt(getUniqueId(),0); - } - - /** - * Compares to ChannelData objects, only compares on getUniqueId().equals(o.getUniqueId()) - * @param o Object - * @return boolean - */ - public boolean equals(Object o) { - if ( o instanceof ChannelData ) { - return Arrays.equals(getUniqueId(),((ChannelData)o).getUniqueId()); - } else return false; - } - - /** - * Create a shallow clone, only the data gets recreated - * @return ClusterData - */ - public Object clone() { -// byte[] d = this.getDataPackage(); -// return ClusterData.getDataFromPackage(d); - ChannelData clone = new ChannelData(false); - clone.options = this.options; - clone.message = new XByteBuffer(this.message.getBytesDirect(),false); - clone.timestamp = this.timestamp; - clone.uniqueId = this.uniqueId; - clone.address = this.address; - return clone; - } - - /** - * Complete clone - * @return ClusterData - */ - public Object deepclone() { - byte[] d = this.getDataPackage(); - return ChannelData.getDataFromPackage(d); - } - - /** - * Utility method, returns true if the options flag indicates that an ack - * is to be sent after the message has been received and processed - * @param options int - the options for the message - * @return boolean - * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK - * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK - */ - public static boolean sendAckSync(int options) { - return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) && - ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) == Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); - } - - - /** - * Utility method, returns true if the options flag indicates that an ack - * is to be sent after the message has been received but not yet processed - * @param options int - the options for the message - * @return boolean - * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK - * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK - */ - public static boolean sendAckAsync(int options) { - return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) && - ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) != Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append("ClusterData[src="); - buf.append(getAddress()).append("; id="); - buf.append(bToS(getUniqueId())).append("; sent="); - buf.append(new Timestamp(this.getTimestamp()).toString()).append("]"); - return buf.toString(); - } - - public static String bToS(byte[] data) { - StringBuffer buf = new StringBuffer(4*16); - buf.append("{"); - for (int i=0; data!=null && i<data.length; i++ ) buf.append(String.valueOf(data[i])).append(" "); - buf.append("}"); - return buf.toString(); - } - - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.tribes.io; + +import java.util.Arrays; + +import org.apache.catalina.tribes.ChannelMessage; +import org.apache.catalina.tribes.Member; +import org.apache.catalina.tribes.membership.MemberImpl; +import org.apache.catalina.tribes.util.UUIDGenerator; +import org.apache.catalina.tribes.Channel; +import java.sql.Timestamp; + +/** + * The <code>ChannelData</code> object is used to transfer a message through the + * channel interceptor stack and eventually out on a transport to be sent + * to another node. While the message is being processed by the different + * interceptors, the message data can be manipulated as each interceptor seems appropriate. + * @author Peter Rossbach + * @author Filip Hanik + * @version $Revision$ $Date$ + * + */ +public class ChannelData implements ChannelMessage { + public static ChannelData[] EMPTY_DATA_ARRAY = new ChannelData[0]; + + public static boolean USE_SECURE_RANDOM_FOR_UUID = false; + + /** + * The options this message was sent with + */ + private int options = 0 ; + /** + * The message data, stored in a dynamic buffer + */ + private XByteBuffer message ; + /** + * The timestamp that goes with this message + */ + private long timestamp ; + /** + * A unique message id + */ + private byte[] uniqueId ; + /** + * The source or reply-to address for this message + */ + private Member address; + + /** + * Creates an empty channel data with a new unique Id + * @see #ChannelData(boolean) + */ + public ChannelData() { + this(true); + } + + /** + * Create an empty channel data object + * @param generateUUID boolean - if true, a unique Id will be generated + */ + public ChannelData(boolean generateUUID) { + if ( generateUUID ) generateUUID(); + } + + + + /** + * Creates a new channel data object with data + * @param uniqueId - unique message id + * @param message - message data + * @param timestamp - message timestamp + */ + public ChannelData(byte[] uniqueId, XByteBuffer message, long timestamp) { + this.uniqueId = uniqueId; + this.message = message; + this.timestamp = timestamp; + } + + /** + * @return Returns the message byte buffer + */ + public XByteBuffer getMessage() { + return message; + } + /** + * @param message The message to send. + */ + public void setMessage(XByteBuffer message) { + this.message = message; + } + /** + * @return Returns the timestamp. + */ + public long getTimestamp() { + return timestamp; + } + /** + * @param timestamp The timestamp to send + */ + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + /** + * @return Returns the uniqueId. + */ + public byte[] getUniqueId() { + return uniqueId; + } + /** + * @param uniqueId The uniqueId to send. + */ + public void setUniqueId(byte[] uniqueId) { + this.uniqueId = uniqueId; + } + /** + * @return returns the message options + * see org.apache.catalina.tribes.Channel#sendMessage(org.apache.catalina.tribes.Member[], java.io.Serializable, int) + * + */ + public int getOptions() { + return options; + } + /** + * @param sets the message options + */ + public void setOptions(int options) { + this.options = options; + } + + /** + * Returns the source or reply-to address + * @return Member + */ + public Member getAddress() { + return address; + } + + /** + * Sets the source or reply-to address + * @param address Member + */ + public void setAddress(Member address) { + this.address = address; + } + + /** + * Generates a UUID and invokes setUniqueId + */ + public void generateUUID() { + byte[] data = new byte[16]; + UUIDGenerator.randomUUID(USE_SECURE_RANDOM_FOR_UUID,data,0); + setUniqueId(data); + } + + public int getDataPackageLength() { + int length = + 4 + //options + 8 + //timestamp off=4 + 4 + //unique id length off=12 + uniqueId.length+ //id data off=12+uniqueId.length + 4 + //addr length off=12+uniqueId.length+4 + ((MemberImpl)address).getDataLength()+ //member data off=12+uniqueId.length+4+add.length + 4 + //message length off=12+uniqueId.length+4+add.length+4 + message.getLength(); + return length; + + } + + /** + * Serializes the ChannelData object into a byte[] array + * @return byte[] + */ + public byte[] getDataPackage() { + int length = getDataPackageLength(); + byte[] data = new byte[length]; + int offset = 0; + return getDataPackage(data,offset); + } + + public byte[] getDataPackage(byte[] data, int offset) { + byte[] addr = ((MemberImpl)address).getData(false); + XByteBuffer.toBytes(options,data,offset); + offset += 4; //options + XByteBuffer.toBytes(timestamp,data,offset); + offset += 8; //timestamp + XByteBuffer.toBytes(uniqueId.length,data,offset); + offset += 4; //uniqueId.length + System.arraycopy(uniqueId,0,data,offset,uniqueId.length); + offset += uniqueId.length; //uniqueId data + XByteBuffer.toBytes(addr.length,data,offset); + offset += 4; //addr.length + System.arraycopy(addr,0,data,offset,addr.length); + offset += addr.length; //addr data + XByteBuffer.toBytes(message.getLength(),data,offset); + offset += 4; //message.length + System.arraycopy(message.getBytesDirect(),0,data,offset,message.getLength()); + offset += message.getLength(); //message data + return data; + } + + /** + * Deserializes a ChannelData object from a byte array + * @param b byte[] + * @return ChannelData + */ + public static ChannelData getDataFromPackage(XByteBuffer xbuf) { + ChannelData data = new ChannelData(false); + int offset = 0; + data.setOptions(XByteBuffer.toInt(xbuf.getBytesDirect(),offset)); + offset += 4; //options + data.setTimestamp(XByteBuffer.toLong(xbuf.getBytesDirect(),offset)); + offset += 8; //timestamp + data.uniqueId = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)]; + offset += 4; //uniqueId length + System.arraycopy(xbuf.getBytesDirect(),offset,data.uniqueId,0,data.uniqueId.length); + offset += data.uniqueId.length; //uniqueId data + byte[] addr = new byte[XByteBuffer.toInt(xbuf.getBytesDirect(),offset)]; + offset += 4; //addr length + System.arraycopy(xbuf.getBytesDirect(),offset,addr,0,addr.length); + data.setAddress(MemberImpl.getMember(addr)); + offset += addr.length; //addr data + int xsize = XByteBuffer.toInt(xbuf.getBytesDirect(),offset); + offset += 4; //xsize length + System.arraycopy(xbuf.getBytesDirect(),offset,xbuf.getBytesDirect(),0,xsize); + xbuf.setLength(xsize); + data.message = xbuf; + return data; + + } + + public static ChannelData getDataFromPackage(byte[] b) { + ChannelData data = new ChannelData(false); + int offset = 0; + data.setOptions(XByteBuffer.toInt(b,offset)); + offset += 4; //options + data.setTimestamp(XByteBuffer.toLong(b,offset)); + offset += 8; //timestamp + data.uniqueId = new byte[XByteBuffer.toInt(b,offset)]; + offset += 4; //uniqueId length + System.arraycopy(b,offset,data.uniqueId,0,data.uniqueId.length); + offset += data.uniqueId.length; //uniqueId data + byte[] addr = new byte[XByteBuffer.toInt(b,offset)]; + offset += 4; //addr length + System.arraycopy(b,offset,addr,0,addr.length); + data.setAddress(MemberImpl.getMember(addr)); + offset += addr.length; //addr data + int xsize = XByteBuffer.toInt(b,offset); + //data.message = new XByteBuffer(new byte[xsize],false); + data.message = BufferPool.getBufferPool().getBuffer(xsize,false); + offset += 4; //message length + System.arraycopy(b,offset,data.message.getBytesDirect(),0,xsize); + data.message.append(b,offset,xsize); + offset += xsize; //message data + return data; + } + + public int hashCode() { + return XByteBuffer.toInt(getUniqueId(),0); + } + + /** + * Compares to ChannelData objects, only compares on getUniqueId().equals(o.getUniqueId()) + * @param o Object + * @return boolean + */ + public boolean equals(Object o) { + if ( o instanceof ChannelData ) { + return Arrays.equals(getUniqueId(),((ChannelData)o).getUniqueId()); + } else return false; + } + + /** + * Create a shallow clone, only the data gets recreated + * @return ClusterData + */ + public Object clone() { +// byte[] d = this.getDataPackage(); +// return ClusterData.getDataFromPackage(d); + ChannelData clone = new ChannelData(false); + clone.options = this.options; + clone.message = new XByteBuffer(this.message.getBytesDirect(),false); + clone.timestamp = this.timestamp; + clone.uniqueId = this.uniqueId; + clone.address = this.address; + return clone; + } + + /** + * Complete clone + * @return ClusterData + */ + public Object deepclone() { + byte[] d = this.getDataPackage(); + return ChannelData.getDataFromPackage(d); + } + + /** + * Utility method, returns true if the options flag indicates that an ack + * is to be sent after the message has been received and processed + * @param options int - the options for the message + * @return boolean + * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK + * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK + */ + public static boolean sendAckSync(int options) { + return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) && + ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) == Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); + } + + + /** + * Utility method, returns true if the options flag indicates that an ack + * is to be sent after the message has been received but not yet processed + * @param options int - the options for the message + * @return boolean + * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_USE_ACK + * @see org.apache.catalina.tribes.Channel#SEND_OPTIONS_SYNCHRONIZED_ACK + */ + public static boolean sendAckAsync(int options) { + return ( (Channel.SEND_OPTIONS_USE_ACK & options) == Channel.SEND_OPTIONS_USE_ACK) && + ( (Channel.SEND_OPTIONS_SYNCHRONIZED_ACK & options) != Channel.SEND_OPTIONS_SYNCHRONIZED_ACK); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("ClusterData[src="); + buf.append(getAddress()).append("; id="); + buf.append(bToS(getUniqueId())).append("; sent="); + buf.append(new Timestamp(this.getTimestamp()).toString()).append("]"); + return buf.toString(); + } + + public static String bToS(byte[] data) { + StringBuffer buf = new StringBuffer(4*16); + buf.append("{"); + for (int i=0; data!=null && i<data.length; i++ ) buf.append(String.valueOf(data[i])).append(" "); + buf.append("}"); + return buf.toString(); + } + + +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ChannelData.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java?view=diff&rev=467173&r1=467172&r2=467173 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java Mon Oct 23 16:12:17 2006 @@ -1,63 +1,63 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.tribes.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Byte array output stream that exposes the byte array directly - * - * @author not attributable - * @version 1.0 - */ -public class DirectByteArrayOutputStream extends OutputStream { - - private XByteBuffer buffer; - - public DirectByteArrayOutputStream(int size) { - buffer = new XByteBuffer(size,false); - } - - /** - * Writes the specified byte to this output stream. - * - * @param b the <code>byte</code>. - * @throws IOException if an I/O error occurs. In particular, an - * <code>IOException</code> may be thrown if the output stream has - * been closed. - * @todo Implement this java.io.OutputStream method - */ - public void write(int b) throws IOException { - buffer.append((byte)b); - } - - public int size() { - return buffer.getLength(); - } - - public byte[] getArrayDirect() { - return buffer.getBytesDirect(); - } - - public byte[] getArray() { - return buffer.getBytes(); - } - - +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.tribes.io; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Byte array output stream that exposes the byte array directly + * + * @author not attributable + * @version 1.0 + */ +public class DirectByteArrayOutputStream extends OutputStream { + + private XByteBuffer buffer; + + public DirectByteArrayOutputStream(int size) { + buffer = new XByteBuffer(size,false); + } + + /** + * Writes the specified byte to this output stream. + * + * @param b the <code>byte</code>. + * @throws IOException if an I/O error occurs. In particular, an + * <code>IOException</code> may be thrown if the output stream has + * been closed. + * @todo Implement this java.io.OutputStream method + */ + public void write(int b) throws IOException { + buffer.append((byte)b); + } + + public int size() { + return buffer.getLength(); + } + + public byte[] getArrayDirect() { + return buffer.getBytesDirect(); + } + + public byte[] getArray() { + return buffer.getBytes(); + } + + } Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/DirectByteArrayOutputStream.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java?view=diff&rev=467173&r1=467172&r2=467173 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java Mon Oct 23 16:12:17 2006 @@ -1,42 +1,42 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.tribes.io; - -import org.apache.catalina.tribes.ChannelMessage; - - - -/** - * Internal interface, similar to the MessageListener but used - * at the IO base - * The listen callback interface is used by the replication system - * when data has been received. The interface does not care about - * objects and marshalling and just passes the bytes straight through. - * @author Filip Hanik - * @version $Revision: 303987 $, $Date: 2005-07-08 15:50:30 -0500 (Fri, 08 Jul 2005) $ - */ -public interface ListenCallback -{ - /** - * This method is invoked on the callback object to notify it that new data has - * been received from one of the cluster nodes. - * @param data - the message bytes received from the cluster/replication system - */ - public void messageDataReceived(ChannelMessage data); - +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.tribes.io; + +import org.apache.catalina.tribes.ChannelMessage; + + + +/** + * Internal interface, similar to the MessageListener but used + * at the IO base + * The listen callback interface is used by the replication system + * when data has been received. The interface does not care about + * objects and marshalling and just passes the bytes straight through. + * @author Filip Hanik + * @version $Revision$, $Date$ + */ +public interface ListenCallback +{ + /** + * This method is invoked on the callback object to notify it that new data has + * been received from one of the cluster nodes. + * @param data - the message bytes received from the cluster/replication system + */ + public void messageDataReceived(ChannelMessage data); + } Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ListenCallback.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java?view=diff&rev=467173&r1=467172&r2=467173 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java Mon Oct 23 16:12:17 2006 @@ -1,165 +1,165 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.tribes.io; - -import java.io.IOException; -import java.net.Socket; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; - -import org.apache.catalina.tribes.ChannelMessage; - - - -/** - * The object reader object is an object used in conjunction with - * java.nio TCP messages. This object stores the message bytes in a - * <code>XByteBuffer</code> until a full package has been received. - * This object uses an XByteBuffer which is an extendable object buffer that also allows - * for message encoding and decoding. - * - * @author Filip Hanik - * @version $Revision: 377484 $, $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $ - */ -public class ObjectReader { - - protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(ObjectReader.class); - - private XByteBuffer buffer; - - protected long lastAccess = System.currentTimeMillis(); - - protected boolean accessed = false; - private boolean cancelled; - - /** - * Creates an <code>ObjectReader</code> for a TCP NIO socket channel - * @param channel - the channel to be read. - */ - public ObjectReader(SocketChannel channel) { - this(channel.socket()); - } - - /** - * Creates an <code>ObjectReader</code> for a TCP socket - * @param socket Socket - */ - public ObjectReader(Socket socket) { - try{ - this.buffer = new XByteBuffer(socket.getReceiveBufferSize(), true); - }catch ( IOException x ) { - //unable to get buffer size - log.warn("Unable to retrieve the socket receiver buffer size, setting to default 43800 bytes."); - this.buffer = new XByteBuffer(43800,true); - } - } - - public synchronized void access() { - this.accessed = true; - this.lastAccess = System.currentTimeMillis(); - } - - public synchronized void finish() { - this.accessed = false; - this.lastAccess = System.currentTimeMillis(); - } - - public boolean isAccessed() { - return this.accessed; - } - - /** - * Append new bytes to buffer. - * @see XByteBuffer#countPackages() - * @param data new transfer buffer - * @param off offset - * @param len length in buffer - * @return number of messages that sended to callback - * @throws java.io.IOException - */ - public int append(ByteBuffer data, int len, boolean count) throws java.io.IOException { - buffer.append(data,len); - int pkgCnt = -1; - if ( count ) pkgCnt = buffer.countPackages(); - return pkgCnt; - } - - public int append(byte[] data,int off,int len, boolean count) throws java.io.IOException { - buffer.append(data,off,len); - int pkgCnt = -1; - if ( count ) pkgCnt = buffer.countPackages(); - return pkgCnt; - } - - /** - * Send buffer to cluster listener (callback). - * Is message complete receiver send message to callback? - * - * @see org.apache.catalina.tribes.transport.ClusterReceiverBase#messageDataReceived(ChannelMessage) - * @see XByteBuffer#doesPackageExist() - * @see XByteBuffer#extractPackage(boolean) - * - * @return number of received packages/messages - * @throws java.io.IOException - */ - public ChannelMessage[] execute() throws java.io.IOException { - int pkgCnt = buffer.countPackages(); - ChannelMessage[] result = new ChannelMessage[pkgCnt]; - for (int i=0; i<pkgCnt; i++) { - ChannelMessage data = buffer.extractPackage(true); - result[i] = data; - } - return result; - } - - public int bufferSize() { - return buffer.getLength(); - } - - - public boolean hasPackage() { - return buffer.countPackages(true)>0; - } - /** - * Returns the number of packages that the reader has read - * @return int - */ - public int count() { - return buffer.countPackages(); - } - - public void close() { - this.buffer = null; - } - - public long getLastAccess() { - return lastAccess; - } - - public boolean isCancelled() { - return cancelled; - } - - public void setLastAccess(long lastAccess) { - this.lastAccess = lastAccess; - } - - public void setCancelled(boolean cancelled) { - this.cancelled = cancelled; - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.tribes.io; + +import java.io.IOException; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; + +import org.apache.catalina.tribes.ChannelMessage; + + + +/** + * The object reader object is an object used in conjunction with + * java.nio TCP messages. This object stores the message bytes in a + * <code>XByteBuffer</code> until a full package has been received. + * This object uses an XByteBuffer which is an extendable object buffer that also allows + * for message encoding and decoding. + * + * @author Filip Hanik + * @version $Revision$, $Date$ + */ +public class ObjectReader { + + protected static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog(ObjectReader.class); + + private XByteBuffer buffer; + + protected long lastAccess = System.currentTimeMillis(); + + protected boolean accessed = false; + private boolean cancelled; + + /** + * Creates an <code>ObjectReader</code> for a TCP NIO socket channel + * @param channel - the channel to be read. + */ + public ObjectReader(SocketChannel channel) { + this(channel.socket()); + } + + /** + * Creates an <code>ObjectReader</code> for a TCP socket + * @param socket Socket + */ + public ObjectReader(Socket socket) { + try{ + this.buffer = new XByteBuffer(socket.getReceiveBufferSize(), true); + }catch ( IOException x ) { + //unable to get buffer size + log.warn("Unable to retrieve the socket receiver buffer size, setting to default 43800 bytes."); + this.buffer = new XByteBuffer(43800,true); + } + } + + public synchronized void access() { + this.accessed = true; + this.lastAccess = System.currentTimeMillis(); + } + + public synchronized void finish() { + this.accessed = false; + this.lastAccess = System.currentTimeMillis(); + } + + public boolean isAccessed() { + return this.accessed; + } + + /** + * Append new bytes to buffer. + * @see XByteBuffer#countPackages() + * @param data new transfer buffer + * @param off offset + * @param len length in buffer + * @return number of messages that sended to callback + * @throws java.io.IOException + */ + public int append(ByteBuffer data, int len, boolean count) throws java.io.IOException { + buffer.append(data,len); + int pkgCnt = -1; + if ( count ) pkgCnt = buffer.countPackages(); + return pkgCnt; + } + + public int append(byte[] data,int off,int len, boolean count) throws java.io.IOException { + buffer.append(data,off,len); + int pkgCnt = -1; + if ( count ) pkgCnt = buffer.countPackages(); + return pkgCnt; + } + + /** + * Send buffer to cluster listener (callback). + * Is message complete receiver send message to callback? + * + * @see org.apache.catalina.tribes.transport.ClusterReceiverBase#messageDataReceived(ChannelMessage) + * @see XByteBuffer#doesPackageExist() + * @see XByteBuffer#extractPackage(boolean) + * + * @return number of received packages/messages + * @throws java.io.IOException + */ + public ChannelMessage[] execute() throws java.io.IOException { + int pkgCnt = buffer.countPackages(); + ChannelMessage[] result = new ChannelMessage[pkgCnt]; + for (int i=0; i<pkgCnt; i++) { + ChannelMessage data = buffer.extractPackage(true); + result[i] = data; + } + return result; + } + + public int bufferSize() { + return buffer.getLength(); + } + + + public boolean hasPackage() { + return buffer.countPackages(true)>0; + } + /** + * Returns the number of packages that the reader has read + * @return int + */ + public int count() { + return buffer.countPackages(); + } + + public void close() { + this.buffer = null; + } + + public long getLastAccess() { + return lastAccess; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setLastAccess(long lastAccess) { + this.lastAccess = lastAccess; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ObjectReader.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java?view=diff&rev=467173&r1=467172&r2=467173 ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java Mon Oct 23 16:12:17 2006 @@ -1,117 +1,117 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.tribes.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; - -/** - * Custom subclass of <code>ObjectInputStream</code> that loads from the - * class loader for this web application. This allows classes defined only - * with the web application to be found correctly. - * - * @author Craig R. McClanahan - * @author Bip Thelin - * @author Filip Hanik - * @version $Revision: 377484 $, $Date: 2006-02-13 15:00:05 -0600 (Mon, 13 Feb 2006) $ - */ - -public final class ReplicationStream extends ObjectInputStream { - - - /** - * The class loader we will use to resolve classes. - */ - private ClassLoader[] classLoaders = null; - - - /** - * Construct a new instance of CustomObjectInputStream - * - * @param stream The input stream we will read from - * @param classLoader The class loader used to instantiate objects - * - * @exception IOException if an input/output error occurs - */ - public ReplicationStream(InputStream stream, - ClassLoader[] classLoaders) - throws IOException { - - super(stream); - this.classLoaders = classLoaders; - } - - /** - * Load the local class equivalent of the specified stream class - * description, by using the class loader assigned to this Context. - * - * @param classDesc Class description from the input stream - * - * @exception ClassNotFoundException if this class cannot be found - * @exception IOException if an input/output error occurs - */ - public Class resolveClass(ObjectStreamClass classDesc) - throws ClassNotFoundException, IOException { - String name = classDesc.getName(); - boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes"); - try { - try - { - if ( tryRepFirst ) return findReplicationClass(name); - else return findExternalClass(name); - } - catch ( Exception x ) - { - if ( tryRepFirst ) return findExternalClass(name); - else return findReplicationClass(name); - } - } catch (ClassNotFoundException e) { - return super.resolveClass(classDesc); - } - } - - public Class findReplicationClass(String name) - throws ClassNotFoundException, IOException { - Class clazz = Class.forName(name, false, getClass().getClassLoader()); - return clazz; - } - - public Class findExternalClass(String name) throws ClassNotFoundException { - ClassNotFoundException cnfe = null; - for (int i=0; i<classLoaders.length; i++ ) { - try { - Class clazz = Class.forName(name, false, classLoaders[i]); - return clazz; - } catch ( ClassNotFoundException x ) { - cnfe = x; - } - } - if ( cnfe != null ) throw cnfe; - else throw new ClassNotFoundException(name); - } - - public void close() throws IOException { - this.classLoaders = null; - super.close(); - } - - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.tribes.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; + +/** + * Custom subclass of <code>ObjectInputStream</code> that loads from the + * class loader for this web application. This allows classes defined only + * with the web application to be found correctly. + * + * @author Craig R. McClanahan + * @author Bip Thelin + * @author Filip Hanik + * @version $Revision$, $Date$ + */ + +public final class ReplicationStream extends ObjectInputStream { + + + /** + * The class loader we will use to resolve classes. + */ + private ClassLoader[] classLoaders = null; + + + /** + * Construct a new instance of CustomObjectInputStream + * + * @param stream The input stream we will read from + * @param classLoader The class loader used to instantiate objects + * + * @exception IOException if an input/output error occurs + */ + public ReplicationStream(InputStream stream, + ClassLoader[] classLoaders) + throws IOException { + + super(stream); + this.classLoaders = classLoaders; + } + + /** + * Load the local class equivalent of the specified stream class + * description, by using the class loader assigned to this Context. + * + * @param classDesc Class description from the input stream + * + * @exception ClassNotFoundException if this class cannot be found + * @exception IOException if an input/output error occurs + */ + public Class resolveClass(ObjectStreamClass classDesc) + throws ClassNotFoundException, IOException { + String name = classDesc.getName(); + boolean tryRepFirst = name.startsWith("org.apache.catalina.tribes"); + try { + try + { + if ( tryRepFirst ) return findReplicationClass(name); + else return findExternalClass(name); + } + catch ( Exception x ) + { + if ( tryRepFirst ) return findExternalClass(name); + else return findReplicationClass(name); + } + } catch (ClassNotFoundException e) { + return super.resolveClass(classDesc); + } + } + + public Class findReplicationClass(String name) + throws ClassNotFoundException, IOException { + Class clazz = Class.forName(name, false, getClass().getClassLoader()); + return clazz; + } + + public Class findExternalClass(String name) throws ClassNotFoundException { + ClassNotFoundException cnfe = null; + for (int i=0; i<classLoaders.length; i++ ) { + try { + Class clazz = Class.forName(name, false, classLoaders[i]); + return clazz; + } catch ( ClassNotFoundException x ) { + cnfe = x; + } + } + if ( cnfe != null ) throw cnfe; + else throw new ClassNotFoundException(name); + } + + public void close() throws IOException { + this.classLoaders = null; + super.close(); + } + + +} Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/tc6.0.x/trunk/java/org/apache/catalina/tribes/io/ReplicationStream.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]