/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011 ForgeRock AS
*/
package org.opends.server.tools;
import org.opends.messages.Message;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.SocketTimeoutException;
import org.opends.server.protocols.asn1.ASN1Exception;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.types.DN;
import org.opends.server.types.ByteString;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
* This class provides utility functions for all the client side tools.
*/
public class LDAPToolUtils
{
/**
* Parse the specified command line argument to create the
* appropriate LDAPControl. The argument string should be in the format
* controloid[:criticality[:value|::b64value|:<fileurl]]
*
* @param argString The argument string containing the encoded control
* information.
* @param err A print stream to which error messages should be
* written if a problem occurs.
*
* @return The control decoded from the provided string, or <CODE>null</CODE>
* if an error occurs while parsing the argument value.
*/
public static LDAPControl getControl(String argString, PrintStream err)
{
LDAPControl control = null;
String controlOID = null;
boolean controlCriticality = false;
ByteString controlValue = null;
int idx = argString.indexOf(":");
if(idx < 0)
{
controlOID = argString;
}
else
{
controlOID = argString.substring(0, idx);
}
String lowerOID = toLowerCase(controlOID);
if (lowerOID.equals("accountusable") || lowerOID.equals("accountusability"))
{
controlOID = OID_ACCOUNT_USABLE_CONTROL;
}
else if (lowerOID.equals("authzid") ||
lowerOID.equals("authorizationidentity"))
{
controlOID = OID_AUTHZID_REQUEST;
}
else if (lowerOID.equals("noop") || lowerOID.equals("no-op"))
{
controlOID = OID_LDAP_NOOP_OPENLDAP_ASSIGNED;
}
else if (lowerOID.equals("managedsait"))
{
controlOID = OID_MANAGE_DSAIT_CONTROL;
}
else if (lowerOID.equals("pwpolicy") || lowerOID.equals("passwordpolicy"))
{
controlOID = OID_PASSWORD_POLICY_CONTROL;
}
else if (lowerOID.equals("subtreedelete") || lowerOID.equals("treedelete"))
{
controlOID = OID_SUBTREE_DELETE_CONTROL;
}
else if (lowerOID.equals("realattrsonly") ||
lowerOID.equals("realattributesonly"))
{
controlOID = OID_REAL_ATTRS_ONLY;
}
else if (lowerOID.equals("virtualattrsonly") ||
lowerOID.equals("virtualattributesonly"))
{
controlOID = OID_VIRTUAL_ATTRS_ONLY;
}
else if(lowerOID.equals("effectiverights") ||
lowerOID.equals("geteffectiverights"))
{
controlOID = OID_GET_EFFECTIVE_RIGHTS;
}
if (idx < 0)
{
return new LDAPControl(controlOID);
}
String remainder = argString.substring(idx+1, argString.length());
idx = remainder.indexOf(":");
if(idx == -1)
{
if(remainder.equalsIgnoreCase("true"))
{
controlCriticality = true;
} else if(remainder.equalsIgnoreCase("false"))
{
controlCriticality = false;
} else
{
err.println("Invalid format for criticality value:" + remainder);
return null;
}
control = new LDAPControl(controlOID, controlCriticality);
return control;
}
String critical = remainder.substring(0, idx);
if(critical.equalsIgnoreCase("true"))
{
controlCriticality = true;
} else if(critical.equalsIgnoreCase("false"))
{
controlCriticality = false;
} else
{
err.println("Invalid format for criticality value:" + critical);
return null;
}
String valString = remainder.substring(idx+1, remainder.length());
if (valString.length() == 0)
{
control = new LDAPControl(controlOID, controlCriticality);
return control;
}
if(valString.charAt(0) == ':')
{
controlValue =
ByteString.valueOf(valString.substring(1, valString.length()));
} else if(valString.charAt(0) == '<')
{
// Read data from the file.
String filePath = valString.substring(1, valString.length());
try
{
byte[] val = readBytesFromFile(filePath, err);
controlValue = ByteString.wrap(val);
}
catch (Exception e)
{
return null;
}
} else
{
controlValue = ByteString.valueOf(valString);
}
control = new LDAPControl(controlOID, controlCriticality, controlValue);
return control;
}
/**
* Read the data from the specified file and return it in a byte array.
*
* @param filePath The path to the file that should be read.
* @param err A print stream to which error messages should be
* written if a problem occurs.
*
* @return A byte array containing the contents of the requested file.
*
* @throws IOException If a problem occurs while trying to read the
* specified file.
*/
public static byte[] readBytesFromFile(String filePath, PrintStream err)
throws IOException
{
byte[] val = null;
FileInputStream fis = null;
try
{
File file = new File(filePath);
fis = new FileInputStream (file);
long length = file.length();
val = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < val.length &&
(numRead=fis.read(val, offset, val.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < val.length)
{
err.println("Could not completely read file "+filePath);
return null;
}
return val;
} finally
{
if (fis != null)
{
fis.close();
}
}
}
/**
* Prints a multi-line error message with the provided information to the
* given print stream.
*
* @param err The print stream to use to write the error message.
* @param explanation The general explanation to provide to the user, or
* {@code null} if there is none.
* @param resultCode The result code returned from the server, or -1 if
* there is none.
* @param errorMessage The additional information / error message returned
* from the server, or {@code null} if there was none.
* @param matchedDN The matched DN returned from the server, or
* {@code null} if there was none.
*/
public static void printErrorMessage(PrintStream err, Message explanation,
int resultCode, Message errorMessage,
DN matchedDN)
{
if ((explanation != null) && (explanation.length() > 0))
{
err.println(explanation);
}
if (resultCode >= 0)
{
err.println(ERR_TOOL_RESULT_CODE.get(resultCode,
LDAPResultCode.toString(resultCode)));
}
if ((errorMessage != null) && (errorMessage.length() > 0))
{
err.println(ERR_TOOL_ERROR_MESSAGE.get(errorMessage));
}
if (matchedDN != null)
{
err.println(ERR_TOOL_MATCHED_DN.get(matchedDN.toString()));
}
}
/**
* Returns the message to be displayed to the user when an exception occurs.
* <br>
* The code simply checks that the exception corresponds to a client side
* time out.
* @param ae the asn1exception that occurred connecting to the server or
* handling the response from the server.
* @return the message to be displayed to the user when an exception occurs.
*/
public static String getMessageForConnectionException(ASN1Exception ae)
{
String msg;
Throwable cause = ae.getCause();
if (cause != null)
{
boolean isTimeout = false;
while (cause != null && !isTimeout)
{
isTimeout = cause instanceof SocketTimeoutException;
cause = cause.getCause();
}
if (isTimeout)
{
msg = ERR_CLIENT_SIDE_TIMEOUT.get(
ae.getMessageObject().toString()).toString();
}
else
{
msg = ae.getMessageObject().toString();
}
}
else
{
msg = ae.getMessageObject().toString();
}
return msg;
}
}