001/* 002 * Copyright 2016-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2016-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2016-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.experimental; 037 038 039 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.LinkedHashMap; 043import java.util.List; 044 045import com.unboundid.ldap.sdk.Attribute; 046import com.unboundid.ldap.sdk.DeleteRequest; 047import com.unboundid.ldap.sdk.Entry; 048import com.unboundid.ldap.sdk.LDAPException; 049import com.unboundid.ldap.sdk.OperationType; 050import com.unboundid.ldap.sdk.ResultCode; 051import com.unboundid.util.NotMutable; 052import com.unboundid.util.StaticUtils; 053import com.unboundid.util.ThreadSafety; 054import com.unboundid.util.ThreadSafetyLevel; 055 056import static com.unboundid.ldap.sdk.experimental.ExperimentalMessages.*; 057 058 059 060/** 061 * This class represents an entry that holds information about a delete 062 * operation processed by an LDAP server, as per the specification described in 063 * draft-chu-ldap-logschema-00. 064 */ 065@NotMutable() 066@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 067public final class DraftChuLDAPLogSchema00DeleteEntry 068 extends DraftChuLDAPLogSchema00Entry 069{ 070 /** 071 * The name of the attribute used to hold information about attributes 072 * contained in the entry that was deleted. 073 */ 074 public static final String ATTR_DELETED_ATTRIBUTE = "reqOld"; 075 076 077 078 /** 079 * The serial version UID for this serializable class. 080 */ 081 private static final long serialVersionUID = -4326357861964770357L; 082 083 084 085 // The list of deleted attributes, if available. 086 private final List<Attribute> deletedAttributes; 087 088 089 090 /** 091 * Creates a new instance of this delete access log entry from the provided 092 * entry. 093 * 094 * @param entry The entry used to create this delete access log entry. 095 * 096 * @throws LDAPException If the provided entry cannot be decoded as a valid 097 * delete access log entry as per the specification 098 * contained in draft-chu-ldap-logschema-00. 099 */ 100 public DraftChuLDAPLogSchema00DeleteEntry(final Entry entry) 101 throws LDAPException 102 { 103 super(entry, OperationType.DELETE); 104 105 final byte[][] deletedAttrBytes = 106 entry.getAttributeValueByteArrays(ATTR_DELETED_ATTRIBUTE); 107 if ((deletedAttrBytes == null) || (deletedAttrBytes.length == 0)) 108 { 109 deletedAttributes = Collections.emptyList(); 110 return; 111 } 112 113 final LinkedHashMap<String,List<Attribute>> attrMap = new LinkedHashMap<>( 114 StaticUtils.computeMapCapacity(deletedAttrBytes.length)); 115 for (final byte[] attrBytes : deletedAttrBytes) 116 { 117 int colonPos = -1; 118 for (int i=0; i < attrBytes.length; i++) 119 { 120 if (attrBytes[i] == ':') 121 { 122 colonPos = i; 123 break; 124 } 125 } 126 127 if (colonPos < 0) 128 { 129 throw new LDAPException(ResultCode.DECODING_ERROR, 130 ERR_LOGSCHEMA_DECODE_DELETE_OLD_ATTR_MISSING_COLON.get( 131 entry.getDN(), ATTR_DELETED_ATTRIBUTE, 132 StaticUtils.toUTF8String(attrBytes))); 133 } 134 else if (colonPos == 0) 135 { 136 throw new LDAPException(ResultCode.DECODING_ERROR, 137 ERR_LOGSCHEMA_DECODE_DELETE_OLD_ATTR_MISSING_ATTR.get( 138 entry.getDN(), ATTR_DELETED_ATTRIBUTE, 139 StaticUtils.toUTF8String(attrBytes))); 140 } 141 142 if ((colonPos == (attrBytes.length - 1)) || 143 (attrBytes[colonPos+1] != ' ')) 144 { 145 throw new LDAPException(ResultCode.DECODING_ERROR, 146 ERR_LOGSCHEMA_DECODE_DELETE_OLD_ATTR_MISSING_SPACE.get( 147 entry.getDN(), ATTR_DELETED_ATTRIBUTE, 148 StaticUtils.toUTF8String(attrBytes))); 149 } 150 151 final String attrName = 152 StaticUtils.toUTF8String(attrBytes, 0, colonPos); 153 final String lowerName = StaticUtils.toLowerCase(attrName); 154 155 List<Attribute> attrList = attrMap.get(lowerName); 156 if (attrList == null) 157 { 158 attrList = new ArrayList<>(10); 159 attrMap.put(lowerName, attrList); 160 } 161 162 final byte[] attrValue = new byte[attrBytes.length - colonPos - 2]; 163 if (attrValue.length > 0) 164 { 165 System.arraycopy(attrBytes, colonPos + 2, attrValue, 0, 166 attrValue.length); 167 } 168 169 attrList.add(new Attribute(attrName, attrValue)); 170 } 171 172 final ArrayList<Attribute> oldAttributes = new ArrayList<>(attrMap.size()); 173 for (final List<Attribute> attrList : attrMap.values()) 174 { 175 if (attrList.size() == 1) 176 { 177 oldAttributes.addAll(attrList); 178 } 179 else 180 { 181 final byte[][] valueArray = new byte[attrList.size()][]; 182 for (int i=0; i < attrList.size(); i++) 183 { 184 valueArray[i] = attrList.get(i).getValueByteArray(); 185 } 186 oldAttributes.add(new Attribute(attrList.get(0).getName(), valueArray)); 187 } 188 } 189 190 deletedAttributes = Collections.unmodifiableList(oldAttributes); 191 } 192 193 194 195 /** 196 * Retrieves a list of the attributes from the entry that was deleted, if 197 * available. 198 * 199 * @return A list of the attributes from the entry that was deleted, or an 200 * empty list if no deleted attribute information was included in the 201 * access log entry. 202 */ 203 public List<Attribute> getDeletedAttributes() 204 { 205 return deletedAttributes; 206 } 207 208 209 210 /** 211 * Retrieves an {@code DeleteRequest} created from this delete access log 212 * entry. 213 * 214 * @return The {@code DeleteRequest} created from this delete access log 215 * entry. 216 */ 217 public DeleteRequest toDeleteRequest() 218 { 219 return new DeleteRequest(getTargetEntryDN(), getRequestControlArray()); 220 } 221}