001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.name;
021
022 import java.io.IOException;
023 import java.io.ObjectInput;
024 import java.io.ObjectOutput;
025
026 import javax.naming.InvalidNameException;
027
028 import org.apache.directory.shared.ldap.entry.Value;
029 import org.apache.directory.shared.ldap.entry.client.ClientBinaryValue;
030 import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
031 import org.apache.directory.shared.ldap.util.StringTools;
032 import org.slf4j.Logger;
033 import org.slf4j.LoggerFactory;
034
035 /**
036 * A helper class which serialize and deserialize an AttributeTypeAndValue
037 *
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 * @version $Rev$, $Date$
040 */
041 public class AVASerializer
042 {
043 /** The LoggerFactory used by this class */
044 protected static final Logger LOG = LoggerFactory.getLogger( AVASerializer.class );
045
046 /**
047 * Serialize an AttributeTypeAndValue object.
048 *
049 * An AttributeTypeAndValue is composed of a type and a value.
050 * The data are stored following the structure :
051 *
052 * <li>upName</li> The User provided ATAV
053 * <li>start</li> The position of this ATAV in the DN
054 * <li>length</li> The ATAV length
055 * <li>upType</li> The user Provided Type
056 * <li>normType</li> The normalized AttributeType
057 * <li>isHR<li> Tells if the value is a String or not
058 * <p>
059 * if the value is a String :
060 * <li>upValue</li> The User Provided value.
061 * <li>value</li> The normalized value.
062 * <p>
063 * if the value is binary :
064 * <li>upValueLength</li>
065 * <li>upValue</li> The User Provided value.
066 * <li>valueLength</li>
067 * <li>value</li> The normalized value.
068 *
069 * @param atav the AttributeTypeAndValue to serialize
070 * @param out the OutputStream in which the atav will be serialized
071 * @throws IOException If we can't serialize the atav
072 */
073 public static void serialize( AVA atav, ObjectOutput out ) throws IOException
074 {
075 if ( StringTools.isEmpty( atav.getUpName() ) ||
076 StringTools.isEmpty( atav.getUpType() ) ||
077 StringTools.isEmpty( atav.getNormType() ) ||
078 ( atav.getStart() < 0 ) ||
079 ( atav.getLength() < 2 ) || // At least a type and '='
080 ( atav.getUpValue().isNull() ) ||
081 ( atav.getNormValue().isNull() ) )
082 {
083 String message = "Cannot serialize an wrong ATAV, ";
084
085 if ( StringTools.isEmpty( atav.getUpName() ) )
086 {
087 message += "the upName should not be null or empty";
088 }
089 else if ( StringTools.isEmpty( atav.getUpType() ) )
090 {
091 message += "the upType should not be null or empty";
092 }
093 else if ( StringTools.isEmpty( atav.getNormType() ) )
094 {
095 message += "the normType should not be null or empty";
096 }
097 else if ( atav.getStart() < 0 )
098 {
099 message += "the start should not be < 0";
100 }
101 else if ( atav.getLength() < 2 )
102 {
103 message += "the length should not be < 2";
104 }
105 else if ( atav.getUpValue().isNull() )
106 {
107 message += "the upValue should not be null";
108 }
109 else if ( atav.getNormValue().isNull() )
110 {
111 message += "the value should not be null";
112 }
113
114 LOG.error( message );
115 throw new IOException( message );
116 }
117
118 out.writeUTF( atav.getUpName() );
119 out.writeInt( atav.getStart() );
120 out.writeInt( atav.getLength() );
121 out.writeUTF( atav.getUpType() );
122 out.writeUTF( atav.getNormType() );
123
124 boolean isHR = !atav.getNormValue().isBinary();
125
126 out.writeBoolean( isHR );
127
128 if ( isHR )
129 {
130 out.writeUTF( atav.getUpValue().getString() );
131 out.writeUTF( atav.getNormValue().getString() );
132 }
133 else
134 {
135 out.writeInt( atav.getUpValue().length() );
136 out.write( atav.getUpValue().getBytes() );
137 out.writeInt( atav.getNormValue().length() );
138 out.write( atav.getNormValue().getBytes() );
139 }
140 }
141
142
143 /**
144 * Deserialize an AttributeTypeAndValue object
145 *
146 * We read back the data to create a new ATAV. The structure
147 * read is exposed in the {@link AVA#writeExternal(ObjectOutput)}
148 * method<p>
149 *
150 * @param in the input stream
151 * @throws IOException If the input stream can't be read
152 * @return The constructed AttributeTypeAndValue
153 */
154 public static AVA deserialize( ObjectInput in ) throws IOException
155 {
156 String upName = in.readUTF();
157 int start = in.readInt();
158 int length = in.readInt();
159 String upType = in.readUTF();
160 String normType = in.readUTF();
161
162 boolean isHR = in.readBoolean();
163
164 try
165 {
166 if ( isHR )
167 {
168 Value<String> upValue = new ClientStringValue( in.readUTF() );
169 Value<String> normValue = new ClientStringValue( in.readUTF() );
170
171 AVA atav =
172 new AVA( upType, normType, upValue, normValue, upName );
173
174 return atav;
175 }
176 else
177 {
178 int upValueLength = in.readInt();
179 byte[] upValue = new byte[upValueLength];
180 in.readFully( upValue );
181
182 int valueLength = in.readInt();
183 byte[] normValue = new byte[valueLength];
184 in.readFully( normValue );
185
186 AVA atav =
187 new AVA( upType, normType,
188 new ClientBinaryValue( upValue) ,
189 new ClientBinaryValue( normValue ), upName );
190
191 return atav;
192 }
193 }
194 catch ( InvalidNameException ine )
195 {
196 throw new IOException( ine.getMessage() );
197 }
198 }
199 }