You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ki...@apache.org on 2013/02/01 07:32:04 UTC

[13/40] Added Mock ApiServer, Regions API calls with api keys

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/api/MockApiServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/MockApiServer.java b/server/src/com/cloud/api/MockApiServer.java
new file mode 100755
index 0000000..23b78a4
--- /dev/null
+++ b/server/src/com/cloud/api/MockApiServer.java
@@ -0,0 +1,638 @@
+// 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.api;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.ConnectionClosedException;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpServerConnection;
+import org.apache.http.HttpStatus;
+import org.apache.http.entity.BasicHttpEntity;
+import org.apache.http.impl.DefaultHttpResponseFactory;
+import org.apache.http.impl.DefaultHttpServerConnection;
+import org.apache.http.impl.NoConnectionReuseStrategy;
+import org.apache.http.impl.SocketHttpServerConnection;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.HttpRequestHandlerRegistry;
+import org.apache.http.protocol.HttpService;
+import org.apache.http.protocol.ResponseConnControl;
+import org.apache.http.protocol.ResponseContent;
+import org.apache.http.protocol.ResponseDate;
+import org.apache.http.protocol.ResponseServer;
+import org.apache.log4j.Logger;
+
+import com.cloud.api.response.ApiResponseSerializer;
+import com.cloud.api.response.ExceptionResponse;
+import com.cloud.async.AsyncJobManager;
+import com.cloud.cluster.StackMaid;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.ConfigurationVO;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.region.RegionManager;
+import com.cloud.server.ManagementService;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.DomainManager;
+import com.cloud.user.User;
+import com.cloud.user.UserContext;
+import com.cloud.utils.IdentityProxy;
+import com.cloud.utils.PropertiesUtil;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.exception.CSExceptionErrorCode;
+
+public class MockApiServer implements HttpRequestHandler {
+    private static final Logger s_logger = Logger.getLogger(MockApiServer.class.getName());
+
+    public static final short ADMIN_COMMAND = 1;
+    public static final short DOMAIN_ADMIN_COMMAND = 4;
+    public static final short RESOURCE_DOMAIN_ADMIN_COMMAND = 2;
+    public static final short USER_COMMAND = 8;
+    public static boolean encodeApiResponse = false;
+    public static String jsonContentType = "text/javascript";
+    private Properties _apiCommands = null;
+    private ApiDispatcher _dispatcher;
+    private AccountManager _accountMgr = null;
+    private Account _systemAccount = null;
+    private User _systemUser = null;
+
+    private static int _workerCount = 0;
+
+    private static MockApiServer s_instance = null;
+    private static List<String> s_userCommands = null;
+    private static List<String> s_resellerCommands = null; // AKA domain-admin
+    private static List<String> s_adminCommands = null;
+    private static List<String> s_resourceDomainAdminCommands = null;
+    private static List<String> s_allCommands = null;
+    private static List<String> s_pluggableServiceCommands = null;
+
+    private static ExecutorService _executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory("ApiServer"));
+
+    static {
+        s_userCommands = new ArrayList<String>();
+        s_resellerCommands = new ArrayList<String>();
+        s_adminCommands = new ArrayList<String>();
+        s_resourceDomainAdminCommands = new ArrayList<String>();
+        s_allCommands = new ArrayList<String>();
+        s_pluggableServiceCommands = new ArrayList<String>();
+    }
+
+    private MockApiServer() {
+    }
+
+    public static void initApiServer(String[] apiConfig) {
+        if (s_instance == null) {
+            s_instance = new MockApiServer();
+            s_instance.init(apiConfig);
+        }
+    }
+
+    public static MockApiServer getInstance() {
+        // initApiServer();
+        return s_instance;
+    }
+
+    public Properties get_apiCommands() {
+        return _apiCommands;
+    }
+
+    private void processConfigFiles(String[] apiConfig, boolean pluggableServicesConfig) {
+        try {
+            if (_apiCommands == null) {
+                _apiCommands = new Properties();
+            }
+            Properties preProcessedCommands = new Properties();
+            if (apiConfig != null) {
+                for (String configFile : apiConfig) {
+                    File commandsFile = PropertiesUtil.findConfigFile(configFile);
+                    if (commandsFile != null) {
+                        try {
+                            preProcessedCommands.load(new FileInputStream(commandsFile));
+                        } catch (FileNotFoundException fnfex) {
+                            // in case of a file within a jar in classpath, try to open stream using url
+                            InputStream stream = PropertiesUtil.openStreamFromURL(configFile);
+                            if (stream != null) {
+                                preProcessedCommands.load(stream);
+                            } else {
+                                s_logger.error("Unable to find properites file", fnfex);
+                            }
+                        }
+                    }
+                }
+                for (Object key : preProcessedCommands.keySet()) {
+                    String preProcessedCommand = preProcessedCommands.getProperty((String) key);
+                    String[] commandParts = preProcessedCommand.split(";");
+                    _apiCommands.put(key, commandParts[0]);
+
+                    if (pluggableServicesConfig) {
+                        s_pluggableServiceCommands.add(commandParts[0]);
+                    }
+
+                    if (commandParts.length > 1) {
+                        try {
+                            short cmdPermissions = Short.parseShort(commandParts[1]);
+                            if ((cmdPermissions & ADMIN_COMMAND) != 0) {
+                                s_adminCommands.add((String) key);
+                            }
+                            if ((cmdPermissions & RESOURCE_DOMAIN_ADMIN_COMMAND) != 0) {
+                                s_resourceDomainAdminCommands.add((String) key);
+                            }
+                            if ((cmdPermissions & DOMAIN_ADMIN_COMMAND) != 0) {
+                                s_resellerCommands.add((String) key);
+                            }
+                            if ((cmdPermissions & USER_COMMAND) != 0) {
+                                s_userCommands.add((String) key);
+                            }
+                        } catch (NumberFormatException nfe) {
+                            s_logger.info("Malformed command.properties permissions value, key = " + key + ", value = " + preProcessedCommand);
+                        }
+                    }
+                }
+
+                s_allCommands.addAll(s_adminCommands);
+                s_allCommands.addAll(s_resourceDomainAdminCommands);
+                s_allCommands.addAll(s_userCommands);
+                s_allCommands.addAll(s_resellerCommands);
+            }
+        } catch (FileNotFoundException fnfex) {
+            s_logger.error("Unable to find properites file", fnfex);
+        } catch (IOException ioex) {
+            s_logger.error("Exception loading properties file", ioex);
+        }
+    }
+
+    public void init(String[] apiConfig) {
+        BaseCmd.setComponents(new ApiResponseHelper());
+        BaseListCmd.configure();
+        processConfigFiles(apiConfig, false);
+
+        ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name);
+        _accountMgr = locator.getManager(AccountManager.class);
+        _systemAccount = _accountMgr.getSystemAccount();
+        _systemUser = _accountMgr.getSystemUser();
+        _dispatcher = ApiDispatcher.getInstance();
+
+        Integer apiPort = null; // api port, null by default
+        ConfigurationDao configDao = locator.getDao(ConfigurationDao.class);
+        SearchCriteria<ConfigurationVO> sc = configDao.createSearchCriteria();
+        sc.addAnd("name", SearchCriteria.Op.EQ, "integration.api.port");
+        List<ConfigurationVO> values = configDao.search(sc, null);
+        if ((values != null) && (values.size() > 0)) {
+            ConfigurationVO apiPortConfig = values.get(0);
+            if (apiPortConfig.getValue() != null) {
+                apiPort = Integer.parseInt(apiPortConfig.getValue());
+            }
+        }
+
+        encodeApiResponse = Boolean.valueOf(configDao.getValue(Config.EncodeApiResponse.key()));
+
+        String jsonType = configDao.getValue(Config.JavaScriptDefaultContentType.key());
+        if (jsonType != null) {
+            jsonContentType = jsonType;
+        }
+
+        if (apiPort != null) {
+            ListenerThread listenerThread = new ListenerThread(this, apiPort);
+            listenerThread.start();
+        }
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
+        // get some information for the access log...
+        StringBuffer sb = new StringBuffer();
+        HttpServerConnection connObj = (HttpServerConnection) context.getAttribute("http.connection");
+        if (connObj instanceof SocketHttpServerConnection) {
+            InetAddress remoteAddr = ((SocketHttpServerConnection) connObj).getRemoteAddress();
+            sb.append(remoteAddr.toString() + " -- ");
+        }
+        sb.append(request.getRequestLine());
+
+        try {
+            String uri = request.getRequestLine().getUri();
+            int requestParamsStartIndex = uri.indexOf('?');
+            if (requestParamsStartIndex >= 0) {
+                uri = uri.substring(requestParamsStartIndex + 1);
+            }
+
+            String[] paramArray = uri.split("&");
+            if (paramArray.length < 1) {
+                s_logger.info("no parameters received for request: " + uri + ", aborting...");
+                return;
+            }
+
+            Map parameterMap = new HashMap<String, String[]>();
+
+            String responseType = BaseCmd.RESPONSE_TYPE_XML;
+            for (String paramEntry : paramArray) {
+                String[] paramValue = paramEntry.split("=");
+                if (paramValue.length != 2) {
+                    s_logger.info("malformed parameter: " + paramEntry + ", skipping");
+                    continue;
+                }
+                if ("response".equalsIgnoreCase(paramValue[0])) {
+                    responseType = paramValue[1];
+                } else {
+                    // according to the servlet spec, the parameter map should be in the form (name=String,
+                    // value=String[]), so
+                    // parameter values will be stored in an array
+                    parameterMap.put(/* name */paramValue[0], /* value */new String[] { paramValue[1] });
+                }
+            }
+            try {
+                // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM
+                UserContext.registerContext(_systemUser.getId(), _systemAccount, null, true);
+                sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") ");
+                String responseText = handleRequest(parameterMap, true, responseType, sb);
+                sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length()));
+
+                writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null);
+            } catch (ServerApiException se) {
+                String responseText = getSerializedApiError(se.getErrorCode(), se.getDescription(), parameterMap, responseType, se);                
+                writeResponse(response, responseText, se.getErrorCode(), responseType, se.getDescription());
+                sb.append(" " + se.getErrorCode() + " " + se.getDescription());
+            } catch (RuntimeException e) {
+                // log runtime exception like NullPointerException to help identify the source easier
+                s_logger.error("Unhandled exception, ", e);
+                throw e;
+            } catch (Exception e){
+            	s_logger.info("Error: "+e.getMessage());
+            }
+        } finally {
+            UserContext.unregisterContext();
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    public String handleRequest(Map params, boolean decode, String responseType, StringBuffer auditTrailSb) throws ServerApiException {
+        String response = null;
+        String[] command = null;
+        try {
+            command = (String[]) params.get("command");
+            if (command == null) {
+                s_logger.error("invalid request, no command sent");
+                if (s_logger.isTraceEnabled()) {
+                    s_logger.trace("dumping request parameters");
+                    for (Object key : params.keySet()) {
+                        String keyStr = (String) key;
+                        String[] value = (String[]) params.get(key);
+                        s_logger.trace("   key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0]));
+                    }
+                }
+                throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent");
+            } else {
+                Map<String, String> paramMap = new HashMap<String, String>();
+                Set keys = params.keySet();
+                Iterator keysIter = keys.iterator();
+                while (keysIter.hasNext()) {
+                    String key = (String) keysIter.next();
+                    if ("command".equalsIgnoreCase(key)) {
+                        continue;
+                    }
+                    String[] value = (String[]) params.get(key);
+
+                    String decodedValue = null;
+                    if (decode) {
+                        try {
+                            decodedValue = URLDecoder.decode(value[0], "UTF-8");
+                        } catch (UnsupportedEncodingException usex) {
+                            s_logger.warn(key + " could not be decoded, value = " + value[0]);
+                            throw new ServerApiException(BaseCmd.PARAM_ERROR, key + " could not be decoded, received value " + value[0]);
+                        } catch (IllegalArgumentException iae) {
+                            s_logger.warn(key + " could not be decoded, value = " + value[0]);
+                            throw new ServerApiException(BaseCmd.PARAM_ERROR, key + " could not be decoded, received value " + value[0] + " which contains illegal characters eg.%");
+                        }
+                    } else {
+                        decodedValue = value[0];
+                    }
+                    paramMap.put(key, decodedValue);
+                }
+                String cmdClassName = _apiCommands.getProperty(command[0]);
+                if (cmdClassName != null) {
+                    Class<?> cmdClass = Class.forName(cmdClassName);
+                    BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance();
+                    cmdObj.setFullUrlParams(paramMap);
+                    cmdObj.setResponseType(responseType);
+                    // This is where the command is either serialized, or directly dispatched
+                    response = queueCommand(cmdObj, paramMap);
+                } else {
+                    if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) {
+                        String errorString = "Unknown API command: " + ((command == null) ? "null" : command[0]);
+                        s_logger.warn(errorString);
+                        auditTrailSb.append(" " + errorString);
+                        throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, errorString);
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            if (ex instanceof InvalidParameterValueException) {
+            	InvalidParameterValueException ref = (InvalidParameterValueException)ex;
+            	ServerApiException e = new ServerApiException(BaseCmd.PARAM_ERROR, ex.getMessage());            	
+                // copy over the IdentityProxy information as well and throw the serverapiexception.
+                ArrayList<IdentityProxy> idList = ref.getIdProxyList();
+                if (idList != null) {
+                	// Iterate through entire arraylist and copy over each proxy id.
+                	for (int i = 0 ; i < idList.size(); i++) {
+                		IdentityProxy obj = idList.get(i);
+                		e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName());
+                	}
+                }
+                // Also copy over the cserror code and the function/layer in which it was thrown.
+            	e.setCSErrorCode(ref.getCSErrorCode());
+                throw e;
+            } else if (ex instanceof PermissionDeniedException) {
+            	PermissionDeniedException ref = (PermissionDeniedException)ex;
+            	ServerApiException e = new ServerApiException(BaseCmd.ACCOUNT_ERROR, ex.getMessage());
+                // copy over the IdentityProxy information as well and throw the serverapiexception.
+            	ArrayList<IdentityProxy> idList = ref.getIdProxyList();
+                if (idList != null) {
+                	// Iterate through entire arraylist and copy over each proxy id.
+                	for (int i = 0 ; i < idList.size(); i++) {
+                		IdentityProxy obj = idList.get(i);
+                		e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName());
+                	}
+                }
+                e.setCSErrorCode(ref.getCSErrorCode());
+                throw e;
+            } else if (ex instanceof ServerApiException) {
+                throw (ServerApiException) ex;
+            } else {
+                s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex);
+                ServerApiException e = new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal server error, unable to execute request.");
+                e.setCSErrorCode(CSExceptionErrorCode.getCSErrCode("ServerApiException"));
+                throw e;
+            }
+        }
+        return response;
+    }
+
+    private String queueCommand(BaseCmd cmdObj, Map<String, String> params) {
+    	params.put("ctxStartEventId", String.valueOf(0L));
+    	_dispatcher.dispatch(cmdObj, params);
+    	SerializationContext.current().setUuidTranslation(true);
+    	return ApiResponseSerializer.toSerializedString((ResponseObject) cmdObj.getResponseObject(), cmdObj.getResponseType());
+    }
+
+    // FIXME: rather than isError, we might was to pass in the status code to give more flexibility
+    private void writeResponse(HttpResponse resp, final String responseText, final int statusCode, String responseType, String reasonPhrase) {
+        try {
+            resp.setStatusCode(statusCode);
+            resp.setReasonPhrase(reasonPhrase);
+
+            BasicHttpEntity body = new BasicHttpEntity();
+            if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
+                // JSON response
+                body.setContentType(jsonContentType);
+                if (responseText == null) {
+                    body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\" : \"Internal Server Error\" } }".getBytes("UTF-8")));
+                }
+            } else {
+                body.setContentType("text/xml");
+                if (responseText == null) {
+                    body.setContent(new ByteArrayInputStream("<error>Internal Server Error</error>".getBytes("UTF-8")));
+                }
+            }
+
+            if (responseText != null) {
+                body.setContent(new ByteArrayInputStream(responseText.getBytes("UTF-8")));
+            }
+            resp.setEntity(body);
+        } catch (Exception ex) {
+            s_logger.error("error!", ex);
+        }
+    }
+
+    // FIXME: the following two threads are copied from
+    // http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore/src/examples/org/apache/http/examples/ElementalHttpServer.java
+    // we have to cite a license if we are using this code directly, so we need to add the appropriate citation or
+    // modify the
+    // code to be very specific to our needs
+    static class ListenerThread extends Thread {
+        private HttpService _httpService = null;
+        private ServerSocket _serverSocket = null;
+        private HttpParams _params = null;
+
+        public ListenerThread(MockApiServer requestHandler, int port) {
+            try {
+                _serverSocket = new ServerSocket(port);
+            } catch (IOException ioex) {
+                s_logger.error("error initializing api server", ioex);
+                return;
+            }
+
+            _params = new BasicHttpParams();
+            _params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
+                    .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
+                    .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
+
+            // Set up the HTTP protocol processor
+            BasicHttpProcessor httpproc = new BasicHttpProcessor();
+            httpproc.addInterceptor(new ResponseDate());
+            httpproc.addInterceptor(new ResponseServer());
+            httpproc.addInterceptor(new ResponseContent());
+            httpproc.addInterceptor(new ResponseConnControl());
+
+            // Set up request handlers
+            HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
+            reqistry.register("*", requestHandler);
+
+            // Set up the HTTP service
+            _httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory());
+            _httpService.setParams(_params);
+            _httpService.setHandlerResolver(reqistry);
+        }
+
+        @Override
+        public void run() {
+            s_logger.info("ApiServer listening on port " + _serverSocket.getLocalPort());
+            while (!Thread.interrupted()) {
+                try {
+                    // Set up HTTP connection
+                    Socket socket = _serverSocket.accept();
+                    DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
+                    conn.bind(socket, _params);
+
+                    // Execute a new worker task to handle the request
+                    _executor.execute(new WorkerTask(_httpService, conn, _workerCount++));
+                } catch (InterruptedIOException ex) {
+                    break;
+                } catch (IOException e) {
+                    s_logger.error("I/O error initializing connection thread", e);
+                    break;
+                }
+            }
+        }
+    }
+
+    static class WorkerTask implements Runnable {
+        private final HttpService _httpService;
+        private final HttpServerConnection _conn;
+
+        public WorkerTask(final HttpService httpService, final HttpServerConnection conn, final int count) {
+            _httpService = httpService;
+            _conn = conn;
+        }
+
+        @Override
+        public void run() {
+            HttpContext context = new BasicHttpContext(null);
+            try {
+                while (!Thread.interrupted() && _conn.isOpen()) {
+                    try {
+                        _httpService.handleRequest(_conn, context);
+                        _conn.close();
+                    } finally {
+                        StackMaid.current().exitCleanup();
+                    }
+                }
+            } catch (ConnectionClosedException ex) {
+                if (s_logger.isTraceEnabled()) {
+                    s_logger.trace("ApiServer:  Client closed connection");
+                }
+            } catch (IOException ex) {
+                if (s_logger.isTraceEnabled()) {
+                    s_logger.trace("ApiServer:  IOException - " + ex);
+                }
+            } catch (HttpException ex) {
+                s_logger.warn("ApiServer:  Unrecoverable HTTP protocol violation" + ex);
+            } finally {
+                try {
+                    _conn.shutdown();
+                } catch (IOException ignore) {
+                }
+            }
+        }
+    }
+
+    public String getSerializedApiError(int errorCode, String errorText, Map<String, Object[]> apiCommandParams, String responseType, Exception ex) {
+        String responseName = null;
+        String cmdClassName = null;
+
+        String responseText = null;
+
+        try {
+            if (errorCode == BaseCmd.UNSUPPORTED_ACTION_ERROR || apiCommandParams == null || apiCommandParams.isEmpty()) {
+                responseName = "errorresponse";
+            } else {
+                Object cmdObj = apiCommandParams.get("command");
+                // cmd name can be null when "command" parameter is missing in the request
+                if (cmdObj != null) {
+                    String cmdName = ((String[]) cmdObj)[0];
+                    cmdClassName = _apiCommands.getProperty(cmdName);
+                    if (cmdClassName != null) {
+                        Class<?> claz = Class.forName(cmdClassName);
+                        responseName = ((BaseCmd) claz.newInstance()).getCommandName();
+                    } else {
+                        responseName = "errorresponse";
+                    }
+                }
+            }
+            ExceptionResponse apiResponse = new ExceptionResponse();
+            apiResponse.setErrorCode(errorCode);
+            apiResponse.setErrorText(errorText);
+            apiResponse.setResponseName(responseName);
+            // Also copy over the IdentityProxy object List into this new apiResponse, from
+            // the exception caught. When invoked from handle(), the exception here can
+            // be either ServerApiException, PermissionDeniedException or InvalidParameterValue
+            // Exception. When invoked from ApiServlet's processRequest(), this can be
+            // a standard exception like NumberFormatException. We'll leave the standard ones alone.
+            if (ex != null) {
+            	if (ex instanceof ServerApiException || ex instanceof PermissionDeniedException
+            			|| ex instanceof InvalidParameterValueException) {
+            		// Cast the exception appropriately and retrieve the IdentityProxy
+            		if (ex instanceof ServerApiException) {
+            			ServerApiException ref = (ServerApiException) ex;
+            			ArrayList<IdentityProxy> idList = ref.getIdProxyList();
+            			if (idList != null) {
+            				for (int i=0; i < idList.size(); i++) {
+            					IdentityProxy id = idList.get(i);
+            					apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
+            				}            				
+            			}
+            			// Also copy over the cserror code and the function/layer in which it was thrown.
+            			apiResponse.setCSErrorCode(ref.getCSErrorCode());
+            		} else if (ex instanceof PermissionDeniedException) {
+            			PermissionDeniedException ref = (PermissionDeniedException) ex;
+            			ArrayList<IdentityProxy> idList = ref.getIdProxyList();
+            			if (idList != null) {
+            				for (int i=0; i < idList.size(); i++) {
+            					IdentityProxy id = idList.get(i);
+            					apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
+            				}            				
+            			}
+            			// Also copy over the cserror code and the function/layer in which it was thrown.
+            			apiResponse.setCSErrorCode(ref.getCSErrorCode());
+            		} else if (ex instanceof InvalidParameterValueException) {
+            			InvalidParameterValueException ref = (InvalidParameterValueException) ex;
+            			ArrayList<IdentityProxy> idList = ref.getIdProxyList();
+            			if (idList != null) {
+            				for (int i=0; i < idList.size(); i++) {
+            					IdentityProxy id = idList.get(i);
+            					apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName());
+            				}            				
+            			}
+            			// Also copy over the cserror code and the function/layer in which it was thrown.
+            			apiResponse.setCSErrorCode(ref.getCSErrorCode());
+            		}
+            	}
+            }
+            SerializationContext.current().setUuidTranslation(true);
+            responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType);
+
+        } catch (Exception e) {
+            s_logger.error("Exception responding to http request", e);            
+        }
+        return responseText;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/domain/DomainVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/domain/DomainVO.java b/server/src/com/cloud/domain/DomainVO.java
index 87bc559..bab1dd7 100644
--- a/server/src/com/cloud/domain/DomainVO.java
+++ b/server/src/com/cloud/domain/DomainVO.java
@@ -75,11 +75,11 @@ public class DomainVO implements Domain, Identity {
     private String uuid;
 
     @Column(name="region_id")
-    private long regionId;
+    private int regionId;
     
     public DomainVO() {}
     
-    public DomainVO(String name, long owner, Long parentId, String networkDomain, Long regionId) {
+    public DomainVO(String name, long owner, Long parentId, String networkDomain, int regionId) {
     	this.parent = parentId;
         this.name = name;
         this.accountId = owner;
@@ -91,7 +91,7 @@ public class DomainVO implements Domain, Identity {
         this.regionId = regionId;
     }
 
-    public DomainVO(String name, long owner, Long parentId, String networkDomain, String uuid, Long regionId) {
+    public DomainVO(String name, long owner, Long parentId, String networkDomain, String uuid, int regionId) {
     	this.parent = parentId;
         this.name = name;
         this.accountId = owner;
@@ -215,11 +215,11 @@ public class DomainVO implements Domain, Identity {
     	this.uuid = uuid;
     }
     
-	public long getRegionId() {
+	public int getRegionId() {
 		return regionId;
 	}
 
-	public void setRegionId(long regionId) {
+	public void setRegionId(int regionId) {
 		this.regionId = regionId;
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/domain/dao/DomainDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/domain/dao/DomainDaoImpl.java b/server/src/com/cloud/domain/dao/DomainDaoImpl.java
index 90e2891..ecf8325 100644
--- a/server/src/com/cloud/domain/dao/DomainDaoImpl.java
+++ b/server/src/com/cloud/domain/dao/DomainDaoImpl.java
@@ -29,10 +29,9 @@ import org.apache.log4j.Logger;
 
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
-import com.cloud.user.UserVO;
+import com.cloud.region.RegionManager;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GenericDaoBase;
-import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
 import com.cloud.utils.db.Transaction;
@@ -47,7 +46,6 @@ public class DomainDaoImpl extends GenericDaoBase<DomainVO, Long> implements Dom
 	protected SearchBuilder<DomainVO> ImmediateChildDomainSearch;
 	protected SearchBuilder<DomainVO> FindAllChildrenSearch;
 	protected SearchBuilder<DomainVO> AllFieldsSearch;
-	private final long _regionId = 1;
 	
 	public DomainDaoImpl () {
 		DomainNameLikeSearch = createSearchBuilder();
@@ -273,10 +271,4 @@ public class DomainDaoImpl extends GenericDaoBase<DomainVO, Long> implements Dom
         return parentDomains;
     }
     
-	@Override
-	@DB
-	public DomainVO persist(DomainVO domain) {
-		domain.setRegionId(_regionId);
-		return super.persist(domain);
-	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/projects/ProjectManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java
index 68b113c..daf185f 100755
--- a/server/src/com/cloud/projects/ProjectManagerImpl.java
+++ b/server/src/com/cloud/projects/ProjectManagerImpl.java
@@ -207,7 +207,7 @@ public class ProjectManagerImpl implements ProjectManager, Manager{
         StringBuilder acctNm = new StringBuilder("PrjAcct-");
         acctNm.append(name).append("-").append(owner.getDomainId());
         
-        Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null, "", 0L);
+        Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null, "", 0);
         
         Project project = _projectDao.persist(new ProjectVO(name, displayText, owner.getDomainId(), projectAccount.getId()));
         

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/region/FindDomainResponse.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/region/FindDomainResponse.java b/server/src/com/cloud/region/FindDomainResponse.java
new file mode 100644
index 0000000..075bcf2
--- /dev/null
+++ b/server/src/com/cloud/region/FindDomainResponse.java
@@ -0,0 +1,36 @@
+// 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.region;
+
+import com.cloud.domain.Domain;
+
+
+public class FindDomainResponse {
+
+	private Domain domain;
+
+	public FindDomainResponse(){
+	}
+
+	public Domain getDomain() {
+		return domain;
+	}
+	
+	public void setDomain(Domain domain) {
+		this.domain = domain;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/region/FindUserResponse.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/region/FindUserResponse.java b/server/src/com/cloud/region/FindUserResponse.java
new file mode 100644
index 0000000..b6eba46
--- /dev/null
+++ b/server/src/com/cloud/region/FindUserResponse.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.region;
+
+
+public class FindUserResponse {
+
+	private RegionUser user;
+
+	public FindUserResponse(){
+	}
+
+	public RegionUser getUser() {
+		return user;
+	}
+	
+	public void setUser(RegionUser user) {
+		this.user = user;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/region/RegionAccount.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/region/RegionAccount.java b/server/src/com/cloud/region/RegionAccount.java
new file mode 100644
index 0000000..cb94210
--- /dev/null
+++ b/server/src/com/cloud/region/RegionAccount.java
@@ -0,0 +1,287 @@
+// 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.region;
+
+import com.cloud.user.AccountVO;
+
+public class RegionAccount extends AccountVO {
+    String accountUuid;
+    String domainUuid;
+	String domain;
+	String receivedbytes;
+	String sentbytes;
+	String vmlimit;
+	String vmtotal;
+	String vmavailable;
+	String iplimit;
+	String iptotal;
+	String ipavailable;
+	String volumelimit;
+	String volumetotal;
+	String volumeavailable;
+	String snapshotlimit;
+	String snapshottotal;
+	String snapshotavailable;
+	String templatelimit;
+	String templatetotal;
+	String templateavailable;
+	String vmstopped;
+	String vmrunning;
+	String projectlimit;
+	String projecttotal;
+	String projectavailable;
+	String networklimit;
+	String networktotal;
+	String networkavailable;
+	RegionUser user;
+
+	public RegionAccount() {
+    }
+    
+    public String getAccountuuid() {
+		return accountUuid;
+	}
+
+	public void setAccountuuid(String accountUuid) {
+		this.accountUuid = accountUuid;
+	}
+
+	public String getDomainUuid() {
+		return domainUuid;
+	}
+
+	public void setDomainUuid(String domainUuid) {
+		this.domainUuid = domainUuid;
+	}
+
+	public String getDomain() {
+		return domain;
+	}
+
+	public void setDomain(String domain) {
+		this.domain = domain;
+	}
+
+	public String getReceivedbytes() {
+		return receivedbytes;
+	}
+
+	public void setReceivedbytes(String receivedbytes) {
+		this.receivedbytes = receivedbytes;
+	}
+
+	public String getSentbytes() {
+		return sentbytes;
+	}
+
+	public void setSentbytes(String sentbytes) {
+		this.sentbytes = sentbytes;
+	}
+
+	public String getVmlimit() {
+		return vmlimit;
+	}
+
+	public void setVmlimit(String vmlimit) {
+		this.vmlimit = vmlimit;
+	}
+
+	public String getVmtotal() {
+		return vmtotal;
+	}
+
+	public void setVmtotal(String vmtotal) {
+		this.vmtotal = vmtotal;
+	}
+
+	public String getVmavailable() {
+		return vmavailable;
+	}
+
+	public void setVmavailable(String vmavailable) {
+		this.vmavailable = vmavailable;
+	}
+
+	public String getIplimit() {
+		return iplimit;
+	}
+
+	public void setIplimit(String iplimit) {
+		this.iplimit = iplimit;
+	}
+
+	public String getIptotal() {
+		return iptotal;
+	}
+
+	public void setIptotal(String iptotal) {
+		this.iptotal = iptotal;
+	}
+
+	public String getIpavailable() {
+		return ipavailable;
+	}
+
+	public void setIpavailable(String ipavailable) {
+		this.ipavailable = ipavailable;
+	}
+
+	public String getVolumelimit() {
+		return volumelimit;
+	}
+
+	public void setVolumelimit(String volumelimit) {
+		this.volumelimit = volumelimit;
+	}
+
+	public String getVolumetotal() {
+		return volumetotal;
+	}
+
+	public void setVolumetotal(String volumetotal) {
+		this.volumetotal = volumetotal;
+	}
+
+	public String getVolumeavailable() {
+		return volumeavailable;
+	}
+
+	public void setVolumeavailable(String volumeavailable) {
+		this.volumeavailable = volumeavailable;
+	}
+
+	public String getSnapshotlimit() {
+		return snapshotlimit;
+	}
+
+	public void setSnapshotlimit(String snapshotlimit) {
+		this.snapshotlimit = snapshotlimit;
+	}
+
+	public String getSnapshottotal() {
+		return snapshottotal;
+	}
+
+	public void setSnapshottotal(String snapshottotal) {
+		this.snapshottotal = snapshottotal;
+	}
+
+	public String getSnapshotavailable() {
+		return snapshotavailable;
+	}
+
+	public void setSnapshotavailable(String snapshotavailable) {
+		this.snapshotavailable = snapshotavailable;
+	}
+
+	public String getTemplatelimit() {
+		return templatelimit;
+	}
+
+	public void setTemplatelimit(String templatelimit) {
+		this.templatelimit = templatelimit;
+	}
+
+	public String getTemplatetotal() {
+		return templatetotal;
+	}
+
+	public void setTemplatetotal(String templatetotal) {
+		this.templatetotal = templatetotal;
+	}
+
+	public String getTemplateavailable() {
+		return templateavailable;
+	}
+
+	public void setTemplateavailable(String templateavailable) {
+		this.templateavailable = templateavailable;
+	}
+
+	public String getVmstopped() {
+		return vmstopped;
+	}
+
+	public void setVmstopped(String vmstopped) {
+		this.vmstopped = vmstopped;
+	}
+
+	public String getVmrunning() {
+		return vmrunning;
+	}
+
+	public void setVmrunning(String vmrunning) {
+		this.vmrunning = vmrunning;
+	}
+
+	public String getProjectlimit() {
+		return projectlimit;
+	}
+
+	public void setProjectlimit(String projectlimit) {
+		this.projectlimit = projectlimit;
+	}
+
+	public String getProjecttotal() {
+		return projecttotal;
+	}
+
+	public void setProjecttotal(String projecttotal) {
+		this.projecttotal = projecttotal;
+	}
+
+	public String getProjectavailable() {
+		return projectavailable;
+	}
+
+	public void setProjectavailable(String projectavailable) {
+		this.projectavailable = projectavailable;
+	}
+
+	public String getNetworklimit() {
+		return networklimit;
+	}
+
+	public void setNetworklimit(String networklimit) {
+		this.networklimit = networklimit;
+	}
+
+	public String getNetworktotal() {
+		return networktotal;
+	}
+
+	public void setNetworktotal(String networktotal) {
+		this.networktotal = networktotal;
+	}
+
+	public String getNetworkavailable() {
+		return networkavailable;
+	}
+
+	public void setNetworkavailable(String networkavailable) {
+		this.networkavailable = networkavailable;
+	}
+
+	public RegionUser getUser() {
+		return user;
+	}
+
+	public void setUser(RegionUser user) {
+		this.user = user;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/region/RegionDomain.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/region/RegionDomain.java b/server/src/com/cloud/region/RegionDomain.java
new file mode 100644
index 0000000..de82654
--- /dev/null
+++ b/server/src/com/cloud/region/RegionDomain.java
@@ -0,0 +1,61 @@
+// 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.region;
+
+import com.cloud.domain.DomainVO;
+
+public class RegionDomain extends DomainVO {
+    String accountUuid;
+    String parentUuid;
+    String parentdomainname;
+    Boolean haschild;
+
+	public RegionDomain() {
+    }
+    
+    public String getAccountuuid() {
+		return accountUuid;
+	}
+
+	public void setAccountuuid(String accountUuid) {
+		this.accountUuid = accountUuid;
+	}
+
+	public String getParentUuid() {
+		return parentUuid;
+	}
+
+	public void setParentUuid(String parentUuid) {
+		this.parentUuid = parentUuid;
+	}
+
+	public String getParentdomainname() {
+		return parentdomainname;
+	}
+
+	public void setParentdomainname(String parentdomainname) {
+		this.parentdomainname = parentdomainname;
+	}
+
+	public Boolean getHaschild() {
+		return haschild;
+	}
+
+	public void setHaschild(Boolean haschild) {
+		this.haschild = haschild;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f0f33bf4/server/src/com/cloud/region/RegionManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/region/RegionManager.java b/server/src/com/cloud/region/RegionManager.java
index d74633d..20e24ba 100644
--- a/server/src/com/cloud/region/RegionManager.java
+++ b/server/src/com/cloud/region/RegionManager.java
@@ -18,14 +18,19 @@ package com.cloud.region;
 
 import java.util.Map;
 
+import com.cloud.domain.DomainVO;
+import com.cloud.user.UserAccount;
+
 
 public interface RegionManager {
 	public boolean propogateAddAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain,
             Map<String, String> details, String accountUUID, String userUUID);
-	public long getId();
-	public void setId(long id);
+	public int getId();
+	public void setId(int id);
 	public void propogateAddUser(String userName, String password,
 			String firstName, String lastName, String email, String timeZone,
 			String accountName, String domainUUId, String userUUID);
 	public void propogateAddDomain(String name, Long parentId, String networkDomain, String uuid);
+	UserAccount getUserAccount(String username, Long domainId);
+	DomainVO findDomainByPath(String domainPath);	
 }