001/* 002 * Copyright 2017-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2017-2024 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) 2017-2024 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.unboundidds.tools; 037 038 039 040import java.io.OutputStream; 041import java.util.ArrayList; 042import java.util.List; 043 044import com.unboundid.ldap.sdk.Attribute; 045import com.unboundid.ldap.sdk.ExtendedResult; 046import com.unboundid.ldap.sdk.LDAPConnection; 047import com.unboundid.ldap.sdk.LDAPResult; 048import com.unboundid.ldap.sdk.SearchResultEntry; 049import com.unboundid.ldap.sdk.SearchResultReference; 050import com.unboundid.util.ColumnFormatter; 051import com.unboundid.util.FormattableColumn; 052import com.unboundid.util.HorizontalAlignment; 053import com.unboundid.util.NotNull; 054import com.unboundid.util.OutputFormat; 055import com.unboundid.util.StaticUtils; 056import com.unboundid.util.ThreadSafety; 057import com.unboundid.util.ThreadSafetyLevel; 058 059 060 061/** 062 * This class provides an {@link LDAPResultWriter} instance that uses a 063 * {@link ColumnFormatter} to output search result entries in a format like CSV 064 * or tab-delimited text. Only a single value from each attribute will be used, 065 * and an empty string will be used for attributes without any values. 066 * <BR> 067 * <BLOCKQUOTE> 068 * <B>NOTE:</B> This class, and other classes within the 069 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 070 * supported for use against Ping Identity, UnboundID, and 071 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 072 * for proprietary functionality or for external specifications that are not 073 * considered stable or mature enough to be guaranteed to work in an 074 * interoperable way with other types of LDAP servers. 075 * </BLOCKQUOTE> 076 */ 077@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 078public final class ColumnBasedLDAPResultWriter 079 extends LDAPResultWriter 080{ 081 // A list used to hold the lines for a formatted representation of a search 082 // result entry or reference. 083 @NotNull private final ArrayList<String> formattedLines; 084 085 // Indicates whether to include all values of a multivalued attribute. 086 private final boolean includeAllValues; 087 088 // The column formatter that will be used to generate the output. 089 @NotNull private final ColumnFormatter formatter; 090 091 // The maximum width to use for comments in the output. 092 private final int maxCommentWidth; 093 094 // An array that holds the values for each of the columns to be output. 095 @NotNull private final Object[] columnValues; 096 097 // The names of the requested attributes. 098 @NotNull private final String[] attributes; 099 100 // A string builder used to hold the formatted representation of the lines 101 // that comprise a search result entry or reference. 102 @NotNull private final StringBuilder formattedLineBuffer; 103 104 105 106 /** 107 * Creates a new instance of this LDAP result writer. 108 * 109 * @param outputStream The output stream to which the 110 * @param outputFormat The output format to use for search entry 111 * attributes. 112 * @param requestedAttributes The names of the requested attributes. 113 * @param maxCommentWidth The maximum width to use for comments in the 114 * output. This will be ignored for information 115 * about search result entries. 116 * @param includeAllValues Indicates whether to include all values of a 117 * multivalued attribute. If this is 118 * {@code true}, then a vertical bar (|) will be 119 * used to separate the values within each field. 120 */ 121 public ColumnBasedLDAPResultWriter( 122 @NotNull final OutputStream outputStream, 123 @NotNull final OutputFormat outputFormat, 124 @NotNull final List<String> requestedAttributes, 125 final int maxCommentWidth, 126 final boolean includeAllValues) 127 { 128 super(outputStream); 129 130 this.maxCommentWidth = maxCommentWidth; 131 this.includeAllValues = includeAllValues; 132 133 attributes = new String[requestedAttributes.size()]; 134 requestedAttributes.toArray(attributes); 135 136 columnValues = new Object[attributes.length + 1]; 137 138 final FormattableColumn[] columns = 139 new FormattableColumn[attributes.length + 1]; 140 columns[0] = new FormattableColumn(10, HorizontalAlignment.LEFT, "DN"); 141 142 for (int i=0; i < attributes.length; i++) 143 { 144 columns[i+1] = 145 new FormattableColumn(10, HorizontalAlignment.LEFT, attributes[i]); 146 } 147 148 formatter = new ColumnFormatter(false, null, outputFormat, " ", columns); 149 150 formattedLines = new ArrayList<>(20); 151 formattedLineBuffer = new StringBuilder(100); 152 } 153 154 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override() 160 public void writeComment(@NotNull final String comment) 161 { 162 // Comments will not be written in this format. 163 } 164 165 166 167 /** 168 * {@inheritDoc} 169 */ 170 @Override() 171 public void writeHeader() 172 { 173 for (final String headerLine : formatter.getHeaderLines(false)) 174 { 175 print("# "); 176 println(headerLine); 177 } 178 } 179 180 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override() 186 public void writeSearchResultEntry(@NotNull final SearchResultEntry entry) 187 { 188 columnValues[0] = entry.getDN(); 189 190 int i=1; 191 final StringBuilder buffer = new StringBuilder(); 192 for (final String attributeName : attributes) 193 { 194 final Attribute a = entry.getAttribute(attributeName); 195 if ((a == null) || (a.size() == 0)) 196 { 197 columnValues[i] = ""; 198 } 199 else if (includeAllValues && (a.size() > 1)) 200 { 201 buffer.setLength(0); 202 for (final String v : a.getValues()) 203 { 204 if (buffer.length() > 0) 205 { 206 buffer.append('|'); 207 } 208 buffer.append(v); 209 } 210 211 columnValues[i] = buffer.toString(); 212 } 213 else 214 { 215 columnValues[i] = a.getValue(); 216 } 217 218 i++; 219 } 220 221 println(formatter.formatRow(columnValues)); 222 } 223 224 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override() 230 public void writeSearchResultReference( 231 @NotNull final SearchResultReference ref) 232 { 233 formattedLines.clear(); 234 formattedLineBuffer.setLength(0); 235 236 ResultUtils.formatSearchResultReference(formattedLines, ref, 237 maxCommentWidth); 238 for (final String s : formattedLines) 239 { 240 formattedLineBuffer.append(s); 241 formattedLineBuffer.append(StaticUtils.EOL); 242 } 243 244 println(formattedLineBuffer.toString()); 245 } 246 247 248 249 /** 250 * {@inheritDoc} 251 */ 252 @Override() 253 public void writeResult(@NotNull final LDAPResult result) 254 { 255 formattedLines.clear(); 256 formattedLineBuffer.setLength(0); 257 258 ResultUtils.formatResult(formattedLines, result, true, false, 0, 259 maxCommentWidth); 260 for (final String s : formattedLines) 261 { 262 formattedLineBuffer.append(s); 263 formattedLineBuffer.append(StaticUtils.EOL); 264 } 265 println(formattedLineBuffer.toString()); 266 } 267 268 269 270 /** 271 * {@inheritDoc} 272 */ 273 @Override() 274 public void writeUnsolicitedNotification( 275 @NotNull final LDAPConnection connection, 276 @NotNull final ExtendedResult notification) 277 { 278 formattedLines.clear(); 279 formattedLineBuffer.setLength(0); 280 281 ResultUtils.formatUnsolicitedNotification(formattedLines, notification, 282 true, 0, maxCommentWidth); 283 for (final String s : formattedLines) 284 { 285 formattedLineBuffer.append(s); 286 formattedLineBuffer.append(StaticUtils.EOL); 287 } 288 println(formattedLineBuffer.toString()); 289 } 290}