You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/11/22 17:05:50 UTC
cayenne git commit: fixing some PMD warnings
Repository: cayenne
Updated Branches:
refs/heads/master 15297ccaf -> 6cdfdbbcb
fixing some PMD warnings
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/6cdfdbbc
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/6cdfdbbc
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/6cdfdbbc
Branch: refs/heads/master
Commit: 6cdfdbbcb94f217b1e486992561f6b8febda5f84
Parents: 15297cc
Author: aadamchik <aa...@apache.org>
Authored: Sat Nov 22 19:05:44 2014 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sat Nov 22 19:05:44 2014 +0300
----------------------------------------------------------------------
.../main/java/org/apache/cayenne/util/Util.java | 1035 +++++++++---------
1 file changed, 520 insertions(+), 515 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/6cdfdbbc/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java b/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java
index 1d5ae49..1700b67 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/util/Util.java
@@ -67,519 +67,524 @@ import org.xml.sax.XMLReader;
*/
public class Util {
- @Deprecated
- private static DefaultAdhocObjectFactory objectFactory;
-
- static {
- objectFactory = new DefaultAdhocObjectFactory(null, new DefaultClassLoaderManager());
- }
-
- /**
- * Converts URL to file. Throws {@link IllegalArgumentException} if the URL
- * is not a "file://" URL.
- */
- public static File toFile(URL url) throws IllegalArgumentException {
- // must convert spaces to %20, or URL->URI conversion may fail
- String urlString = url.toExternalForm();
-
- URI uri;
- try {
- uri = new URI(urlString.replace(" ", "%20"));
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException("URL " + urlString + " can't be converted to URI", e);
- }
- return new File(uri);
- }
-
- /**
- * Reads file contents, returning it as a String, using System default line
- * separator.
- */
- public static String stringFromFile(File file) throws IOException {
- return stringFromFile(file, System.getProperty("line.separator"));
- }
-
- /**
- * Reads file contents, returning it as a String, joining lines with
- * provided separator.
- */
- public static String stringFromFile(File file, String joinWith) throws IOException {
- StringBuilder buf = new StringBuilder();
- BufferedReader in = new BufferedReader(new FileReader(file));
-
- try {
- String line = null;
- while ((line = in.readLine()) != null) {
- buf.append(line).append(joinWith);
- }
- } finally {
- in.close();
- }
- return buf.toString();
- }
-
- /**
- * @param strings
- * The list of strings to join.
- * @param separator
- * The separator between the strings.
- * @return A single string of all the input strings separated by the
- * separator.
- */
- public static String join(List<String> strings, String separator) {
- if (strings == null || strings.size() == 0)
- return "";
-
- if (separator == null)
- separator = "";
-
- StringBuilder builder = new StringBuilder();
-
- for (String string : strings) {
- if (builder.length() > 0)
- builder.append(separator);
- builder.append(string);
- }
-
- return builder.toString();
- }
-
- /**
- * Replaces all backslashes "\" with forward slashes "/". Convenience method
- * to convert path Strings to URI format.
- */
- public static String substBackslashes(String string) {
- return RegexUtil.substBackslashes(string);
- }
-
- /**
- * Looks up and returns the root cause of an exception. If none is found,
- * returns supplied Throwable object unchanged. If root is found,
- * recursively "unwraps" it, and returns the result to the user.
- */
- public static Throwable unwindException(Throwable th) {
- if (th instanceof SAXException) {
- SAXException sax = (SAXException) th;
- if (sax.getException() != null) {
- return unwindException(sax.getException());
- }
- } else if (th instanceof SQLException) {
- SQLException sql = (SQLException) th;
- if (sql.getNextException() != null) {
- return unwindException(sql.getNextException());
- }
- } else if (th.getCause() != null) {
- return unwindException(th.getCause());
- }
-
- return th;
- }
-
- /**
- * Compares two objects similar to "Object.equals(Object)". Unlike
- * Object.equals(..), this method doesn't throw an exception if any of the
- * two objects is null.
- */
- public static boolean nullSafeEquals(Object o1, Object o2) {
-
- if (o1 == null) {
- return o2 == null;
- }
-
- // Arrays must be handled differently since equals() only does
- // an "==" for an array and ignores equivalence. If an array, use
- // the Jakarta Commons Language component EqualsBuilder to determine
- // the types contained in the array and do individual comparisons.
- if (o1.getClass().isArray()) {
- EqualsBuilder builder = new EqualsBuilder();
- builder.append(o1, o2);
- return builder.isEquals();
- } else { // It is NOT an array, so use regular equals()
- return o1.equals(o2);
- }
- }
-
- /**
- * Compares two objects similar to "Comparable.compareTo(Object)". Unlike
- * Comparable.compareTo(..), this method doesn't throw an exception if any
- * of the two objects is null.
- *
- * @since 1.1
- */
- public static <T> int nullSafeCompare(boolean nullsFirst, Comparable<T> o1, T o2) {
- if (o1 == null && o2 == null) {
- return 0;
- } else if (o1 == null) {
- return nullsFirst ? -1 : 1;
- } else if (o2 == null) {
- return nullsFirst ? 1 : -1;
- } else {
- return o1.compareTo(o2);
- }
- }
-
- /**
- * Returns true, if the String is null or an empty string.
- */
- public static boolean isEmptyString(String string) {
- return string == null || string.length() == 0;
- }
-
- /**
- * Creates Serializable object copy using serialization/deserialization.
- */
- public static <T extends Serializable> T cloneViaSerialization(T object) throws Exception {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream() {
-
- @Override
- public byte[] toByteArray() {
- return buf;
- }
- };
-
- ObjectOutputStream out = new ObjectOutputStream(bytes);
- out.writeObject(object);
- out.close();
-
- ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()));
- T copy = (T) in.readObject();
-
- // no need to close the stream - we created it and now will be throwing
- // away...
- // in.close();
-
- return copy;
- }
-
- /**
- * Creates an XMLReader with default feature set. Note that all Cayenne
- * internal XML parsers should probably use XMLReader obtained via this
- * method for consistency sake, and can customize feature sets as needed.
- */
- public static XMLReader createXmlReader() throws SAXException, ParserConfigurationException {
- SAXParserFactory spf = SAXParserFactory.newInstance();
-
- // Create a JAXP SAXParser
- SAXParser saxParser = spf.newSAXParser();
-
- // Get the encapsulated SAX XMLReader
- XMLReader reader = saxParser.getXMLReader();
-
- // set default features
- reader.setFeature("http://xml.org/sax/features/namespaces", true);
-
- return reader;
- }
-
- /**
- * Returns package name for the Java class as a path separated with forward
- * slash ("/"). Method is used to lookup resources that are located in
- * package subdirectories. For example, a String "a/b/c" will be returned
- * for class name "a.b.c.ClassName".
- */
- public static String getPackagePath(String className) {
- return RegexUtil.getPackagePath(className);
- }
-
- /**
- * Returns an unqualified class name for the fully qualified name.
- *
- * @since 3.0
- */
- public static String stripPackageName(String className) {
- if (className == null || className.length() == 0)
- return className;
-
- int lastDot = className.lastIndexOf('.');
-
- if ((-1 == lastDot) || ((className.length() - 1) == lastDot))
- return className;
-
- return className.substring(lastDot + 1);
- }
-
- /**
- * Creates a mutable map out of two arrays with keys and values.
- *
- * @since 1.2
- */
- public static <K, V> Map<K, V> toMap(K[] keys, V[] values) {
- int keysSize = (keys != null) ? keys.length : 0;
- int valuesSize = (values != null) ? values.length : 0;
-
- if (keysSize == 0 && valuesSize == 0) {
- // return mutable map
- return new HashMap<K, V>();
- }
-
- if (keysSize != valuesSize) {
- throw new IllegalArgumentException("The number of keys doesn't match the number of values.");
- }
-
- Map<K, V> map = new HashMap<K, V>();
- for (int i = 0; i < keysSize; i++) {
- map.put(keys[i], values[i]);
- }
-
- return map;
- }
-
- /**
- * Extracts extension from the file name. Dot is not included in the
- * returned string.
- */
- public static String extractFileExtension(String fileName) {
- int dotInd = fileName.lastIndexOf('.');
-
- // if dot is in the first position,
- // we are dealing with a hidden file rather than an extension
- return (dotInd > 0 && dotInd < fileName.length()) ? fileName.substring(dotInd + 1) : null;
- }
-
- /**
- * Strips extension from the file name.
- */
- public static String stripFileExtension(String fileName) {
- int dotInd = fileName.lastIndexOf('.');
-
- // if dot is in the first position,
- // we are dealing with a hidden file rather than an extension
- return (dotInd > 0) ? fileName.substring(0, dotInd) : fileName;
- }
-
- /**
- * Strips "\n", "\r\n", "\r" from the argument string, replacing them with a
- * provided character.
- *
- * @since 3.1
- */
- public static String stripLineBreaks(String string, char replaceWith) {
-
- if (string == null) {
- return null;
- }
-
- int len = string.length();
- char[] buffer = new char[len];
- boolean matched = false;
-
- int j = 0;
- for (int i = 0; i < len; i++, j++) {
- char c = string.charAt(i);
-
- // skip \n, \r, \r\n
- if (c == '\n' || c == '\r') {
-
- matched = true;
-
- // do lookahead
- if (i + 1 < len && string.charAt(i + 1) == '\n') {
- i++;
- }
-
- buffer[j] = replaceWith;
- } else {
- buffer[j] = c;
- }
- }
-
- return matched ? new String(buffer, 0, j) : string;
- }
-
- /**
- * Encodes a string so that it can be used as an attribute value in an XML
- * document. Will do conversion of the greater/less signs, quotes and
- * ampersands.
- */
- public static String encodeXmlAttribute(String string) {
- if (string == null) {
- return null;
- }
-
- int len = string.length();
- if (len == 0) {
- return string;
- }
-
- StringBuilder encoded = new StringBuilder();
- for (int i = 0; i < len; i++) {
- char c = string.charAt(i);
- if (c == '<')
- encoded.append("<");
- else if (c == '\"')
- encoded.append(""");
- else if (c == '>')
- encoded.append(">");
- else if (c == '\'')
- encoded.append("'");
- else if (c == '&')
- encoded.append("&");
- else
- encoded.append(c);
- }
-
- return encoded.toString();
- }
-
- /**
- * Trims long strings substituting middle part with "...".
- *
- * @param str
- * String to trim.
- * @param maxLength
- * maximum allowable length. Must be at least 5, or an
- * IllegalArgumentException is thrown.
- * @return String
- */
- public static String prettyTrim(String str, int maxLength) {
- if (maxLength < 5) {
- throw new IllegalArgumentException("Algorithm for 'prettyTrim' works only with length >= 5. "
- + "Supplied length is " + maxLength);
- }
-
- if (str == null || str.length() <= maxLength) {
- return str;
- }
-
- // find a section to cut off
- int len = maxLength - 3;
- int startLen = len / 2;
- int endLen = len - startLen;
-
- return str.substring(0, startLen) + "..." + str.substring(str.length() - endLen);
- }
-
- /**
- * Returns a sorted iterator from an unsorted one. Use this method as a last
- * resort, since it is much less efficient then just sorting a collection
- * that backs the original iterator.
- */
- public static <T> Iterator<T> sortedIterator(Iterator<T> it, Comparator<T> comparator) {
- List<T> list = new ArrayList<T>();
- while (it.hasNext()) {
- list.add(it.next());
- }
-
- Collections.sort(list, comparator);
- return list.iterator();
- }
-
- /**
- * Builds a hashCode of Collection.
- */
- public static int hashCode(Collection<?> c) {
- HashCodeBuilder builder = new HashCodeBuilder();
- for (Object o : c) {
- builder.append(o);
- }
- return builder.toHashCode();
- }
-
- /**
- * @since 1.2
- */
- public static Pattern sqlPatternToPattern(String pattern, boolean ignoreCase) {
- String preprocessed = RegexUtil.sqlPatternToRegex(pattern);
-
- int flag = (ignoreCase) ? Pattern.CASE_INSENSITIVE : 0;
- return Pattern.compile(preprocessed, flag);
- }
-
- /**
- * Returns true if a Member is accessible via reflection under normal Java
- * access controls.
- *
- * @since 1.2
- */
- public static boolean isAccessible(Member member) {
- return Modifier.isPublic(member.getModifiers()) && Modifier.isPublic(member.getDeclaringClass().getModifiers());
- }
-
- /**
- * Creates a Java class, handling regular class names as well as
- * single-dimensional arrays and primitive types.
- *
- * @since 1.2
- * @deprecated since 4.0 this method based on statically defined class
- * loading algorithm is not going to work in environments like
- * OSGi. {@link AdhocObjectFactory} should be used as it can
- * provide the environment-specific class loading policy.
- */
- @Deprecated
- public static Class<?> getJavaClass(String className) throws ClassNotFoundException {
- return objectFactory.getJavaClass(className);
- }
-
- static void setReverse(final Persistent sourceObject, String propertyName, final Persistent targetObject) {
-
- ArcProperty property = (ArcProperty) Cayenne.getClassDescriptor(sourceObject).getProperty(propertyName);
- ArcProperty reverseArc = property.getComplimentaryReverseArc();
- if (reverseArc != null) {
- reverseArc.visit(new PropertyVisitor() {
-
- public boolean visitToMany(ToManyProperty property) {
- property.addTargetDirectly(targetObject, sourceObject);
- return false;
- }
-
- public boolean visitToOne(ToOneProperty property) {
- property.setTarget(targetObject, sourceObject, false);
- return false;
- }
-
- public boolean visitAttribute(AttributeProperty property) {
- return false;
- }
-
- });
-
- sourceObject.getObjectContext().getGraphManager()
- .arcCreated(targetObject.getObjectId(), sourceObject.getObjectId(), reverseArc.getName());
-
- markAsDirty(targetObject);
- }
- }
-
- static void unsetReverse(final Persistent sourceObject, String propertyName, final Persistent targetObject) {
-
- ArcProperty property = (ArcProperty) Cayenne.getClassDescriptor(sourceObject).getProperty(propertyName);
- ArcProperty reverseArc = property.getComplimentaryReverseArc();
- if (reverseArc != null) {
- reverseArc.visit(new PropertyVisitor() {
-
- public boolean visitToMany(ToManyProperty property) {
- property.removeTargetDirectly(targetObject, sourceObject);
- return false;
- }
-
- public boolean visitToOne(ToOneProperty property) {
- property.setTarget(targetObject, null, false);
- return false;
- }
-
- public boolean visitAttribute(AttributeProperty property) {
- return false;
- }
-
- });
-
- sourceObject.getObjectContext().getGraphManager()
- .arcDeleted(targetObject.getObjectId(), sourceObject.getObjectId(), reverseArc.getName());
-
- markAsDirty(targetObject);
- }
- }
-
- /**
- * Changes object state to MODIFIED if needed, returning true if the change
- * has occurred, false if not.
- */
- static boolean markAsDirty(Persistent object) {
- if (object.getPersistenceState() == PersistenceState.COMMITTED) {
- object.setPersistenceState(PersistenceState.MODIFIED);
- return true;
- }
-
- return false;
- }
+ @Deprecated
+ private static DefaultAdhocObjectFactory objectFactory;
+
+ static {
+ objectFactory = new DefaultAdhocObjectFactory(null, new DefaultClassLoaderManager());
+ }
+
+ /**
+ * Converts URL to file. Throws {@link IllegalArgumentException} if the URL
+ * is not a "file://" URL.
+ */
+ public static File toFile(URL url) throws IllegalArgumentException {
+ // must convert spaces to %20, or URL->URI conversion may fail
+ String urlString = url.toExternalForm();
+
+ URI uri;
+ try {
+ uri = new URI(urlString.replace(" ", "%20"));
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("URL " + urlString + " can't be converted to URI", e);
+ }
+ return new File(uri);
+ }
+
+ /**
+ * Reads file contents, returning it as a String, using System default line
+ * separator.
+ */
+ public static String stringFromFile(File file) throws IOException {
+ return stringFromFile(file, System.getProperty("line.separator"));
+ }
+
+ /**
+ * Reads file contents, returning it as a String, joining lines with
+ * provided separator.
+ */
+ public static String stringFromFile(File file, String joinWith) throws IOException {
+ StringBuilder buf = new StringBuilder();
+ BufferedReader in = new BufferedReader(new FileReader(file));
+
+ try {
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ buf.append(line).append(joinWith);
+ }
+ } finally {
+ in.close();
+ }
+ return buf.toString();
+ }
+
+ /**
+ * @param strings
+ * The list of strings to join.
+ * @param separator
+ * The separator between the strings.
+ * @return A single string of all the input strings separated by the
+ * separator.
+ */
+ public static String join(List<String> strings, String separator) {
+ if (strings == null || strings.size() == 0) {
+ return "";
+ }
+
+ if (separator == null) {
+ separator = "";
+ }
+
+ StringBuilder builder = new StringBuilder();
+
+ for (String string : strings) {
+ if (builder.length() > 0) {
+ builder.append(separator);
+ }
+
+ builder.append(string);
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Replaces all backslashes "\" with forward slashes "/". Convenience method
+ * to convert path Strings to URI format.
+ */
+ public static String substBackslashes(String string) {
+ return RegexUtil.substBackslashes(string);
+ }
+
+ /**
+ * Looks up and returns the root cause of an exception. If none is found,
+ * returns supplied Throwable object unchanged. If root is found,
+ * recursively "unwraps" it, and returns the result to the user.
+ */
+ public static Throwable unwindException(Throwable th) {
+ if (th instanceof SAXException) {
+ SAXException sax = (SAXException) th;
+ if (sax.getException() != null) {
+ return unwindException(sax.getException());
+ }
+ } else if (th instanceof SQLException) {
+ SQLException sql = (SQLException) th;
+ if (sql.getNextException() != null) {
+ return unwindException(sql.getNextException());
+ }
+ } else if (th.getCause() != null) {
+ return unwindException(th.getCause());
+ }
+
+ return th;
+ }
+
+ /**
+ * Compares two objects similar to "Object.equals(Object)". Unlike
+ * Object.equals(..), this method doesn't throw an exception if any of the
+ * two objects is null.
+ */
+ public static boolean nullSafeEquals(Object o1, Object o2) {
+
+ if (o1 == null) {
+ return o2 == null;
+ }
+
+ // Arrays must be handled differently since equals() only does
+ // an "==" for an array and ignores equivalence. If an array, use
+ // the Jakarta Commons Language component EqualsBuilder to determine
+ // the types contained in the array and do individual comparisons.
+ if (o1.getClass().isArray()) {
+ EqualsBuilder builder = new EqualsBuilder();
+ builder.append(o1, o2);
+ return builder.isEquals();
+ } else { // It is NOT an array, so use regular equals()
+ return o1.equals(o2);
+ }
+ }
+
+ /**
+ * Compares two objects similar to "Comparable.compareTo(Object)". Unlike
+ * Comparable.compareTo(..), this method doesn't throw an exception if any
+ * of the two objects is null.
+ *
+ * @since 1.1
+ */
+ public static <T> int nullSafeCompare(boolean nullsFirst, Comparable<T> o1, T o2) {
+ if (o1 == null && o2 == null) {
+ return 0;
+ } else if (o1 == null) {
+ return nullsFirst ? -1 : 1;
+ } else if (o2 == null) {
+ return nullsFirst ? 1 : -1;
+ } else {
+ return o1.compareTo(o2);
+ }
+ }
+
+ /**
+ * Returns true, if the String is null or an empty string.
+ */
+ public static boolean isEmptyString(String string) {
+ return string == null || string.length() == 0;
+ }
+
+ /**
+ * Creates Serializable object copy using serialization/deserialization.
+ */
+ public static <T extends Serializable> T cloneViaSerialization(T object) throws Exception {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream() {
+
+ @Override
+ public byte[] toByteArray() {
+ return buf;
+ }
+ };
+
+ ObjectOutputStream out = new ObjectOutputStream(bytes);
+ out.writeObject(object);
+ out.close();
+
+ ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()));
+ T copy = (T) in.readObject();
+
+ // no need to close the stream - we created it and now will be throwing
+ // away...
+ // in.close();
+
+ return copy;
+ }
+
+ /**
+ * Creates an XMLReader with default feature set. Note that all Cayenne
+ * internal XML parsers should probably use XMLReader obtained via this
+ * method for consistency sake, and can customize feature sets as needed.
+ */
+ public static XMLReader createXmlReader() throws SAXException, ParserConfigurationException {
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+
+ // Create a JAXP SAXParser
+ SAXParser saxParser = spf.newSAXParser();
+
+ // Get the encapsulated SAX XMLReader
+ XMLReader reader = saxParser.getXMLReader();
+
+ // set default features
+ reader.setFeature("http://xml.org/sax/features/namespaces", true);
+
+ return reader;
+ }
+
+ /**
+ * Returns package name for the Java class as a path separated with forward
+ * slash ("/"). Method is used to lookup resources that are located in
+ * package subdirectories. For example, a String "a/b/c" will be returned
+ * for class name "a.b.c.ClassName".
+ */
+ public static String getPackagePath(String className) {
+ return RegexUtil.getPackagePath(className);
+ }
+
+ /**
+ * Returns an unqualified class name for the fully qualified name.
+ *
+ * @since 3.0
+ */
+ public static String stripPackageName(String className) {
+ if (className == null || className.length() == 0)
+ return className;
+
+ int lastDot = className.lastIndexOf('.');
+
+ if ((-1 == lastDot) || ((className.length() - 1) == lastDot))
+ return className;
+
+ return className.substring(lastDot + 1);
+ }
+
+ /**
+ * Creates a mutable map out of two arrays with keys and values.
+ *
+ * @since 1.2
+ */
+ public static <K, V> Map<K, V> toMap(K[] keys, V[] values) {
+ int keysSize = (keys != null) ? keys.length : 0;
+ int valuesSize = (values != null) ? values.length : 0;
+
+ if (keysSize == 0 && valuesSize == 0) {
+ // return mutable map
+ return new HashMap<K, V>();
+ }
+
+ if (keysSize != valuesSize) {
+ throw new IllegalArgumentException("The number of keys doesn't match the number of values.");
+ }
+
+ Map<K, V> map = new HashMap<K, V>();
+ for (int i = 0; i < keysSize; i++) {
+ map.put(keys[i], values[i]);
+ }
+
+ return map;
+ }
+
+ /**
+ * Extracts extension from the file name. Dot is not included in the
+ * returned string.
+ */
+ public static String extractFileExtension(String fileName) {
+ int dotInd = fileName.lastIndexOf('.');
+
+ // if dot is in the first position,
+ // we are dealing with a hidden file rather than an extension
+ return (dotInd > 0 && dotInd < fileName.length()) ? fileName.substring(dotInd + 1) : null;
+ }
+
+ /**
+ * Strips extension from the file name.
+ */
+ public static String stripFileExtension(String fileName) {
+ int dotInd = fileName.lastIndexOf('.');
+
+ // if dot is in the first position,
+ // we are dealing with a hidden file rather than an extension
+ return (dotInd > 0) ? fileName.substring(0, dotInd) : fileName;
+ }
+
+ /**
+ * Strips "\n", "\r\n", "\r" from the argument string, replacing them with a
+ * provided character.
+ *
+ * @since 3.1
+ */
+ public static String stripLineBreaks(String string, char replaceWith) {
+
+ if (string == null) {
+ return null;
+ }
+
+ int len = string.length();
+ char[] buffer = new char[len];
+ boolean matched = false;
+
+ int j = 0;
+ for (int i = 0; i < len; i++, j++) {
+ char c = string.charAt(i);
+
+ // skip \n, \r, \r\n
+ if (c == '\n' || c == '\r') {
+
+ matched = true;
+
+ // do lookahead
+ if (i + 1 < len && string.charAt(i + 1) == '\n') {
+ i++;
+ }
+
+ buffer[j] = replaceWith;
+ } else {
+ buffer[j] = c;
+ }
+ }
+
+ return matched ? new String(buffer, 0, j) : string;
+ }
+
+ /**
+ * Encodes a string so that it can be used as an attribute value in an XML
+ * document. Will do conversion of the greater/less signs, quotes and
+ * ampersands.
+ */
+ public static String encodeXmlAttribute(String string) {
+ if (string == null) {
+ return null;
+ }
+
+ int len = string.length();
+ if (len == 0) {
+ return string;
+ }
+
+ StringBuilder encoded = new StringBuilder();
+ for (int i = 0; i < len; i++) {
+ char c = string.charAt(i);
+ if (c == '<') {
+ encoded.append("<");
+ } else if (c == '\"') {
+ encoded.append(""");
+ } else if (c == '>') {
+ encoded.append(">");
+ } else if (c == '\'') {
+ encoded.append("'");
+ } else if (c == '&') {
+ encoded.append("&");
+ } else {
+ encoded.append(c);
+ }
+ }
+
+ return encoded.toString();
+ }
+
+ /**
+ * Trims long strings substituting middle part with "...".
+ *
+ * @param str
+ * String to trim.
+ * @param maxLength
+ * maximum allowable length. Must be at least 5, or an
+ * IllegalArgumentException is thrown.
+ * @return String
+ */
+ public static String prettyTrim(String str, int maxLength) {
+ if (maxLength < 5) {
+ throw new IllegalArgumentException("Algorithm for 'prettyTrim' works only with length >= 5. "
+ + "Supplied length is " + maxLength);
+ }
+
+ if (str == null || str.length() <= maxLength) {
+ return str;
+ }
+
+ // find a section to cut off
+ int len = maxLength - 3;
+ int startLen = len / 2;
+ int endLen = len - startLen;
+
+ return str.substring(0, startLen) + "..." + str.substring(str.length() - endLen);
+ }
+
+ /**
+ * Returns a sorted iterator from an unsorted one. Use this method as a last
+ * resort, since it is much less efficient then just sorting a collection
+ * that backs the original iterator.
+ */
+ public static <T> Iterator<T> sortedIterator(Iterator<T> it, Comparator<T> comparator) {
+ List<T> list = new ArrayList<T>();
+ while (it.hasNext()) {
+ list.add(it.next());
+ }
+
+ Collections.sort(list, comparator);
+ return list.iterator();
+ }
+
+ /**
+ * Builds a hashCode of Collection.
+ */
+ public static int hashCode(Collection<?> c) {
+ HashCodeBuilder builder = new HashCodeBuilder();
+ for (Object o : c) {
+ builder.append(o);
+ }
+ return builder.toHashCode();
+ }
+
+ /**
+ * @since 1.2
+ */
+ public static Pattern sqlPatternToPattern(String pattern, boolean ignoreCase) {
+ String preprocessed = RegexUtil.sqlPatternToRegex(pattern);
+
+ int flag = (ignoreCase) ? Pattern.CASE_INSENSITIVE : 0;
+ return Pattern.compile(preprocessed, flag);
+ }
+
+ /**
+ * Returns true if a Member is accessible via reflection under normal Java
+ * access controls.
+ *
+ * @since 1.2
+ */
+ public static boolean isAccessible(Member member) {
+ return Modifier.isPublic(member.getModifiers()) && Modifier.isPublic(member.getDeclaringClass().getModifiers());
+ }
+
+ /**
+ * Creates a Java class, handling regular class names as well as
+ * single-dimensional arrays and primitive types.
+ *
+ * @since 1.2
+ * @deprecated since 4.0 this method based on statically defined class
+ * loading algorithm is not going to work in environments like
+ * OSGi. {@link AdhocObjectFactory} should be used as it can
+ * provide the environment-specific class loading policy.
+ */
+ @Deprecated
+ public static Class<?> getJavaClass(String className) throws ClassNotFoundException {
+ return objectFactory.getJavaClass(className);
+ }
+
+ static void setReverse(final Persistent sourceObject, String propertyName, final Persistent targetObject) {
+
+ ArcProperty property = (ArcProperty) Cayenne.getClassDescriptor(sourceObject).getProperty(propertyName);
+ ArcProperty reverseArc = property.getComplimentaryReverseArc();
+ if (reverseArc != null) {
+ reverseArc.visit(new PropertyVisitor() {
+
+ public boolean visitToMany(ToManyProperty property) {
+ property.addTargetDirectly(targetObject, sourceObject);
+ return false;
+ }
+
+ public boolean visitToOne(ToOneProperty property) {
+ property.setTarget(targetObject, sourceObject, false);
+ return false;
+ }
+
+ public boolean visitAttribute(AttributeProperty property) {
+ return false;
+ }
+
+ });
+
+ sourceObject.getObjectContext().getGraphManager()
+ .arcCreated(targetObject.getObjectId(), sourceObject.getObjectId(), reverseArc.getName());
+
+ markAsDirty(targetObject);
+ }
+ }
+
+ static void unsetReverse(final Persistent sourceObject, String propertyName, final Persistent targetObject) {
+
+ ArcProperty property = (ArcProperty) Cayenne.getClassDescriptor(sourceObject).getProperty(propertyName);
+ ArcProperty reverseArc = property.getComplimentaryReverseArc();
+ if (reverseArc != null) {
+ reverseArc.visit(new PropertyVisitor() {
+
+ public boolean visitToMany(ToManyProperty property) {
+ property.removeTargetDirectly(targetObject, sourceObject);
+ return false;
+ }
+
+ public boolean visitToOne(ToOneProperty property) {
+ property.setTarget(targetObject, null, false);
+ return false;
+ }
+
+ public boolean visitAttribute(AttributeProperty property) {
+ return false;
+ }
+
+ });
+
+ sourceObject.getObjectContext().getGraphManager()
+ .arcDeleted(targetObject.getObjectId(), sourceObject.getObjectId(), reverseArc.getName());
+
+ markAsDirty(targetObject);
+ }
+ }
+
+ /**
+ * Changes object state to MODIFIED if needed, returning true if the change
+ * has occurred, false if not.
+ */
+ static boolean markAsDirty(Persistent object) {
+ if (object.getPersistenceState() == PersistenceState.COMMITTED) {
+ object.setPersistenceState(PersistenceState.MODIFIED);
+ return true;
+ }
+
+ return false;
+ }
}