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 org.apache.directory.shared.ldap.entry.BinaryValue;
027 import org.apache.directory.shared.ldap.entry.StringValue;
028 import org.apache.directory.shared.ldap.entry.Value;
029 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
030 import org.apache.directory.shared.ldap.util.StringTools;
031 import org.slf4j.Logger;
032 import org.slf4j.LoggerFactory;
033
034 /**
035 * A helper class which serialize and deserialize an AttributeTypeAndValue
036 *
037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
038 * @version $Rev$, $Date$
039 */
040 public class AVASerializer
041 {
042 /** The LoggerFactory used by this class */
043 protected static final Logger LOG = LoggerFactory.getLogger( AVASerializer.class );
044
045 /**
046 * Serialize an AttributeTypeAndValue object.
047 *
048 * An AttributeTypeAndValue is composed of a type and a value.
049 * The data are stored following the structure :
050 *
051 * <li>upName</li> The User provided ATAV
052 * <li>start</li> The position of this ATAV in the DN
053 * <li>length</li> The ATAV length
054 * <li>upType</li> The user Provided Type
055 * <li>normType</li> The normalized AttributeType
056 * <li>isHR<li> Tells if the value is a String or not
057 * <p>
058 * if the value is a String :
059 * <li>upValue</li> The User Provided value.
060 * <li>value</li> The normalized value.
061 * <p>
062 * if the value is binary :
063 * <li>upValueLength</li>
064 * <li>upValue</li> The User Provided value.
065 * <li>valueLength</li>
066 * <li>value</li> The normalized value.
067 *
068 * @param atav the AttributeTypeAndValue to serialize
069 * @param out the OutputStream in which the atav will be serialized
070 * @throws IOException If we can't serialize the atav
071 */
072 public static void serialize( AVA atav, ObjectOutput out ) throws IOException
073 {
074 if ( StringTools.isEmpty( atav.getUpName() ) ||
075 StringTools.isEmpty( atav.getUpType() ) ||
076 StringTools.isEmpty( atav.getNormType() ) ||
077 ( atav.getStart() < 0 ) ||
078 ( atav.getLength() < 2 ) || // At least a type and '='
079 ( atav.getUpValue().isNull() ) ||
080 ( atav.getNormValue().isNull() ) )
081 {
082 String message = "Cannot serialize an wrong ATAV, ";
083
084 if ( StringTools.isEmpty( atav.getUpName() ) )
085 {
086 message += "the upName should not be null or empty";
087 }
088 else if ( StringTools.isEmpty( atav.getUpType() ) )
089 {
090 message += "the upType should not be null or empty";
091 }
092 else if ( StringTools.isEmpty( atav.getNormType() ) )
093 {
094 message += "the normType should not be null or empty";
095 }
096 else if ( atav.getStart() < 0 )
097 {
098 message += "the start should not be < 0";
099 }
100 else if ( atav.getLength() < 2 )
101 {
102 message += "the length should not be < 2";
103 }
104 else if ( atav.getUpValue().isNull() )
105 {
106 message += "the upValue should not be null";
107 }
108 else if ( atav.getNormValue().isNull() )
109 {
110 message += "the value should not be null";
111 }
112
113 LOG.error( message );
114 throw new IOException( message );
115 }
116
117 out.writeUTF( atav.getUpName() );
118 out.writeInt( atav.getStart() );
119 out.writeInt( atav.getLength() );
120 out.writeUTF( atav.getUpType() );
121 out.writeUTF( atav.getNormType() );
122
123 boolean isHR = !atav.getNormValue().isBinary();
124
125 out.writeBoolean( isHR );
126
127 if ( isHR )
128 {
129 out.writeUTF( atav.getUpValue().getString() );
130 out.writeUTF( atav.getNormValue().getString() );
131 }
132 else
133 {
134 out.writeInt( atav.getUpValue().length() );
135 out.write( atav.getUpValue().getBytes() );
136 out.writeInt( atav.getNormValue().length() );
137 out.write( atav.getNormValue().getBytes() );
138 }
139 }
140
141
142 /**
143 * Deserialize an AttributeTypeAndValue object
144 *
145 * We read back the data to create a new ATAV. The structure
146 * read is exposed in the {@link AVA#writeExternal(ObjectOutput)}
147 * method<p>
148 *
149 * @param in the input stream
150 * @throws IOException If the input stream can't be read
151 * @return The constructed AttributeTypeAndValue
152 */
153 public static AVA deserialize( ObjectInput in ) throws IOException
154 {
155 String upName = in.readUTF();
156 int start = in.readInt();
157 int length = in.readInt();
158 String upType = in.readUTF();
159 String normType = in.readUTF();
160
161 boolean isHR = in.readBoolean();
162
163 try
164 {
165 if ( isHR )
166 {
167 Value<String> upValue = new StringValue( in.readUTF() );
168 Value<String> normValue = new StringValue( in.readUTF() );
169
170 AVA atav =
171 new AVA( upType, normType, upValue, normValue, upName );
172
173 return atav;
174 }
175 else
176 {
177 int upValueLength = in.readInt();
178 byte[] upValue = new byte[upValueLength];
179 in.readFully( upValue );
180
181 int valueLength = in.readInt();
182 byte[] normValue = new byte[valueLength];
183 in.readFully( normValue );
184
185 AVA atav =
186 new AVA( upType, normType,
187 new BinaryValue( upValue) ,
188 new BinaryValue( normValue ), upName );
189
190 return atav;
191 }
192 }
193 catch ( LdapInvalidDnException ine )
194 {
195 throw new IOException( ine.getMessage() );
196 }
197 }
198 }