All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.ldap.sdk.unboundidds.logs.LogMessage Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2009-2022 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2009-2022 Ping Identity Corporation
 *
 * Licensed 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.
 */
/*
 * Copyright (C) 2009-2022 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk.unboundidds.logs;



import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Map;

import com.unboundid.util.ByteStringBuffer;
import com.unboundid.util.Debug;
import com.unboundid.util.NotExtensible;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;

import static com.unboundid.ldap.sdk.unboundidds.logs.LogMessages.*;



/**
 * This class provides a data structure that holds information about a log
 * message contained in a Directory Server access or error log file.
 * 
*
* NOTE: This class, and other classes within the * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only * supported for use against Ping Identity, UnboundID, and * Nokia/Alcatel-Lucent 8661 server products. These classes provide support * for proprietary functionality or for external specifications that are not * considered stable or mature enough to be guaranteed to work in an * interoperable way with other types of LDAP servers. *
*/ @NotExtensible() @NotMutable() @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) public class LogMessage implements Serializable { /** * The format string that will be used for log message timestamps * with seconds-level precision enabled. */ @NotNull private static final String TIMESTAMP_SEC_FORMAT = "'['dd/MMM/yyyy:HH:mm:ss Z']'"; /** * The format string that will be used for log message timestamps * with seconds-level precision enabled. */ @NotNull private static final String TIMESTAMP_MS_FORMAT = "'['dd/MMM/yyyy:HH:mm:ss.SSS Z']'"; /** * The thread-local date formatter. */ @NotNull private static final ThreadLocal dateSecFormat = new ThreadLocal<>(); /** * The thread-local date formatter. */ @NotNull private static final ThreadLocal dateMsFormat = new ThreadLocal<>(); /** * The serial version UID for this serializable class. */ private static final long serialVersionUID = -1210050773534504972L; // The timestamp for this log message. @NotNull private final Date timestamp; // The map of named fields contained in this log message. @NotNull private final Map namedValues; // The set of unnamed values contained in this log message. @NotNull private final Set unnamedValues; // The string representation of this log message. @NotNull private final String messageString; /** * Creates a log message from the provided log message. * * @param m The log message to use to create this log message. */ protected LogMessage(@NotNull final LogMessage m) { timestamp = m.timestamp; unnamedValues = m.unnamedValues; namedValues = m.namedValues; messageString = m.messageString; } /** * Parses the provided string as a log message. * * @param s The string to be parsed as a log message. * * @throws LogException If the provided string cannot be parsed as a valid * log message. */ protected LogMessage(@NotNull final String s) throws LogException { messageString = s; // The first element should be the timestamp, which should end with a // closing bracket. final int bracketPos = s.indexOf(']'); if (bracketPos < 0) { throw new LogException(s, ERR_LOG_MESSAGE_NO_TIMESTAMP.get()); } final String timestampString = s.substring(0, bracketPos+1); SimpleDateFormat f; if (timestampIncludesMilliseconds(timestampString)) { f = dateMsFormat.get(); if (f == null) { f = new SimpleDateFormat(TIMESTAMP_MS_FORMAT); f.setLenient(false); dateMsFormat.set(f); } } else { f = dateSecFormat.get(); if (f == null) { f = new SimpleDateFormat(TIMESTAMP_SEC_FORMAT); f.setLenient(false); dateSecFormat.set(f); } } try { timestamp = f.parse(timestampString); } catch (final Exception e) { Debug.debugException(e); throw new LogException(s, ERR_LOG_MESSAGE_INVALID_TIMESTAMP.get( StaticUtils.getExceptionMessage(e)), e); } // The remainder of the message should consist of named and unnamed values. final LinkedHashMap named = new LinkedHashMap<>(StaticUtils.computeMapCapacity(10)); final LinkedHashSet unnamed = new LinkedHashSet<>(StaticUtils.computeMapCapacity(10)); parseTokens(s, bracketPos+1, named, unnamed); namedValues = Collections.unmodifiableMap(named); unnamedValues = Collections.unmodifiableSet(unnamed); } /** * Parses the set of named and unnamed tokens from the provided message * string. * * @param s The complete message string being parsed. * @param startPos The position at which to start parsing. * @param named The map in which to place the named tokens. * @param unnamed The set in which to place the unnamed tokens. * * @throws LogException If a problem occurs while processing the tokens. */ private static void parseTokens(@NotNull final String s, final int startPos, @NotNull final Map named, @NotNull final Set unnamed) throws LogException { boolean inQuotes = false; final StringBuilder buffer = new StringBuilder(); for (int p=startPos; p < s.length(); p++) { final char c = s.charAt(p); if ((c == ' ') && (! inQuotes)) { if (buffer.length() > 0) { processToken(s, buffer.toString(), named, unnamed); buffer.delete(0, buffer.length()); } } else if (c == '"') { inQuotes = (! inQuotes); } else { buffer.append(c); } } if (buffer.length() > 0) { processToken(s, buffer.toString(), named, unnamed); } } /** * Processes the provided token and adds it to the appropriate collection. * * @param s The complete message string being parsed. * @param token The token to be processed. * @param named The map in which to place named tokens. * @param unnamed The set in which to place unnamed tokens. * * @throws LogException If a problem occurs while processing the token. */ private static void processToken(@NotNull final String s, @NotNull final String token, @NotNull final Map named, @NotNull final Set unnamed) throws LogException { // If the token contains an equal sign, then it's a named token. Otherwise, // it's unnamed. final int equalPos = token.indexOf('='); if (equalPos < 0) { // Unnamed tokens should never need any additional processing. unnamed.add(token); } else { // The name of named tokens should never need any additional processing. // The value may need to be processed to remove surrounding quotes and/or // to un-escape any special characters. final String name = token.substring(0, equalPos); final String value = processValue(s, token.substring(equalPos+1)); named.put(name, value); } } /** * Performs any processing needed on the provided value to obtain the original * text. This may include removing surrounding quotes and/or un-escaping any * special characters. * * @param s The complete message string being parsed. * @param v The value to be processed. * * @return The processed version of the provided string. * * @throws LogException If a problem occurs while processing the value. */ @NotNull() private static String processValue(@NotNull final String s, @NotNull final String v) throws LogException { final ByteStringBuffer b = new ByteStringBuffer(); for (int i=0; i < v.length(); i++) { final char c = v.charAt(i); if (c == '"') { // This should only happen at the beginning or end of the string, in // which case it should be stripped out so we don't need to do anything. } else if (c == '#') { // Every octothorpe should be followed by exactly two hex digits, which // represent a byte of a UTF-8 character. if (i > (v.length() - 3)) { throw new LogException(s, ERR_LOG_MESSAGE_INVALID_ESCAPED_CHARACTER.get(v)); } byte rawByte = 0x00; for (int j=0; j < 2; j++) { rawByte <<= 4; switch (v.charAt(++i)) { case '0': break; case '1': rawByte |= 0x01; break; case '2': rawByte |= 0x02; break; case '3': rawByte |= 0x03; break; case '4': rawByte |= 0x04; break; case '5': rawByte |= 0x05; break; case '6': rawByte |= 0x06; break; case '7': rawByte |= 0x07; break; case '8': rawByte |= 0x08; break; case '9': rawByte |= 0x09; break; case 'a': case 'A': rawByte |= 0x0A; break; case 'b': case 'B': rawByte |= 0x0B; break; case 'c': case 'C': rawByte |= 0x0C; break; case 'd': case 'D': rawByte |= 0x0D; break; case 'e': case 'E': rawByte |= 0x0E; break; case 'f': case 'F': rawByte |= 0x0F; break; default: throw new LogException(s, ERR_LOG_MESSAGE_INVALID_ESCAPED_CHARACTER.get(v)); } } b.append(rawByte); } else { b.append(c); } } return b.toString(); } /** * Determines whether a string that represents a timestamp includes a * millisecond component. * * @param timestamp The timestamp string to examine. * * @return {@code true} if the given string includes a millisecond component, * or {@code false} if not. */ private static boolean timestampIncludesMilliseconds( @NotNull final String timestamp) { // The sec and ms format strings differ at the 22nd character. return ((timestamp.length() > 21) && (timestamp.charAt(21) == '.')); } /** * Retrieves the timestamp for this log message. * * @return The timestamp for this log message. */ @NotNull() public final Date getTimestamp() { return timestamp; } /** * Retrieves the set of named tokens for this log message, mapped from the * name to the corresponding value. * * @return The set of named tokens for this log message. */ @NotNull() public final Map getNamedValues() { return namedValues; } /** * Retrieves the value of the token with the specified name. * * @param name The name of the token to retrieve. * * @return The value of the token with the specified name, or {@code null} if * there is no value with the specified name. */ @Nullable() public final String getNamedValue(@NotNull final String name) { return namedValues.get(name); } /** * Retrieves the value of the token with the specified name as a * {@code Boolean}. * * @param name The name of the token to retrieve. * * @return The value of the token with the specified name as a * {@code Boolean}, or {@code null} if there is no value with the * specified name or the value cannot be parsed as a {@code Boolean}. */ @Nullable() public final Boolean getNamedValueAsBoolean(@NotNull final String name) { final String s = namedValues.get(name); if (s == null) { return null; } final String lowerValue = StaticUtils.toLowerCase(s); if (lowerValue.equals("true") || lowerValue.equals("t") || lowerValue.equals("yes") || lowerValue.equals("y") || lowerValue.equals("on") || lowerValue.equals("1")) { return Boolean.TRUE; } else if (lowerValue.equals("false") || lowerValue.equals("f") || lowerValue.equals("no") || lowerValue.equals("n") || lowerValue.equals("off") || lowerValue.equals("0")) { return Boolean.FALSE; } else { return null; } } /** * Retrieves the value of the token with the specified name as a * {@code Double}. * * @param name The name of the token to retrieve. * * @return The value of the token with the specified name as a * {@code Double}, or {@code null} if there is no value with the * specified name or the value cannot be parsed as a {@code Double}. */ @Nullable() public final Double getNamedValueAsDouble(@NotNull final String name) { final String s = namedValues.get(name); if (s == null) { return null; } try { return Double.valueOf(s); } catch (final Exception e) { Debug.debugException(e); return null; } } /** * Retrieves the value of the token with the specified name as an * {@code Integer}. * * @param name The name of the token to retrieve. * * @return The value of the token with the specified name as an * {@code Integer}, or {@code null} if there is no value with the * specified name or the value cannot be parsed as an * {@code Integer}. */ @Nullable() public final Integer getNamedValueAsInteger(@NotNull final String name) { final String s = namedValues.get(name); if (s == null) { return null; } try { return Integer.valueOf(s); } catch (final Exception e) { Debug.debugException(e); return null; } } /** * Retrieves the value of the token with the specified name as a {@code Long}. * * @param name The name of the token to retrieve. * * @return The value of the token with the specified name as a {@code Long}, * or {@code null} if there is no value with the specified name or * the value cannot be parsed as a {@code Long}. */ @Nullable() public final Long getNamedValueAsLong(@NotNull final String name) { final String s = namedValues.get(name); if (s == null) { return null; } try { return Long.valueOf(s); } catch (final Exception e) { Debug.debugException(e); return null; } } /** * Retrieves the set of unnamed tokens for this log message. * * @return The set of unnamed tokens for this log message. */ @NotNull() public final Set getUnnamedValues() { return unnamedValues; } /** * Indicates whether this log message has the specified unnamed value. * * @param value The value for which to make the determination. * * @return {@code true} if this log message has the specified unnamed value, * or {@code false} if not. */ public final boolean hasUnnamedValue(@NotNull final String value) { return unnamedValues.contains(value); } /** * Retrieves a string representation of this log message. * * @return A string representation of this log message. */ @Override() @NotNull() public final String toString() { return messageString; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy