http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/StringUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/StringUtils.java 
b/utils/src/main/java/com/cloud/utils/StringUtils.java
new file mode 100644
index 0000000..c598be8
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/StringUtils.java
@@ -0,0 +1,323 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.owasp.esapi.StringUtilities;
+
+public class StringUtils {
+    private static final char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', 
'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+    private static Charset preferredACSCharset;
+    private static final String UTF8 = "UTF-8";
+
+    static {
+        if (isUtf8Supported()) {
+            preferredACSCharset = Charset.forName(UTF8);
+        } else {
+            preferredACSCharset = Charset.defaultCharset();
+        }
+    }
+
+    public static Charset getPreferredCharset() {
+        return preferredACSCharset;
+    }
+
+    public static boolean isUtf8Supported() {
+        return Charset.isSupported(UTF8);
+    }
+
+    protected static Charset getDefaultCharset() {
+        return Charset.defaultCharset();
+    }
+
+    public static String join(final Iterable<? extends Object> iterable, final 
String delim) {
+        final StringBuilder sb = new StringBuilder();
+        if (iterable != null) {
+            final Iterator<? extends Object> iter = iterable.iterator();
+            if (iter.hasNext()) {
+                final Object next = iter.next();
+                sb.append(next.toString());
+            }
+            while (iter.hasNext()) {
+                final Object next = iter.next();
+                sb.append(delim + next.toString());
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String join(final String delimiter, final Object... 
components) {
+        return org.apache.commons.lang.StringUtils.join(components, delimiter);
+    }
+
+    public static boolean isNotBlank(final String str) {
+        if (str != null && str.trim().length() > 0) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public static String cleanupTags(String tags) {
+        if (tags != null) {
+            final String[] tokens = tags.split(",");
+            final StringBuilder t = new StringBuilder();
+            for (int i = 0; i < tokens.length; i++) {
+                t.append(tokens[i].trim()).append(",");
+            }
+            t.delete(t.length() - 1, t.length());
+            tags = t.toString();
+        }
+
+        return tags;
+    }
+
+    /**
+     * @param tags
+     * @return List of tags
+     */
+    public static List<String> csvTagsToList(final String tags) {
+        final List<String> tagsList = new ArrayList<String>();
+
+        if (tags != null) {
+            final String[] tokens = tags.split(",");
+            for (int i = 0; i < tokens.length; i++) {
+                tagsList.add(tokens[i].trim());
+            }
+        }
+
+        return tagsList;
+    }
+
+    /**
+     * Converts a List of tags to a comma separated list
+     * @param tags
+     * @return String containing a comma separated list of tags
+     */
+
+    public static String listToCsvTags(final List<String> tagsList) {
+        final StringBuilder tags = new StringBuilder();
+        if (tagsList.size() > 0) {
+            for (int i = 0; i < tagsList.size(); i++) {
+                tags.append(tagsList.get(i));
+                if (i != tagsList.size() - 1) {
+                    tags.append(',');
+                }
+            }
+        }
+
+        return tags.toString();
+    }
+
+    public static String getExceptionStackInfo(final Throwable e) {
+        final StringBuffer sb = new StringBuffer();
+
+        sb.append(e.toString()).append("\n");
+        final StackTraceElement[] elemnents = e.getStackTrace();
+        for (final StackTraceElement element : elemnents) {
+            sb.append(element.getClassName()).append(".");
+            sb.append(element.getMethodName()).append("(");
+            sb.append(element.getFileName()).append(":");
+            sb.append(element.getLineNumber()).append(")");
+            sb.append("\n");
+        }
+
+        return sb.toString();
+    }
+
+    public static String unicodeEscape(final String s) {
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < s.length(); i++) {
+            final char c = s.charAt(i);
+            if (c >> 7 > 0) {
+                sb.append("\\u");
+                sb.append(hexChar[c >> 12 & 0xF]); // append the hex character 
for the left-most 4-bits
+                sb.append(hexChar[c >> 8 & 0xF]);  // hex for the second group 
of 4-bits from the left
+                sb.append(hexChar[c >> 4 & 0xF]);  // hex for the third group
+                sb.append(hexChar[c & 0xF]);         // hex for the last 
group, e.g., the right most 4-bits
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String getMaskedPasswordForDisplay(final String password) {
+        if (password == null || password.isEmpty()) {
+            return "*";
+        }
+
+        final StringBuffer sb = new StringBuffer();
+        sb.append(password.charAt(0));
+        for (int i = 1; i < password.length(); i++) {
+            sb.append("*");
+        }
+
+        return sb.toString();
+    }
+
+    // removes a password request param and it's value, also considering 
password is in query parameter value which has been url encoded
+    private static final Pattern REGEX_PASSWORD_QUERYSTRING = 
Pattern.compile("(&|%26)?[^(&|%26)]*((p|P)assword|accesskey|secretkey)(=|%3D).*?(?=(%26|[&'\"]|$))");
+
+    // removes a password/accesskey/ property from a response json object
+    private static final Pattern REGEX_PASSWORD_JSON = 
Pattern.compile("\"((p|P)assword|accesskey|secretkey)\":\\s?\".*?\",?");
+
+    private static final Pattern REGEX_PASSWORD_DETAILS = 
Pattern.compile("(&|%26)?details(\\[|%5B)\\d*(\\]|%5D)\\.key(=|%3D)((p|P)assword|accesskey|secretkey)(?=(%26|[&'\"]))");
+
+    private static final Pattern REGEX_PASSWORD_DETAILS_INDEX = 
Pattern.compile("details(\\[|%5B)\\d*(\\]|%5D)");
+
+    private static final Pattern REGEX_REDUNDANT_AND = 
Pattern.compile("(&|%26)(&|%26)+");
+
+    // Responsible for stripping sensitive content from request and response 
strings
+    public static String cleanString(final String stringToClean) {
+        String cleanResult = "";
+        if (stringToClean != null) {
+            cleanResult = 
REGEX_PASSWORD_QUERYSTRING.matcher(stringToClean).replaceAll("");
+            cleanResult = 
REGEX_PASSWORD_JSON.matcher(cleanResult).replaceAll("");
+            final Matcher detailsMatcher = 
REGEX_PASSWORD_DETAILS.matcher(cleanResult);
+            while (detailsMatcher.find()) {
+                final Matcher detailsIndexMatcher = 
REGEX_PASSWORD_DETAILS_INDEX.matcher(detailsMatcher.group());
+                if (detailsIndexMatcher.find()) {
+                    cleanResult = cleanDetails(cleanResult, 
detailsIndexMatcher.group());
+                }
+            }
+        }
+        return cleanResult;
+    }
+
+    public static String cleanDetails(final String stringToClean, final String 
detailsIndexSting) {
+        String cleanResult = stringToClean;
+        for (final String log : stringToClean.split("&|%26")) {
+            if (log.contains(detailsIndexSting)) {
+                cleanResult = cleanResult.replace(log, "");
+            }
+        }
+        cleanResult = REGEX_REDUNDANT_AND.matcher(cleanResult).replaceAll("&");
+        return cleanResult;
+    }
+
+    public static boolean areTagsEqual(final String tags1, final String tags2) 
{
+        if (tags1 == null && tags2 == null) {
+            return true;
+        }
+
+        if (tags1 != null && tags2 == null) {
+            return false;
+        }
+
+        if (tags1 == null && tags2 != null) {
+            return false;
+        }
+
+        final String delimiter = ",";
+
+        final List<String> lstTags1 = new ArrayList<String>();
+        final String[] aTags1 = tags1.split(delimiter);
+
+        for (final String tag1 : aTags1) {
+            lstTags1.add(tag1.toLowerCase());
+        }
+
+        final List<String> lstTags2 = new ArrayList<String>();
+        final String[] aTags2 = tags2.split(delimiter);
+
+        for (final String tag2 : aTags2) {
+            lstTags2.add(tag2.toLowerCase());
+        }
+
+        return lstTags1.containsAll(lstTags2) && 
lstTags2.containsAll(lstTags1);
+    }
+
+    public static String stripControlCharacters(final String s) {
+        return StringUtilities.stripControls(s);
+    }
+
+    public static int formatForOutput(final String text, final int start, 
final int columns, final char separator) {
+        if (start >= text.length()) {
+            return -1;
+        }
+
+        int end = start + columns;
+        if (end > text.length()) {
+            end = text.length();
+        }
+        final String searchable = text.substring(start, end);
+        final int found = searchable.lastIndexOf(separator);
+        return found > 0 ? found : end - start;
+    }
+
+    public static Map<String, String> stringToMap(final String s) {
+        final Map<String, String> map = new HashMap<String, String>();
+        final String[] elements = s.split(";");
+        for (final String parts : elements) {
+            final String[] keyValue = parts.split(":");
+            map.put(keyValue[0], keyValue[1]);
+        }
+        return map;
+    }
+
+    public static String mapToString(final Map<String, String> map) {
+        String s = "";
+        for (final Map.Entry<String, String> entry : map.entrySet()) {
+            s += entry.getKey() + ":" + entry.getValue() + ";";
+        }
+        if (s.length() > 0) {
+            s = s.substring(0, s.length() - 1);
+        }
+        return s;
+    }
+
+    public static <T> List<T> applyPagination(final List<T> originalList, 
final Long startIndex, final Long pageSizeVal) {
+        // Most likely pageSize will never exceed int value, and we need 
integer to partition the listToReturn
+        final boolean applyPagination = startIndex != null && pageSizeVal != 
null
+                && startIndex <= Integer.MAX_VALUE && startIndex >= 
Integer.MIN_VALUE && pageSizeVal <= Integer.MAX_VALUE
+                && pageSizeVal >= Integer.MIN_VALUE;
+                List<T> listWPagination = null;
+                if (applyPagination) {
+                    listWPagination = new ArrayList<>();
+                    final int index = startIndex.intValue() == 0 ? 0 : 
startIndex.intValue() / pageSizeVal.intValue();
+                    final List<List<T>> partitions = 
StringUtils.partitionList(originalList, pageSizeVal.intValue());
+                    if (index < partitions.size()) {
+                        listWPagination = partitions.get(index);
+                    }
+                }
+                return listWPagination;
+    }
+
+    private static <T> List<List<T>> partitionList(final List<T> originalList, 
final int chunkSize) {
+        final List<List<T>> listOfChunks = new ArrayList<List<T>>();
+        for (int i = 0; i < originalList.size() / chunkSize; i++) {
+            listOfChunks.add(originalList.subList(i * chunkSize, i * chunkSize 
+ chunkSize));
+        }
+        if (originalList.size() % chunkSize != 0) {
+            listOfChunks.add(originalList.subList(originalList.size() - 
originalList.size() % chunkSize, originalList.size()));
+        }
+        return listOfChunks;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/SwiftUtil.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/SwiftUtil.java 
b/utils/src/main/java/com/cloud/utils/SwiftUtil.java
new file mode 100644
index 0000000..1136818
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/SwiftUtil.java
@@ -0,0 +1,239 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.OutputInterpreter;
+import com.cloud.utils.script.Script;
+
+public class SwiftUtil {
+    private static Logger logger = Logger.getLogger(SwiftUtil.class);
+    private static final long SWIFT_MAX_SIZE = 5L * 1024L * 1024L * 1024L;
+
+    public interface SwiftClientCfg {
+        String getAccount();
+
+        String getUserName();
+
+        String getKey();
+
+        String getEndPoint();
+    }
+
+    private static String getSwiftCLIPath() {
+        String swiftCLI = Script.findScript("scripts/storage/secondary", 
"swift");
+        if (swiftCLI == null) {
+            logger.debug("Can't find swift cli at 
scripts/storage/secondary/swift");
+            throw new CloudRuntimeException("Can't find swift cli at 
scripts/storage/secondary/swift");
+        }
+        return swiftCLI;
+    }
+
+    public static boolean postMeta(SwiftClientCfg cfg, String container, 
String object, Map<String, String> metas) {
+        String swiftCli = getSwiftCLIPath();
+        StringBuilder cms = new StringBuilder();
+        for (Map.Entry<String, String> entry : metas.entrySet()) {
+            cms.append(" -m ");
+            cms.append(entry.getKey());
+            cms.append(":");
+            cms.append(entry.getValue());
+            cms.append(" ");
+        }
+        Script command = new Script("/bin/bash", logger);
+        command.add("-c");
+        command.add("/usr/bin/python " + swiftCli + " -A " + cfg.getEndPoint() 
+ " -U " + cfg.getAccount() + ":" + cfg.getUserName() + " -K " + cfg.getKey() + 
" post " +
+            container + " " + object + " " + cms.toString());
+        OutputInterpreter.OneLineParser parser = new 
OutputInterpreter.OneLineParser();
+        String result = command.execute(parser);
+        if (result != null) {
+            throw new CloudRuntimeException("Failed to post meta" + result);
+        }
+        return true;
+    }
+
+    public static String putObject(SwiftClientCfg cfg, File srcFile, String 
container, String fileName) {
+        String swiftCli = getSwiftCLIPath();
+        if (fileName == null) {
+            fileName = srcFile.getName();
+        }
+        String srcDirectory = srcFile.getParent();
+        Script command = new Script("/bin/bash", logger);
+        long size = srcFile.length();
+        command.add("-c");
+        if (size <= SWIFT_MAX_SIZE) {
+            command.add("cd " + srcDirectory + ";/usr/bin/python " + swiftCli 
+ " -A " + cfg.getEndPoint() + " -U " + cfg.getAccount() + ":" + 
cfg.getUserName() +
+                " -K " + cfg.getKey() + " upload " + container + " " + 
fileName);
+        } else {
+            command.add("cd " + srcDirectory + ";/usr/bin/python " + swiftCli 
+ " -A " + cfg.getEndPoint() + " -U " + cfg.getAccount() + ":" + 
cfg.getUserName() +
+                " -K " + cfg.getKey() + " upload -S " + SWIFT_MAX_SIZE + " " + 
container + " " + fileName);
+        }
+        OutputInterpreter.AllLinesParser parser = new 
OutputInterpreter.AllLinesParser();
+        String result = command.execute(parser);
+        if (result != null) {
+            throw new CloudRuntimeException("Failed to upload file: " + 
result);
+        }
+
+        if (parser.getLines() != null) {
+            String[] lines = parser.getLines().split("\\n");
+            for (String line : lines) {
+                if (line.contains("Errno") || line.contains("failed") || 
line.contains("not found")) {
+                    throw new CloudRuntimeException("Failed to upload file: " 
+ Arrays.toString(lines));
+                }
+            }
+        }
+
+        return container + File.separator + srcFile.getName();
+    }
+
+    private static StringBuilder buildSwiftCmd(SwiftClientCfg swift) {
+        String swiftCli = getSwiftCLIPath();
+        StringBuilder sb = new StringBuilder();
+        sb.append(" /usr/bin/python ");
+        sb.append(swiftCli);
+        sb.append(" -A ");
+        sb.append(swift.getEndPoint());
+        sb.append(" -U ");
+        sb.append(swift.getAccount());
+        sb.append(":");
+        sb.append(swift.getUserName());
+        sb.append(" -K ");
+        sb.append(swift.getKey());
+        sb.append(" ");
+        return sb;
+    }
+
+    public static String[] list(SwiftClientCfg swift, String container, String 
rFilename) {
+        getSwiftCLIPath();
+        Script command = new Script("/bin/bash", logger);
+        command.add("-c");
+
+        StringBuilder swiftCmdBuilder = buildSwiftCmd(swift);
+        swiftCmdBuilder.append(" list ");
+        swiftCmdBuilder.append(container);
+
+        if (rFilename != null) {
+            swiftCmdBuilder.append(" -p ");
+            swiftCmdBuilder.append(rFilename);
+        }
+
+        command.add(swiftCmdBuilder.toString());
+        OutputInterpreter.AllLinesParser parser = new 
OutputInterpreter.AllLinesParser();
+        String result = command.execute(parser);
+        if (result == null && parser.getLines() != null && 
!parser.getLines().equalsIgnoreCase("")) {
+            String[] lines = parser.getLines().split("\\n");
+            return lines;
+        } else {
+            if (result != null) {
+                String errMsg = "swiftList failed , err=" + result;
+                logger.debug("Failed to list " + errMsg);
+            } else {
+                String errMsg = "swiftList failed, no lines returns";
+                logger.debug("Failed to list " + errMsg);
+            }
+        }
+        return new String[0];
+    }
+
+    public static File getObject(SwiftClientCfg cfg, File destDirectory, 
String swiftPath) {
+        int firstIndexOfSeparator = swiftPath.indexOf(File.separator);
+        String container = swiftPath.substring(0, firstIndexOfSeparator);
+        String srcPath = swiftPath.substring(firstIndexOfSeparator + 1);
+        String destFilePath = null;
+        if (destDirectory.isDirectory()) {
+            destFilePath = destDirectory.getAbsolutePath() + File.separator + 
srcPath;
+        } else {
+            destFilePath = destDirectory.getAbsolutePath();
+        }
+        String swiftCli = getSwiftCLIPath();
+        Script command = new Script("/bin/bash", logger);
+        command.add("-c");
+        command.add("/usr/bin/python " + swiftCli + " -A " + cfg.getEndPoint() 
+ " -U " + cfg.getAccount() + ":" + cfg.getUserName() + " -K " + cfg.getKey() +
+            " download " + container + " " + srcPath + " -o " + destFilePath);
+        OutputInterpreter.AllLinesParser parser = new 
OutputInterpreter.AllLinesParser();
+        String result = command.execute(parser);
+        if (result != null) {
+            String errMsg = "swiftDownload failed  err=" + result;
+            logger.debug(errMsg);
+            throw new CloudRuntimeException("failed to get object: " + 
swiftPath);
+        }
+        if (parser.getLines() != null) {
+            String[] lines = parser.getLines().split("\\n");
+            for (String line : lines) {
+                if (line.contains("Errno") || line.contains("failed")) {
+                    String errMsg = "swiftDownload failed , err=" + 
Arrays.toString(lines);
+                    logger.debug(errMsg);
+                    throw new CloudRuntimeException("Failed to get object: " + 
swiftPath);
+                }
+            }
+        }
+        return new File(destFilePath);
+    }
+
+    public static String getContainerName(String type, Long id) {
+        if (type.startsWith("T")) {
+            return "T-" + id;
+        } else if (type.startsWith("S")) {
+            return "S-" + id;
+        } else if (type.startsWith("V")) {
+            return "V-" + id;
+        }
+        return null;
+    }
+
+    public static String[] splitSwiftPath(String path) {
+        int index = path.indexOf(File.separator);
+        if (index == -1) {
+            return null;
+        }
+        String[] paths = new String[2];
+        paths[0] = path.substring(0, index);
+        paths[1] = path.substring(index + 1);
+        return paths;
+    }
+
+    public static boolean deleteObject(SwiftClientCfg cfg, String path) {
+        Script command = new Script("/bin/bash", logger);
+        command.add("-c");
+
+        String[] paths = splitSwiftPath(path);
+        if (paths == null) {
+            return false;
+        }
+        String container = paths[0];
+        String objectName = paths[1];
+
+        StringBuilder swiftCmdBuilder = buildSwiftCmd(cfg);
+        swiftCmdBuilder.append(" delete ");
+        swiftCmdBuilder.append(container);
+        swiftCmdBuilder.append(" ");
+        swiftCmdBuilder.append(objectName);
+
+        command.add(swiftCmdBuilder.toString());
+        OutputInterpreter.AllLinesParser parser = new 
OutputInterpreter.AllLinesParser();
+        command.execute(parser);
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/Ternary.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/Ternary.java 
b/utils/src/main/java/com/cloud/utils/Ternary.java
new file mode 100644
index 0000000..fdc2fc9
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/Ternary.java
@@ -0,0 +1,85 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils;
+
+public class Ternary<T, U, V> {
+    private T t;
+    private U u;
+    private V v;
+
+    public Ternary(T t, U u, V v) {
+        this.t = t;
+        this.u = u;
+        this.v = v;
+    }
+
+    public T first() {
+        return t;
+    }
+
+    public void first(T t) {
+        this.t = t;
+    }
+
+    public U second() {
+        return u;
+    }
+
+    public void second(U u) {
+        this.u = u;
+    }
+
+    public V third() {
+        return v;
+    }
+
+    public void third(V v) {
+        this.v = v;
+    }
+
+    @Override
+    // Note: This means any two pairs with null for both values will match each
+    // other but what can I do?  This is due to stupid type erasure.
+        public
+        int hashCode() {
+        return (t != null ? t.hashCode() : 0) | (u != null ? u.hashCode() : 0) 
| (v != null ? v.hashCode() : 0);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Ternary)) {
+            return false;
+        }
+        Ternary<?, ?, ?> that = (Ternary<?, ?, ?>)obj;
+        return (t != null ? t.equals(that.t) : that.t == null) && (u != null ? 
u.equals(that.u) : that.u == null) && (v != null ? v.equals(that.v) : that.v == 
null);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder("T[");
+        b.append(t != null ? t.toString() : "null");
+        b.append(":");
+        b.append(u != null ? u.toString() : "null");
+        b.append(":");
+        b.append(v != null ? v.toString() : "null");
+        b.append("]");
+        return b.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/UriUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/UriUtils.java 
b/utils/src/main/java/com/cloud/utils/UriUtils.java
new file mode 100644
index 0000000..631c629
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/UriUtils.java
@@ -0,0 +1,394 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.StringTokenizer;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.util.URIUtil;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.log4j.Logger;
+
+import com.cloud.utils.crypt.DBEncryptionUtil;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+public class UriUtils {
+
+    public static final Logger s_logger = 
Logger.getLogger(UriUtils.class.getName());
+
+    public static String formNfsUri(String host, String path) {
+        try {
+            URI uri = new URI("nfs", host, path, null);
+            return uri.toString();
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException("Unable to form nfs URI: " + host 
+ " - " + path);
+        }
+    }
+
+    public static String formIscsiUri(String host, String iqn, Integer lun) {
+        try {
+            String path = iqn;
+            if (lun != null) {
+                path += "/" + lun.toString();
+            }
+            URI uri = new URI("iscsi", host, path, null);
+            return uri.toString();
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException("Unable to form iscsi URI: " + 
host + " - " + iqn + " - " + lun);
+        }
+    }
+
+    public static String formFileUri(String path) {
+        File file = new File(path);
+
+        return file.toURI().toString();
+    }
+
+    // a simple URI component helper (Note: it does not deal with URI 
paramemeter area)
+    public static String encodeURIComponent(String url) {
+        int schemeTail = url.indexOf("://");
+
+        int pathStart = 0;
+        if (schemeTail > 0)
+            pathStart = url.indexOf('/', schemeTail + 3);
+        else
+            pathStart = url.indexOf('/');
+
+        if (pathStart > 0) {
+            String[] tokens = url.substring(pathStart + 1).split("/");
+            StringBuilder sb = new StringBuilder(url.substring(0, pathStart));
+            for (String token : tokens) {
+                sb.append("/").append(URLEncoder.encode(token));
+            }
+
+            return sb.toString();
+        }
+
+        // no need to do URL component encoding
+        return url;
+    }
+
+    public static String getCifsUriParametersProblems(URI uri) {
+        if (!UriUtils.hostAndPathPresent(uri)) {
+            String errMsg = "cifs URI missing host and/or path. Make sure it's 
of the format cifs://hostname/path";
+            s_logger.warn(errMsg);
+            return errMsg;
+        }
+        return null;
+    }
+
+    public static boolean hostAndPathPresent(URI uri) {
+        return !(uri.getHost() == null || uri.getHost().trim().isEmpty() || 
uri.getPath() == null || uri.getPath().trim().isEmpty());
+    }
+
+    public static boolean cifsCredentialsPresent(URI uri) {
+        List<NameValuePair> args = URLEncodedUtils.parse(uri, "UTF-8");
+        boolean foundUser = false;
+        boolean foundPswd = false;
+        for (NameValuePair nvp : args) {
+            String name = nvp.getName();
+            if (name.equals("user")) {
+                foundUser = true;
+                s_logger.debug("foundUser is" + foundUser);
+            } else if (name.equals("password")) {
+                foundPswd = true;
+                s_logger.debug("foundPswd is" + foundPswd);
+            }
+        }
+        return (foundUser && foundPswd);
+    }
+
+    public static String getUpdateUri(String url, boolean encrypt) {
+        String updatedPath = null;
+        try {
+            String query = URIUtil.getQuery(url);
+            URIBuilder builder = new URIBuilder(url);
+            builder.removeQuery();
+
+            StringBuilder updatedQuery = new StringBuilder();
+            List<NameValuePair> queryParams = getUserDetails(query);
+            ListIterator<NameValuePair> iterator = queryParams.listIterator();
+            while (iterator.hasNext()) {
+                NameValuePair param = iterator.next();
+                String value = null;
+                if ("password".equalsIgnoreCase(param.getName()) &&
+                        param.getValue() != null) {
+                    value = encrypt ? 
DBEncryptionUtil.encrypt(param.getValue()) : 
DBEncryptionUtil.decrypt(param.getValue());
+                } else {
+                    value = param.getValue();
+                }
+
+                if (updatedQuery.length() == 0) {
+                    updatedQuery.append(param.getName()).append('=')
+                            .append(value);
+                } else {
+                    updatedQuery.append('&').append(param.getName())
+                            .append('=').append(value);
+                }
+            }
+
+            String schemeAndHost = "";
+            URI newUri = builder.build();
+            if (newUri.getScheme() != null) {
+                schemeAndHost = newUri.getScheme() + "://" + newUri.getHost();
+            }
+
+            updatedPath = schemeAndHost + newUri.getPath() + "?" + 
updatedQuery;
+        } catch (URISyntaxException e) {
+            throw new CloudRuntimeException("Couldn't generate an updated uri. 
" + e.getMessage());
+        }
+
+        return updatedPath;
+    }
+
+    private static List<NameValuePair> getUserDetails(String query) {
+        List<NameValuePair> details = new ArrayList<NameValuePair>();
+        if (query != null && !query.isEmpty()) {
+            StringTokenizer allParams = new StringTokenizer(query, "&");
+            while (allParams.hasMoreTokens()) {
+                String param = allParams.nextToken();
+                details.add(new BasicNameValuePair(param.substring(0, 
param.indexOf("=")),
+                        param.substring(param.indexOf("=") + 1)));
+            }
+        }
+
+        return details;
+    }
+
+    // Get the size of a file from URL response header.
+    public static Long getRemoteSize(String url) {
+        Long remoteSize = (long)0;
+        HttpURLConnection httpConn = null;
+        HttpsURLConnection httpsConn = null;
+        try {
+            URI uri = new URI(url);
+            if (uri.getScheme().equalsIgnoreCase("http")) {
+                httpConn = (HttpURLConnection)uri.toURL().openConnection();
+                if (httpConn != null) {
+                    httpConn.setConnectTimeout(2000);
+                    httpConn.setReadTimeout(5000);
+                    String contentLength = 
httpConn.getHeaderField("content-length");
+                    if (contentLength != null) {
+                        remoteSize = Long.parseLong(contentLength);
+                    }
+                    httpConn.disconnect();
+                }
+            } else if (uri.getScheme().equalsIgnoreCase("https")) {
+                httpsConn = (HttpsURLConnection)uri.toURL().openConnection();
+                if (httpsConn != null) {
+                    String contentLength = 
httpsConn.getHeaderField("content-length");
+                    if (contentLength != null) {
+                        remoteSize = Long.parseLong(contentLength);
+                    }
+                    httpsConn.disconnect();
+                }
+            }
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException("Invalid URL " + url);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Unable to establish connection 
with URL " + url);
+        }
+        return remoteSize;
+    }
+
+    public static Pair<String, Integer> validateUrl(String url) throws 
IllegalArgumentException {
+        return validateUrl(null, url);
+    }
+
+    public static Pair<String, Integer> validateUrl(String format, String url) 
throws IllegalArgumentException {
+        try {
+            URI uri = new URI(url);
+            if ((uri.getScheme() == null) ||
+                    (!uri.getScheme().equalsIgnoreCase("http") && 
!uri.getScheme().equalsIgnoreCase("https") && 
!uri.getScheme().equalsIgnoreCase("file"))) {
+                throw new IllegalArgumentException("Unsupported scheme for 
url: " + url);
+            }
+            int port = uri.getPort();
+            if (!(port == 80 || port == 8080 || port == 443 || port == -1)) {
+                throw new IllegalArgumentException("Only ports 80, 8080 and 
443 are allowed");
+            }
+
+            if (port == -1 && uri.getScheme().equalsIgnoreCase("https")) {
+                port = 443;
+            } else if (port == -1 && uri.getScheme().equalsIgnoreCase("http")) 
{
+                port = 80;
+            }
+
+            String host = uri.getHost();
+            try {
+                InetAddress hostAddr = InetAddress.getByName(host);
+                if (hostAddr.isAnyLocalAddress() || 
hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || 
hostAddr.isMulticastAddress()) {
+                    throw new IllegalArgumentException("Illegal host specified 
in url");
+                }
+                if (hostAddr instanceof Inet6Address) {
+                    throw new IllegalArgumentException("IPV6 addresses not 
supported (" + hostAddr.getHostAddress() + ")");
+                }
+            } catch (UnknownHostException uhe) {
+                throw new IllegalArgumentException("Unable to resolve " + 
host);
+            }
+
+            // verify format
+            if (format != null) {
+                String uripath = uri.getPath();
+                checkFormat(format, uripath);
+            }
+            return new Pair<String, Integer>(host, port);
+        } catch (URISyntaxException use) {
+            throw new IllegalArgumentException("Invalid URL: " + url);
+        }
+    }
+
+    // use http HEAD method to validate url
+    public static void checkUrlExistence(String url) {
+        if (url.toLowerCase().startsWith("http") || 
url.toLowerCase().startsWith("https")) {
+            HttpClient httpClient = new HttpClient(new 
MultiThreadedHttpConnectionManager());
+            HeadMethod httphead = new HeadMethod(url);
+            try {
+                if (httpClient.executeMethod(httphead) != HttpStatus.SC_OK) {
+                    throw new IllegalArgumentException("Invalid URL: " + url);
+                }
+            } catch (HttpException hte) {
+                throw new IllegalArgumentException("Cannot reach URL: " + url);
+            } catch (IOException ioe) {
+                throw new IllegalArgumentException("Cannot reach URL: " + url);
+            }
+        }
+    }
+
+    // verify if a URI path is compliance with the file format given
+    private static void checkFormat(String format, String uripath) {
+        if ((!uripath.toLowerCase().endsWith("vhd")) && 
(!uripath.toLowerCase().endsWith("vhd.zip")) && 
(!uripath.toLowerCase().endsWith("vhd.bz2")) &&
+                (!uripath.toLowerCase().endsWith("vhdx")) && 
(!uripath.toLowerCase().endsWith("vhdx.gz")) &&
+                (!uripath.toLowerCase().endsWith("vhdx.bz2")) && 
(!uripath.toLowerCase().endsWith("vhdx.zip")) &&
+                (!uripath.toLowerCase().endsWith("vhd.gz")) && 
(!uripath.toLowerCase().endsWith("qcow2")) && 
(!uripath.toLowerCase().endsWith("qcow2.zip")) &&
+                (!uripath.toLowerCase().endsWith("qcow2.bz2")) && 
(!uripath.toLowerCase().endsWith("qcow2.gz")) && 
(!uripath.toLowerCase().endsWith("ova")) &&
+                (!uripath.toLowerCase().endsWith("ova.zip")) && 
(!uripath.toLowerCase().endsWith("ova.bz2")) && 
(!uripath.toLowerCase().endsWith("ova.gz")) &&
+                (!uripath.toLowerCase().endsWith("tar")) && 
(!uripath.toLowerCase().endsWith("tar.zip")) && 
(!uripath.toLowerCase().endsWith("tar.bz2")) &&
+                (!uripath.toLowerCase().endsWith("tar.gz")) && 
(!uripath.toLowerCase().endsWith("vmdk")) && 
(!uripath.toLowerCase().endsWith("vmdk.gz")) &&
+                (!uripath.toLowerCase().endsWith("vmdk.zip")) && 
(!uripath.toLowerCase().endsWith("vmdk.bz2")) && 
(!uripath.toLowerCase().endsWith("img")) &&
+                (!uripath.toLowerCase().endsWith("img.gz")) && 
(!uripath.toLowerCase().endsWith("img.zip")) && 
(!uripath.toLowerCase().endsWith("img.bz2")) &&
+                (!uripath.toLowerCase().endsWith("raw")) && 
(!uripath.toLowerCase().endsWith("raw.gz")) && 
(!uripath.toLowerCase().endsWith("raw.bz2")) &&
+                (!uripath.toLowerCase().endsWith("raw.zip")) && 
(!uripath.toLowerCase().endsWith("iso")) && 
(!uripath.toLowerCase().endsWith("iso.zip"))
+                && (!uripath.toLowerCase().endsWith("iso.bz2")) && 
(!uripath.toLowerCase().endsWith("iso.gz"))) {
+            throw new IllegalArgumentException("Please specify a valid " + 
format.toLowerCase());
+        }
+
+        if ((format.equalsIgnoreCase("vhd")
+                && (!uripath.toLowerCase().endsWith("vhd")
+                && !uripath.toLowerCase().endsWith("vhd.zip")
+                && !uripath.toLowerCase().endsWith("vhd.bz2")
+                && !uripath.toLowerCase().endsWith("vhd.gz")))
+                || (format.equalsIgnoreCase("vhdx")
+                && (!uripath.toLowerCase().endsWith("vhdx")
+                        && !uripath.toLowerCase().endsWith("vhdx.zip")
+                        && !uripath.toLowerCase().endsWith("vhdx.bz2")
+                        && !uripath.toLowerCase().endsWith("vhdx.gz")))
+                || (format.equalsIgnoreCase("qcow2")
+                && (!uripath.toLowerCase().endsWith("qcow2")
+                        && !uripath.toLowerCase().endsWith("qcow2.zip")
+                        && !uripath.toLowerCase().endsWith("qcow2.bz2")
+                        && !uripath.toLowerCase().endsWith("qcow2.gz")))
+                || (format.equalsIgnoreCase("ova")
+                && (!uripath.toLowerCase().endsWith("ova")
+                        && !uripath.toLowerCase().endsWith("ova.zip")
+                        && !uripath.toLowerCase().endsWith("ova.bz2")
+                        && !uripath.toLowerCase().endsWith("ova.gz")))
+                || (format.equalsIgnoreCase("tar")
+                && (!uripath.toLowerCase().endsWith("tar")
+                        && !uripath.toLowerCase().endsWith("tar.zip")
+                        && !uripath.toLowerCase().endsWith("tar.bz2")
+                        && !uripath.toLowerCase().endsWith("tar.gz")))
+                || (format.equalsIgnoreCase("raw")
+                && (!uripath.toLowerCase().endsWith("img")
+                        && !uripath.toLowerCase().endsWith("img.zip")
+                        && !uripath.toLowerCase().endsWith("img.bz2")
+                        && !uripath.toLowerCase().endsWith("img.gz")
+                        && !uripath.toLowerCase().endsWith("raw")
+                        && !uripath.toLowerCase().endsWith("raw.bz2")
+                        && !uripath.toLowerCase().endsWith("raw.zip")
+                        && !uripath.toLowerCase().endsWith("raw.gz")))
+                || (format.equalsIgnoreCase("vmdk")
+                && (!uripath.toLowerCase().endsWith("vmdk")
+                        && !uripath.toLowerCase().endsWith("vmdk.zip")
+                        && !uripath.toLowerCase().endsWith("vmdk.bz2")
+                        && !uripath.toLowerCase().endsWith("vmdk.gz")))
+                || (format.equalsIgnoreCase("iso")
+                && (!uripath.toLowerCase().endsWith("iso")
+                        && !uripath.toLowerCase().endsWith("iso.zip")
+                        && !uripath.toLowerCase().endsWith("iso.bz2")
+                        && !uripath.toLowerCase().endsWith("iso.gz")))) {
+            throw new IllegalArgumentException("Please specify a valid URL. 
URL:" + uripath + " is an invalid for the format " + format.toLowerCase());
+        }
+
+    }
+
+    public static InputStream getInputStreamFromUrl(String url, String user, 
String password) {
+
+        try {
+            Pair<String, Integer> hostAndPort = validateUrl(url);
+            HttpClient httpclient = new HttpClient(new 
MultiThreadedHttpConnectionManager());
+            if ((user != null) && (password != null)) {
+                httpclient.getParams().setAuthenticationPreemptive(true);
+                Credentials defaultcreds = new 
UsernamePasswordCredentials(user, password);
+                httpclient.getState().setCredentials(new 
AuthScope(hostAndPort.first(), hostAndPort.second(), AuthScope.ANY_REALM), 
defaultcreds);
+                s_logger.info("Added username=" + user + ", password=" + 
password + "for host " + hostAndPort.first() + ":" + hostAndPort.second());
+            }
+            // Execute the method.
+            GetMethod method = new GetMethod(url);
+            int statusCode = httpclient.executeMethod(method);
+
+            if (statusCode != HttpStatus.SC_OK) {
+                s_logger.error("Failed to read from URL: " + url);
+                return null;
+            }
+
+            return method.getResponseBodyAsStream();
+        } catch (Exception ex) {
+            s_logger.error("Failed to read from URL: " + url);
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/UsernamePasswordValidator.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/UsernamePasswordValidator.java 
b/utils/src/main/java/com/cloud/utils/UsernamePasswordValidator.java
new file mode 100644
index 0000000..f11186c
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/UsernamePasswordValidator.java
@@ -0,0 +1,49 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class UsernamePasswordValidator {
+    private Pattern usernamePattern;
+    private Pattern passwordPattern;
+    private Matcher matcher;
+
+    private static final String USERNAME_PATTERN = 
"^[a-zA-Z0-9][a-zA-Z0-9@._-]{2,63}$";
+    private static final String PASSWORD_PATTERN = 
"^[a-zA-Z0-9][a-zA-Z0-9@#+=._-]{2,31}$";
+
+    public UsernamePasswordValidator() {
+        usernamePattern = Pattern.compile(USERNAME_PATTERN);
+        passwordPattern = Pattern.compile(PASSWORD_PATTERN);
+
+    }
+
+    public boolean validateUsername(final String username) {
+        matcher = usernamePattern.matcher(username);
+        return matcher.matches();
+    }
+
+    public boolean validatePassword(final String password) {
+        matcher = passwordPattern.matcher(password);
+        return matcher.matches();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/UuidUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/UuidUtils.java 
b/utils/src/main/java/com/cloud/utils/UuidUtils.java
new file mode 100644
index 0000000..9c4a756
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/UuidUtils.java
@@ -0,0 +1,34 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils;
+
+import org.apache.xerces.impl.xpath.regex.RegularExpression;
+
+public class UuidUtils {
+
+    public final static String first(String uuid) {
+        return uuid.substring(0, uuid.indexOf('-'));
+    }
+
+    public static boolean validateUUID(String uuid) {
+        RegularExpression regex = new 
RegularExpression("[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}");
+        return regex.matches(uuid);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/backoff/BackoffAlgorithm.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/backoff/BackoffAlgorithm.java 
b/utils/src/main/java/com/cloud/utils/backoff/BackoffAlgorithm.java
new file mode 100644
index 0000000..b8f3f00
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/backoff/BackoffAlgorithm.java
@@ -0,0 +1,38 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils.backoff;
+
+import com.cloud.utils.component.Adapter;
+
+/**
+ * BackoffAlgorithm implements multiple BackoffAlgorithm.
+ */
+public interface BackoffAlgorithm extends Adapter {
+
+    /**
+     */
+    void waitBeforeRetry();
+
+    /**
+     * no longer need to backoff.  reset to beginning.
+     */
+    void reset();
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoff.java
----------------------------------------------------------------------
diff --git 
a/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoff.java 
b/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoff.java
new file mode 100644
index 0000000..14eae16
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoff.java
@@ -0,0 +1,102 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils.backoff.impl;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ejb.Local;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.backoff.BackoffAlgorithm;
+import com.cloud.utils.component.AdapterBase;
+
+/**
+ * An implementation of BackoffAlgorithm that waits for some seconds.
+ * After the time the client can try to perform the operation again.
+ *
+ * @config
+ * {@table
+ *    || Param Name | Description | Values | Default ||
+ *    || seconds    | seconds to sleep | integer | 5 ||
+ *  }
+ **/
+@Local(value = {BackoffAlgorithm.class})
+public class ConstantTimeBackoff extends AdapterBase implements 
BackoffAlgorithm, ConstantTimeBackoffMBean {
+    long _time;
+    private final Map<String, Thread> _asleep = new ConcurrentHashMap<String, 
Thread>();
+    private final static Log LOG = 
LogFactory.getLog(ConstantTimeBackoff.class);
+
+    @Override
+    public void waitBeforeRetry() {
+        Thread current = Thread.currentThread();
+        try {
+            _asleep.put(current.getName(), current);
+            Thread.sleep(_time);
+        } catch (InterruptedException e) {
+            // JMX or other threads may interrupt this thread, but let's log it
+            // anyway, no exception to log as this is not an error
+            LOG.info("Thread " + current.getName() + " interrupted while 
waiting for retry");
+        } finally {
+            _asleep.remove(current.getName());
+        }
+        return;
+    }
+
+    @Override
+    public void reset() {
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) {
+        _time = NumbersUtil.parseLong((String)params.get("seconds"), 5) * 1000;
+        return true;
+    }
+
+    @Override
+    public Collection<String> getWaiters() {
+        return _asleep.keySet();
+    }
+
+    @Override
+    public boolean wakeup(String threadName) {
+        Thread th = _asleep.get(threadName);
+        if (th != null) {
+            th.interrupt();
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public long getTimeToWait() {
+        return _time;
+    }
+
+    @Override
+    public void setTimeToWait(long seconds) {
+        _time = seconds * 1000;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoffMBean.java
----------------------------------------------------------------------
diff --git 
a/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoffMBean.java
 
b/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoffMBean.java
new file mode 100644
index 0000000..4dc9f9c
--- /dev/null
+++ 
b/utils/src/main/java/com/cloud/utils/backoff/impl/ConstantTimeBackoffMBean.java
@@ -0,0 +1,35 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils.backoff.impl;
+
+import java.util.Collection;
+
+import com.cloud.utils.mgmt.ManagementBean;
+
+public interface ConstantTimeBackoffMBean extends ManagementBean {
+    public long getTimeToWait();
+
+    public void setTimeToWait(long seconds);
+
+    Collection<String> getWaiters();
+
+    boolean wakeup(String threadName);
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java
----------------------------------------------------------------------
diff --git 
a/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java 
b/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java
new file mode 100644
index 0000000..a6d905d
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/NetconfHelper.java
@@ -0,0 +1,355 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils.cisco.n1kv.vsm;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import com.trilead.ssh2.Connection;
+import com.trilead.ssh2.Session;
+
+import com.cloud.utils.Pair;
+import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.BindingType;
+import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.PortProfileType;
+import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.ssh.SSHCmdHelper;
+
+public class NetconfHelper {
+    private static final Logger s_logger = 
Logger.getLogger(NetconfHelper.class);
+
+    private static final String SSH_NETCONF_TERMINATOR = "]]>]]>";
+
+    private Connection _connection;
+
+    private Session _session;
+
+    public NetconfHelper(String ip, String username, String password) throws 
CloudRuntimeException {
+        _connection = SSHCmdHelper.acquireAuthorizedConnection(ip, username, 
password);
+        if (_connection == null) {
+            throw new CloudRuntimeException("Error opening ssh connection.");
+        }
+
+        try {
+            _session = _connection.openSession();
+            _session.startSubSystem("xmlagent");
+            exchangeHello();
+        } catch (final Exception e) {
+            disconnect();
+            s_logger.error("Failed to connect to device SSH server: " + 
e.getMessage());
+            throw new CloudRuntimeException("Failed to connect to SSH server: 
" + _connection.getHostname());
+        }
+    }
+
+    public void disconnect() {
+        if (_session != null) {
+            _session.close();
+        }
+        SSHCmdHelper.releaseSshConnection(_connection);
+    }
+
+    public void queryStatus() throws CloudRuntimeException {
+        // This command is used to query the server status.
+        String status =
+            "<?xml version=\"1.0\"?>" + "<nc:rpc message-id=\"1\" 
xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0" + 
"\"xmlns=\"http://www.cisco.com/nxos:1.0:xml\";>" +
+                "  <nc:get>" + "    <nc:filter type=\"subtree\">" + "      
<show>" + "        <xml>" + "          <server>" + "            <status/>" +
+                "          </server>" + "        </xml>" + "      </show>" + " 
   </nc:filter>" + "  </nc:get>" + "</nc:rpc>" + SSH_NETCONF_TERMINATOR;
+        send(status);
+        // parse the rpc reply.
+        parseOkReply(receive());
+    }
+
+    public void addPortProfile(String name, PortProfileType type, BindingType 
binding, SwitchPortMode mode, int vlanid, String vdc, String espName)
+        throws CloudRuntimeException {
+        String command = VsmCommand.getAddPortProfile(name, type, binding, 
mode, vlanid, vdc, espName);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
adding port profile.");
+        }
+    }
+
+    public void addPortProfile(String name, PortProfileType type, BindingType 
binding, SwitchPortMode mode, int vlanid) throws CloudRuntimeException {
+        String command = VsmCommand.getAddPortProfile(name, type, binding, 
mode, vlanid);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
adding port profile.");
+        }
+    }
+
+    public void updatePortProfile(String name, SwitchPortMode mode, 
List<Pair<VsmCommand.OperationType, String>> params) throws 
CloudRuntimeException {
+        String command = VsmCommand.getUpdatePortProfile(name, mode, params);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
updating port profile.");
+        }
+    }
+
+    public void deletePortProfile(String name) throws CloudRuntimeException {
+        String command = VsmCommand.getDeletePortProfile(name);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
deleting port profile.");
+        }
+    }
+
+    public void addPolicyMap(String name, int averageRate, int maxRate, int 
burstRate) throws CloudRuntimeException {
+        String command = VsmCommand.getAddPolicyMap(name, averageRate, 
maxRate, burstRate);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
adding/updating policy map.");
+        }
+    }
+
+    public void deletePolicyMap(String name) throws CloudRuntimeException {
+        String command = VsmCommand.getDeletePolicyMap(name);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
deleting policy map.");
+        }
+    }
+
+    public void updatePolicyMap(String name, int averageRate, int maxRate, int 
burstRate) throws CloudRuntimeException {
+        // Add and update of policy map work in the exact same way.
+        addPolicyMap(name, averageRate, maxRate, burstRate);
+    }
+
+    public void attachServicePolicy(String policyMap, String portProfile) 
throws CloudRuntimeException {
+        String command = VsmCommand.getServicePolicy(policyMap, portProfile, 
true);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
adding policy map.");
+        }
+    }
+
+    public void detachServicePolicy(String policyMap, String portProfile) 
throws CloudRuntimeException {
+        String command = VsmCommand.getServicePolicy(policyMap, portProfile, 
false);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
removing policy map.");
+        }
+    }
+
+    public void addVServiceNode(String vlanId, String ipAddr) throws 
CloudRuntimeException {
+        String command = VsmCommand.getVServiceNode(vlanId, ipAddr);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            parseOkReply(sendAndReceive(command));
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
adding vservice node for vlan " + vlanId);
+        }
+    }
+
+    public PortProfile getPortProfileByName(String name) throws 
CloudRuntimeException {
+        String command = VsmCommand.getPortProfile(name);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            String received = sendAndReceive(command);
+            VsmPortProfileResponse response = new 
VsmPortProfileResponse(received.trim());
+            if (!response.isResponseOk()) {
+                throw new CloudRuntimeException(response.toString());
+            } else {
+                return response.getPortProfile();
+            }
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
getting port profile.");
+        }
+    }
+
+    public PolicyMap getPolicyMapByName(String name) throws 
CloudRuntimeException {
+        String command = VsmCommand.getPolicyMap(name);
+        if (command != null) {
+            command = command.concat(SSH_NETCONF_TERMINATOR);
+            String received = sendAndReceive(command);
+            VsmPolicyMapResponse response = new 
VsmPolicyMapResponse(received.trim());
+            if (!response.isResponseOk()) {
+                throw new CloudRuntimeException(response.toString());
+            } else {
+                return response.getPolicyMap();
+            }
+        } else {
+            throw new CloudRuntimeException("Error generating rpc request for 
getting policy map.");
+        }
+    }
+
+    private void exchangeHello() {
+        String ack = receive();
+        String hello = VsmCommand.getHello() + SSH_NETCONF_TERMINATOR;
+        send(hello);
+    }
+
+    private String sendAndReceive(String command) {
+        String received;
+        synchronized (NetconfHelper.class) {
+            send(command);
+            received = receive();
+        }
+        return received;
+    }
+
+    private void send(String message) {
+        try {
+            OutputStream outputStream = _session.getStdin();
+            outputStream.write(message.getBytes());
+            outputStream.flush();
+        } catch (Exception e) {
+            s_logger.error("Failed to send message: " + e.getMessage());
+            throw new CloudRuntimeException("Failed to send message: " + 
e.getMessage());
+        }
+    }
+
+    private String receive() {
+        String response = new String("");
+        InputStream inputStream = _session.getStdout();
+
+        try {
+            Delimiter delimiter = new Delimiter();
+            byte[] buffer = new byte[1024];
+            int count = 0;
+
+            // Read the input stream till we find the end sequence ']]>]]>'.
+            while (true) {
+                int data = inputStream.read();
+                if (data != -1) {
+                    byte[] dataStream = delimiter.parse(data);
+                    if (delimiter.endReached()) {
+                        response += new String(buffer, 0, count);
+                        break;
+                    }
+
+                    if (dataStream != null) {
+                        for (int i = 0; i < dataStream.length; i++) {
+                            buffer[count] = dataStream[i];
+                            count++;
+                            if (count == 1024) {
+                                response += new String(buffer, 0, count);
+                                count = 0;
+                            }
+                        }
+                    }
+                } else {
+                    break;
+                }
+            }
+        } catch (final Exception e) {
+            throw new CloudRuntimeException("Error occured while reading from 
the stream: " + e.getMessage());
+        }
+
+        return response;
+    }
+
+    private void parseOkReply(String reply) throws CloudRuntimeException {
+        VsmOkResponse response = new VsmOkResponse(reply.trim());
+        if (!response.isResponseOk()) {
+            throw new CloudRuntimeException(response.toString());
+        }
+    }
+
+    private static class Delimiter {
+        private boolean _endReached = false;
+
+        // Used to accumulate response read while searching for end of 
response.
+        private byte[] _gatherResponse = new byte[6];
+
+        // Index into number of bytes read.
+        private int _offset = 0;
+
+        // True if ']]>]]>' detected.
+        boolean endReached() {
+            return _endReached;
+        }
+
+        // Parses the input stream and checks if end sequence is reached.
+        byte[] parse(int input) throws RuntimeException {
+            boolean collect = false;
+            byte[] streamRead = null;
+
+            // Check if end sequence matched.
+            switch (_offset) {
+                case 0:
+                    if (input == ']') {
+                        collect = true;
+                    }
+                    break;
+                case 1:
+                    if (input == ']') {
+                        collect = true;
+                    }
+                    break;
+                case 2:
+                    if (input == '>') {
+                        collect = true;
+                    }
+                    break;
+                case 3:
+                    if (input == ']') {
+                        collect = true;
+                    }
+                    break;
+                case 4:
+                    if (input == ']') {
+                        collect = true;
+                    }
+                    break;
+                case 5:
+                    if (input == '>') {
+                        collect = true;
+                        _endReached = true;
+                    }
+                    break;
+                default:
+                    throw new RuntimeException("Invalid index value: " + 
_offset);
+            }
+
+            if (collect) {
+                _gatherResponse[_offset++] = (byte)input;
+            } else {
+                // End sequence not yet reached. Return the stream of bytes 
collected so far.
+                streamRead = new byte[_offset + 1];
+                for (int index = 0; index < _offset; ++index) {
+                    streamRead[index] = _gatherResponse[index];
+                }
+
+                streamRead[_offset] = (byte)input;
+                _offset = 0;
+            }
+
+            return streamRead;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PolicyMap.java
----------------------------------------------------------------------
diff --git a/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PolicyMap.java 
b/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PolicyMap.java
new file mode 100644
index 0000000..01605d7
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PolicyMap.java
@@ -0,0 +1,34 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils.cisco.n1kv.vsm;
+
+public class PolicyMap {
+    public String policyMapName;
+    public int committedRate;
+    public int burstRate;
+    public int peakRate;
+
+    PolicyMap() {
+        policyMapName = null;
+        committedRate = 0;
+        burstRate = 0;
+        peakRate = 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PortProfile.java
----------------------------------------------------------------------
diff --git 
a/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PortProfile.java 
b/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PortProfile.java
new file mode 100644
index 0000000..53d9728
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/cisco/n1kv/vsm/PortProfile.java
@@ -0,0 +1,48 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+//
+
+package com.cloud.utils.cisco.n1kv.vsm;
+
+import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.BindingType;
+import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.PortProfileType;
+import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode;
+
+public class PortProfile {
+    public PortProfileType type;
+    public SwitchPortMode mode;
+    public BindingType binding;
+    public String profileName;
+    public String inputPolicyMap;
+    public String outputPolicyMap;
+    public String vlan;
+    public boolean status;
+    public int maxPorts;
+
+    PortProfile() {
+        profileName = null;
+        inputPolicyMap = null;
+        outputPolicyMap = null;
+        vlan = null;
+        status = false;
+        maxPorts = 32;
+        type = PortProfileType.none;
+        mode = SwitchPortMode.none;
+        binding = BindingType.none;
+    }
+}

Reply via email to