gt: 	    for (RepoOperationTO repoOperation: repoOperations) {
context: /*
   * Copyright (C) 2007-2019 Crafter Software Corporation. All Rights Reserved.
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
  package org.craftercms.studio.impl.v1.service.site;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.time.ZoneOffset;
  import java.time.ZonedDateTime;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Objects;
  import java.util.Set;
  import java.util.StringTokenizer;
  import java.util.UUID;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import org.apache.commons.io.FilenameUtils;
  import org.apache.commons.collections4.CollectionUtils;
  import org.apache.commons.io.IOUtils;
  import org.apache.commons.lang3.StringUtils;
  import org.apache.http.HttpStatus;
  import org.apache.http.client.config.RequestConfig;
  import org.apache.http.client.methods.CloseableHttpResponse;
  import org.apache.http.client.methods.HttpGet;
  import org.apache.http.impl.client.CloseableHttpClient;
  import org.apache.http.impl.client.HttpClientBuilder;
  import org.craftercms.commons.entitlements.exception.EntitlementException;
  import org.craftercms.commons.entitlements.model.EntitlementType;
  import org.craftercms.commons.entitlements.validator.EntitlementValidator;
  import org.craftercms.commons.plugin.model.PluginDescriptor;
  import org.craftercms.commons.rest.RestServiceException;
  import org.craftercms.commons.validation.annotations.param.ValidateIntegerParam;
  import org.craftercms.commons.validation.annotations.param.ValidateNoTagsParam;
  import org.craftercms.commons.validation.annotations.param.ValidateParams;
  import org.craftercms.commons.validation.annotations.param.ValidateSecurePathParam;
  import org.craftercms.commons.validation.annotations.param.ValidateStringParam;
  import org.craftercms.studio.api.v1.constant.DmConstants;
  import org.craftercms.studio.api.v1.constant.StudioConstants;
  import org.craftercms.studio.api.v1.dal.GitLog;
  import org.craftercms.studio.api.v1.dal.ItemMetadata;
  import org.craftercms.studio.api.v1.dal.ItemState;
  import org.craftercms.studio.api.v1.dal.SiteFeed;
  import org.craftercms.studio.api.v1.dal.SiteFeedMapper;
  import org.craftercms.studio.api.v1.ebus.PreviewEventContext;
  import org.craftercms.studio.api.v1.exception.BlueprintNotFoundException;
  import org.craftercms.studio.api.v1.exception.ContentNotFoundException;
  import org.craftercms.studio.api.v1.exception.DeployerTargetException;
  import org.craftercms.studio.api.v1.exception.ServiceLayerException;
  import org.craftercms.studio.api.v1.exception.SiteAlreadyExistsException;
  import org.craftercms.studio.api.v1.exception.SiteCreationException;
  import org.craftercms.studio.api.v1.exception.SiteNotFoundException;
  import org.craftercms.studio.api.v1.exception.repository.InvalidRemoteRepositoryCredentialsException;
  import org.craftercms.studio.api.v1.exception.repository.InvalidRemoteRepositoryException;
  import org.craftercms.studio.api.v1.exception.repository.InvalidRemoteUrlException;
  import org.craftercms.studio.api.v1.exception.repository.RemoteRepositoryNotBareException;
  import org.craftercms.studio.api.v1.exception.repository.RemoteRepositoryNotFoundException;
  import org.craftercms.studio.api.v1.exception.security.GroupAlreadyExistsException;
  import org.craftercms.studio.api.v1.exception.security.UserNotFoundException;
  import org.craftercms.studio.api.v1.log.Logger;
  import org.craftercms.studio.api.v1.log.LoggerFactory;
  import org.craftercms.studio.api.v1.repository.ContentRepository;
  import org.craftercms.studio.api.v1.repository.RepositoryItem;
  import org.craftercms.studio.api.v1.service.GeneralLockService;
  import org.craftercms.studio.api.v1.service.configuration.ServicesConfig;
  import org.craftercms.studio.api.v1.service.configuration.SiteEnvironmentConfig;
  import org.craftercms.studio.api.v1.service.content.ContentService;
  import org.craftercms.studio.api.v1.service.content.ContentTypeService;
  import org.craftercms.studio.api.v1.service.content.DmPageNavigationOrderService;
  import org.craftercms.studio.api.v1.service.content.ImportService;
  import org.craftercms.studio.api.v1.service.content.ObjectMetadataManager;
  import org.craftercms.studio.api.v1.service.dependency.DependencyService;
  import org.craftercms.studio.api.v1.service.deployment.DeploymentService;
  import org.craftercms.studio.api.v1.service.event.EventService;
  import org.craftercms.studio.api.v1.service.objectstate.ObjectStateService;
  import org.craftercms.studio.api.v1.service.objectstate.State;
  import org.craftercms.studio.api.v1.service.objectstate.TransitionEvent;
  import org.craftercms.studio.api.v1.service.security.SecurityService;
  import org.craftercms.studio.api.v1.service.site.SiteConfigNotFoundException;
  import org.craftercms.studio.api.v1.service.site.SiteService;
  import org.craftercms.studio.api.v1.to.EnvironmentConfigTO;
  import org.craftercms.studio.api.v1.to.PublishStatus;
  import org.craftercms.studio.api.v1.to.PublishingTargetTO;
  import org.craftercms.studio.api.v1.to.RemoteRepositoryInfoTO;
  import org.craftercms.studio.api.v1.to.RepoOperationTO;
  import org.craftercms.studio.api.v1.to.SiteBlueprintTO;
  import org.craftercms.studio.api.v1.to.SiteTO;
  import org.craftercms.studio.api.v2.dal.AuditLog;
  import org.craftercms.studio.api.v2.deployment.Deployer;
  import org.craftercms.studio.api.v2.exception.MissingPluginParameterException;
  import org.craftercms.studio.api.v2.service.audit.internal.AuditServiceInternal;
  import org.craftercms.studio.api.v2.service.config.ConfigurationService;
  import org.craftercms.studio.api.v2.service.notification.NotificationService;
  import org.craftercms.studio.api.v2.service.security.internal.GroupServiceInternal;
  import org.craftercms.studio.api.v2.service.security.internal.UserServiceInternal;
  import org.craftercms.studio.api.v2.service.site.internal.SitesServiceInternal;
  import org.craftercms.studio.api.v2.upgrade.UpgradeManager;
  import org.craftercms.studio.api.v2.utils.StudioConfiguration;
  import org.craftercms.studio.impl.v1.repository.job.RebuildRepositoryMetadata;
  import org.craftercms.studio.impl.v1.repository.job.SyncDatabaseWithRepository;
  import org.craftercms.studio.impl.v1.util.ContentUtils;
  import org.dom4j.Document;
  import org.dom4j.DocumentException;
  import org.dom4j.DocumentHelper;
  import org.dom4j.Element;
  import org.dom4j.Node;
  import org.dom4j.io.SAXReader;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.xml.sax.SAXException;
  
  import static org.craftercms.studio.api.v1.constant.StudioConstants.CONTENT_TYPE_CONFIG_FOLDER;
  import static org.craftercms.studio.api.v1.constant.StudioConstants.DEFAULT_ORGANIZATION_ID;
  import static org.craftercms.studio.api.v1.constant.StudioConstants.FILE_SEPARATOR;
  import static org.craftercms.studio.api.v1.constant.StudioConstants.MODULE_STUDIO;
  import static org.craftercms.studio.api.v1.constant.StudioConstants.REMOTE_REPOSITORY_CREATE_OPTION_CLONE;
  import static org.craftercms.studio.api.v1.constant.StudioConstants.REMOTE_REPOSITORY_CREATE_OPTION_PUSH;
  import static org.craftercms.studio.api.v1.constant.StudioConstants.SITE_DEFAULT_GROUPS_DESCRIPTION;
  import static org.craftercms.studio.api.v1.ebus.EBusConstants.EVENT_PREVIEW_SYNC;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.OPERATION_ADD_REMOTE;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.OPERATION_CREATE;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.OPERATION_DELETE;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.OPERATION_MOVE;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.OPERATION_REMOVE_REMOTE;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.OPERATION_UPDATE;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.ORIGIN_GIT;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.TARGET_TYPE_CONTENT_ITEM;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.TARGET_TYPE_REMOTE_REPOSITORY;
  import static org.craftercms.studio.api.v2.dal.AuditLogConstants.TARGET_TYPE_SITE;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.BLUE_PRINTS_PATH;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_DEFAULT_ADMIN_GROUP;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_DEFAULT_GROUPS;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_ENVIRONMENT_ACTIVE;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_GLOBAL_CONFIG_BASE_PATH;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_GLOBAL_SYSTEM_SITE;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_CONFIG_BASE_PATH;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_ENVIRONMENT;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.CONFIGURATION_SITE_PREVIEW_DESTROY_CONTEXT_URL;
  import static org.craftercms.studio.api.v2.utils.StudioConfiguration.JOB_DEPLOY_CONTENT_TO_ENVIRONMENT_STATUS_MESSAGE_DEFAULT;
  
  /**
   * Note: consider renaming
   * A site in Crafter Studio is currently the name for a WEM project being managed.
   * This service provides access to site configuration
   * @author russdanner
   */
  public class SiteServiceImpl implements SiteService {
  
  	private final static Logger logger = LoggerFactory.getLogger(SiteServiceImpl.class);
  
      protected Deployer deployer;
      protected SiteServiceDAL _siteServiceDAL;
      protected ServicesConfig servicesConfig;
      protected ContentService contentService;
      protected SiteEnvironmentConfig environmentConfig;
      protected ContentRepository contentRepository;
      protected ObjectStateService objectStateService;
      protected DependencyService dependencyService;
      protected SecurityService securityService;
      protected DeploymentService deploymentService;
      protected ObjectMetadataManager objectMetadataManager;
      protected DmPageNavigationOrderService dmPageNavigationOrderService;
      protected ContentTypeService contentTypeService;
      protected ImportService importService;
      protected NotificationService notificationService;
      protected GeneralLockService generalLockService;
      protected RebuildRepositoryMetadata rebuildRepositoryMetadata;
      protected SyncDatabaseWithRepository syncDatabaseWithRepository;
      protected EventService eventService;
      protected GroupServiceInternal groupServiceInternal;
      protected UserServiceInternal userServiceInternal;
      protected UpgradeManager upgradeManager;
      protected StudioConfiguration studioConfiguration;
      protected SitesServiceInternal sitesServiceInternal;
      protected AuditServiceInternal auditServiceInternal;
      protected ConfigurationService configurationService;
  
      @Autowired
      protected SiteFeedMapper siteFeedMapper;
  
      protected EntitlementValidator entitlementValidator;
  
      @Override
      @ValidateParams
      public boolean writeConfiguration(@ValidateStringParam(name = "site") String site,
                                        @ValidateSecurePathParam(name = "path") String path, InputStream content)
              throws ServiceLayerException {
          // Write site configuration
          String operation = OPERATION_UPDATE;
          if (!contentRepository.contentExists(site, path)) {
              operation = OPERATION_CREATE;
          }
          String commitId = contentRepository.writeContent(site, path, content);
          contentRepository.reloadRepository(site);
  
          PreviewEventContext context = new PreviewEventContext();
          context.setSite(site);
          eventService.publish(EVENT_PREVIEW_SYNC, context);
  
          String user = securityService.getCurrentUser();
          Map<String, String> extraInfo = new HashMap<String, String>();
          if (StringUtils.startsWith(path, contentTypeService.getConfigPath())) {
              extraInfo.put(DmConstants.KEY_CONTENT_TYPE, StudioConstants.CONTENT_TYPE_CONTENT_TYPE);
          } else {
              extraInfo.put(DmConstants.KEY_CONTENT_TYPE, StudioConstants.CONTENT_TYPE_CONFIGURATION);
          }
          SiteFeed siteFeed = getSite(site);
          AuditLog auditLog = auditServiceInternal.createAuditLogEntry();
          auditLog.setOperation(operation);
          auditLog.setSiteId(siteFeed.getId());
          auditLog.setActorId(user);
          auditLog.setPrimaryTargetId(site + ":" + path);
          auditLog.setPrimaryTargetType(TARGET_TYPE_CONTENT_ITEM);
          auditLog.setPrimaryTargetValue(path);
          auditServiceInternal.insertAuditLog(auditLog);
          objectStateService.transition(site, path, TransitionEvent.SAVE);
          if (!objectMetadataManager.metadataExist(site, path)) {
              objectMetadataManager.insertNewObjectMetadata(site, path);
          }
  
          Map<String, Object> properties = new HashMap<>();
          properties.put(ItemMetadata.PROP_NAME, FilenameUtils.getName(path));
          properties.put(ItemMetadata.PROP_MODIFIED, ZonedDateTime.now(ZoneOffset.UTC));
          properties.put(ItemMetadata.PROP_MODIFIER, user);
          objectMetadataManager.setObjectMetadata(site, path, properties);
  
          if (commitId != null) {
              objectMetadataManager.updateCommitId(site, path, commitId);
              contentRepository.insertGitLog(site, commitId, 1);
          }
          boolean toRet = StringUtils.isEmpty(commitId);
  
          return toRet;
      }
  
  	@Override
      @ValidateParams
  	public boolean writeConfiguration(@ValidateSecurePathParam(name = "path") String path, InputStream content)
              throws ServiceLayerException {
  	    // Write global configuration
          String commitId = contentRepository.writeContent("", path, content);
          boolean toReturn = StringUtils.isEmpty(commitId);
          return toReturn;
  	}
  
  	@Override
      @ValidateParams
  	public Map<String, Object> getConfiguration(@ValidateSecurePathParam(name = "path") String path) {
  		return null;
  	}
  
  
  	/**
  	 * given a site ID return the configuration as a document
  	 * This method allows extensions to add additional properties to the configuration that
  	 * are not made available through the site configuration object
  	 * @param site the name of the site
  	 * @return a Document containing the entire site configuration
  	 */
  	@Override
      @ValidateParams
  	public Document getSiteConfiguration(@ValidateStringParam(name = "site") String site)
  	throws SiteConfigNotFoundException {
  		return _siteServiceDAL.getSiteConfiguration(site);
  	}
  
  	@Override
      @ValidateParams
  	public Map<String, Object> getConfiguration(@ValidateStringParam(name = "site") String site,
                                                  @ValidateSecurePathParam(name = "path") String path,
                                                  boolean applyEnv) {
  		String configPath;
          String configContent;
  		if (StringUtils.isEmpty(site)) {
  			configPath = getGlobalConfigRoot() + path;
  			configContent = contentService.getContentAsString(site, configPath);
  		} else {
  		    if (path.startsWith(FILE_SEPARATOR + CONTENT_TYPE_CONFIG_FOLDER + FILE_SEPARATOR)) {
                  configPath = getSitesConfigPath() + path;
                  configContent = contentService.getContentAsString(site, configPath);
              } else {
  		        configContent = configurationService.getConfigurationAsString(site, MODULE_STUDIO, path,
                          studioConfiguration.getProperty(CONFIGURATION_ENVIRONMENT_ACTIVE));
              }
  		}
  
  
  		Map<String, Object> toRet = null;
  		if (configContent != null) {
  			configContent = configContent.replaceAll("\\n([\\s]+)?+", "");
  			configContent = configContent.replaceAll("<!--(.*?)-->", "");
  			toRet = convertNodesFromXml(configContent);
  		}
  		return toRet;
  	}
  
  	private Map<String, Object> convertNodesFromXml(String xml) {
  		try {
  			Document document = DocumentHelper.parseText(xml);
  			return createMap(document.getRootElement());
  
  		} catch (DocumentException e) {
              logger.error("Error reading xml string:\n" + xml);
  		}
  		return null;
  	}
  
      @SuppressWarnings("unchecked")
  	private  Map<String, Object> createMap(Element element) {
  		Map<String, Object> map = new HashMap<String, Object>();
  		for ( int i = 0, size = element.nodeCount(); i < size; i++ ) {
  			Node currentNode = element.node(i);
  			if ( currentNode instanceof Element ) {
  				Element currentElement = (Element)currentNode;
  				String key = currentElement.getName();
  				Object toAdd = null;
  				if (currentElement.isTextOnly()) {
  					 toAdd = currentElement.getStringValue();
  				} else {
  					toAdd = createMap(currentElement);
  				}
  				if (map.containsKey(key)) {
  					Object value = map.get(key);
  					List listOfValues = new ArrayList<Object>();
  					if (value instanceof List) {
  						listOfValues = (List<Object>)value;
  					} else {
  						listOfValues.add(value);
  					}
  					listOfValues.add(toAdd);
  					map.put(key, listOfValues);
  				} else {
  					map.put(key, toAdd);
  				}
  			}
  		}
  		return map;
  	}
  
  
  	/***
  	 * load site environment specific info
  	 *
  	 * @param site
  	 * @param siteConfig
  	 */
  	protected void loadSiteEnvironmentConfig(String site, SiteTO siteConfig) {
  		// get environment specific configuration
  		logger.debug("Loading site environment configuration for " + site + "; Environemnt: " + getEnvironment());
  		EnvironmentConfigTO environmentConfigTO = environmentConfig.getEnvironmentConfig(site);
  		if (environmentConfigTO == null) {
  			logger.error("Environment configuration for site " + site + " does not exist.");
  			return;
  		}
  		siteConfig.setLiveUrl(environmentConfigTO.getLiveServerUrl());
  		siteConfig.setAuthoringUrl(environmentConfigTO.getAuthoringServerUrl());
  		siteConfig.setPreviewUrl(environmentConfigTO.getPreviewServerUrl());
  		siteConfig.setAdminEmail(environmentConfigTO.getAdminEmailAddress());
  		siteConfig.setOpenSiteDropdown(environmentConfigTO.getOpenDropdown());
  	}
  
      @Override
      @ValidateParams
      public List<PublishingTargetTO> getPublishingTargetsForSite(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getPublishingTargetsForSite(site);
      }
  
      @Override
      public Set<String> getAllAvailableSites() {
          List<SiteFeed> sites = siteFeedMapper.getSites();
          Set<String> toRet = new HashSet<>();
          for (SiteFeed site : sites) {
              toRet.add(site.getSiteId());
          }
          return toRet;
      }
  
  	@Override
  	public int countSites() {
  		return siteFeedMapper.countSites();
  	}
  
  	@Override
      @ValidateParams
     	public void createSiteFromBlueprint(@ValidateStringParam(name = "blueprintId") String blueprintId,
                                             @ValidateNoTagsParam(name = "siteName") String siteName,
                                             @ValidateStringParam(name = "siteId") String siteId,
                                             @ValidateStringParam(name = "sandboxBranch") String sandboxBranch,
                                             @ValidateNoTagsParam(name = "desc") String desc,
                                             Map<String, String> params, boolean createAsOrphan)
              throws SiteAlreadyExistsException, SiteCreationException, DeployerTargetException,
              BlueprintNotFoundException, MissingPluginParameterException {
  	    if (exists(siteId)) {
  	        throw new SiteAlreadyExistsException();
          }
  
  	    logger.debug("Get blueprint descriptor for: " + blueprintId);
          PluginDescriptor descriptor = sitesServiceInternal.getBlueprintDescriptor(blueprintId);
          if (Objects.isNull(descriptor)) {
              throw new BlueprintNotFoundException();
          }
  
          logger.debug("Validating blueprint parameters");
          sitesServiceInternal.validateBlueprintParameters(descriptor, params);
          String blueprintLocation = sitesServiceInternal.getBlueprintLocation(blueprintId);
          String searchEngine = descriptor.getPlugin().getSearchEngine();
  
          logger.debug("Validate site entitlements");
          try {
  			entitlementValidator.validateEntitlement(EntitlementType.SITE, 1);
  		} catch (EntitlementException e) {
  	    	throw new SiteCreationException("Unable to complete request due to entitlement limits. Please contact " +
                                              "your system administrator.", e);
  		}
  
          logger.info("Starting site creation process for site " + siteName + " from " + blueprintId + " blueprint.");
          boolean success = true;
  
  	    // We must fail site creation if any of the site creations steps fail and rollback
  	    // For example: Create site => create Deployer Target (fail) = fail
  	    // and rollback the whole thing.
  	    // What we need to do for site creation and the order of execution:
  	    // 1) deployer target, 2) git repo, 3) database, 4) kick deployer
          String siteUuid = UUID.randomUUID().toString();
  
  	    // Create the site in the preview deployer
          logger.info("Creating deployer targets.");
          try {
              deployer.createTargets(siteId, searchEngine);
          } catch (Exception e) {
              success = false;
              String msg = "Error while creating site: " + siteName + " ID: " + siteId + " from blueprint: " +
                           blueprintId + ". The required Deployer targets couldn't be created";
  
              logger.error(msg, e);
  
              throw new DeployerTargetException(msg, e);
          }
  
  	    if (success) {
  	 		try {
  	 		    logger.info("Copying site content from blueprint.");
                  success = createSiteFromBlueprintGit(blueprintLocation, siteName, siteId, sandboxBranch, desc, params);
  
                  logger.debug("Adding site UUID.");
                  addSiteUuidFile(siteId, siteUuid);
  
                  logger.info("Adding site record to database for site " + siteId);
                  // insert database records
                  SiteFeed siteFeed = new SiteFeed();
                  siteFeed.setName(siteName);
                  siteFeed.setSiteId(siteId);
                  siteFeed.setSiteUuid(siteUuid);
                  siteFeed.setDescription(desc);
                  siteFeed.setPublishingStatusMessage(
                          studioConfiguration.getProperty(JOB_DEPLOY_CONTENT_TO_ENVIRONMENT_STATUS_MESSAGE_DEFAULT));
                  siteFeed.setSandboxBranch(sandboxBranch);
                  siteFeed.setSearchEngine(searchEngine);
                  siteFeedMapper.createSite(siteFeed);
  
                  logger.info("Upgrading site.");
                  upgradeManager.upgradeSite(siteId);
  
                  logger.debug("Adding audit log");
                  insertCreateSiteAuditLog(siteId, siteName);
  
                  // Add default groups
                  logger.info("Adding default groups");
                  addDefaultGroupsForNewSite(siteId);
  
                  logger.info("Reload site configuration");
                  reloadSiteConfiguration(siteId);
  
                  logger.info("Syncing database with repository.");
                  syncDatabaseWithRepo(siteId, contentRepository.getRepoFirstCommitId(siteId), true);
  
                  // initial deployment
                  logger.info("Performing initial deployment");
                  List<PublishingTargetTO> publishingTargets = getPublishingTargetsForSite(siteId);
                  if (publishingTargets != null && publishingTargets.size() > 0) {
                      for (PublishingTargetTO target : publishingTargets) {
                          if (StringUtils.isNotEmpty(target.getRepoBranchName())) {
                              contentRepository.initialPublish(siteId, sandboxBranch, target.getRepoBranchName(),
                                      securityService.getCurrentUser(), "Create site.");
                          }
                      }
                  }
                  objectStateService.setStateForSiteContent(siteId, State.EXISTING_UNEDITED_UNLOCKED);
  	        } catch(Exception e) {
  	            success = false;
  	            logger.error("Error while creating site: " + siteName + " ID: " + siteId + " from blueprint: " +
  	                    blueprintId + ". Rolling back.", e);
  
  				deleteSite(siteId);
  
  			    throw new SiteCreationException("Error while creating site: " + siteName + " ID: " + siteId +
                                                  " from blueprint: " + blueprintId + ". Rolling back.");
  		    }
  	    }
  
  	    if (success) {
  	        logger.info("Syncing all content to preview.");
  		    // Now that everything is created, we can sync the preview deployer with the new content
  		    try {
  			    deploymentService.syncAllContentToPreview(siteId, true);
  		    } catch (ServiceLayerException e) {
  			    logger.error("Error while syncing site: " + siteName + " ID: " + siteId + " to preview. Site was "
  				    + "successfully created otherwise. Ignoring.", e);
  
  			    throw new SiteCreationException("Error while syncing site: " + siteName + " ID: " + siteId +
                          " to preview. Site was successfully created, but it won't be preview-able until the Preview " +
                          "Deployer is reachable.");
  		    }
  	    } else {
  		    throw new SiteCreationException("Error while creating site: " + siteName + " ID: " + siteId + ".");
  	    }
  	    logger.info("Finished creating site " + siteId);
      }
  
      private void insertCreateSiteAuditLog(String siteId, String siteName) throws SiteNotFoundException {
  	    SiteFeed siteFeed = getSite(studioConfiguration.getProperty(CONFIGURATION_GLOBAL_SYSTEM_SITE));
          String user = securityService.getCurrentUser();
  	    AuditLog auditLog = auditServiceInternal.createAuditLogEntry();
          auditLog.setOperation(OPERATION_CREATE);
          auditLog.setSiteId(siteFeed.getId());
          auditLog.setActorId(user);
          auditLog.setPrimaryTargetId(siteId);
          auditLog.setPrimaryTargetType(TARGET_TYPE_SITE);
          auditLog.setPrimaryTargetValue(siteName);
          auditServiceInternal.insertAuditLog(auditLog);
      }
  
      protected boolean createSiteFromBlueprintGit(String blueprintLocation, String siteName, String siteId,
                                                   String sandboxBranch, String desc, Map<String, String> params)
              throws Exception {
          boolean success = true;
  
          // create site with git repo
          contentRepository.createSiteFromBlueprint(blueprintLocation, siteId, sandboxBranch, params);
  
  
          String siteConfigFolder = FILE_SEPARATOR + "config" + FILE_SEPARATOR + "studio";
          replaceFileContentGit(siteId, siteConfigFolder + FILE_SEPARATOR + "site-config.xml", "SITENAME",
                  siteId);
  
          return success;
      }
  
      protected void replaceFileContentGit(String site, String path, String find, String replace) throws Exception {
          InputStream content = contentRepository.getContent(site, path);
          String contentAsString = IOUtils.toString(content);
  
          contentAsString = contentAsString.replaceAll(find, replace);
  
          InputStream contentToWrite = IOUtils.toInputStream(contentAsString);
  
          contentRepository.writeContent(site, path, contentToWrite);
      }
  
  	protected void createObjectStatesforNewSite(String site) {
  		createObjectStateNewSiteObjectFolder(site, FILE_SEPARATOR);
  	}
  
  	protected void createObjectStateNewSiteObjectFolder(String site, String path) {
  		RepositoryItem[] children = contentRepository.getContentChildren(site, path);
  		for (RepositoryItem child : children) {
  			if (child.isFolder) {
  				createObjectStateNewSiteObjectFolder(site, child.path + FILE_SEPARATOR + child.name);
  			} else {
  				objectStateService.insertNewEntry(site, child.path + FILE_SEPARATOR + child.name);
  			}
  		}
  	}
  
      protected void createObjectMetadataforNewSite(String site, String lastCommitId) {
          createObjectMetadataNewSiteObjectFolder(site, FILE_SEPARATOR, lastCommitId);
      }
  
      protected void createObjectMetadataNewSiteObjectFolder(String site, String path, String lastCommitId) {
          RepositoryItem[] children = contentRepository.getContentChildren(site, path);
          for (RepositoryItem child : children) {
              if (child.isFolder) {
                  createObjectMetadataNewSiteObjectFolder(site, child.path + FILE_SEPARATOR + child.name,
                          lastCommitId);
              } else {
                  objectMetadataManager.insertNewObjectMetadata(site, child.path + FILE_SEPARATOR + child.name);
                  objectMetadataManager.updateCommitId(site, child.path + FILE_SEPARATOR + child.name,
                          lastCommitId);
              }
          }
      }
  
  	protected void extractDependenciesForNewSite(String site) {
          Map<String, Set<String>> globalDeps = new HashMap<String, Set<String>>();
          extractDependenciesItemForNewSite(site, FILE_SEPARATOR, globalDeps);
  	}
  
      private void extractDependenciesItemForNewSite(String site, String fullPath, Map<String, Set<String>> globalDeps) {
          RepositoryItem[] children = contentRepository.getContentChildren(site, fullPath);
          for (RepositoryItem child : children) {
              if (child.isFolder) {
                  extractDependenciesItemForNewSite(site, child.path + FILE_SEPARATOR + child.name, globalDeps);
              } else {
                  String childPath = child.path + FILE_SEPARATOR + child.name;
  
                  if (childPath.endsWith(DmConstants.XML_PATTERN)) {
                      try {
                          dependencyService.upsertDependencies(site, childPath);
                      } catch (ContentNotFoundException e) {
                          logger.error("Failed to extract dependencies for document: site " + site + " path " +
                                  childPath, e);
                      } catch (ServiceLayerException e) {
                          logger.error("Failed to extract dependencies for document: site " + site + " path " +
                                  childPath, e);
                      }
                  } else {
  
                      boolean isCss = childPath.endsWith(DmConstants.CSS_PATTERN);
                      boolean isJs = childPath.endsWith(DmConstants.JS_PATTERN);
                      List<String> templatePatterns = servicesConfig.getRenderingTemplatePatterns(site);
                      boolean isTemplate = false;
                      for (String templatePattern : templatePatterns) {
                          Pattern pattern = Pattern.compile(templatePattern);
                          Matcher matcher = pattern.matcher(childPath);
                          if (matcher.matches()) {
                              isTemplate = true;
                              break;
                          }
                      }
                      try {
                          if (isCss || isJs || isTemplate) {
                              dependencyService.upsertDependencies(site, childPath);
                          }
                      } catch (ServiceLayerException e) {
                          logger.error("Failed to extract dependencies for: site " + site + " path " + childPath, e);
                      }
                  }
              }
          }
      }
  
      private void addDefaultGroupsForNewSite(String siteId) {
          List<String> defaultGroups = getDefaultGroups();
          for (String group : defaultGroups) {
              String description = group + SITE_DEFAULT_GROUPS_DESCRIPTION;
              try {
                  if (!groupServiceInternal.groupExists(-1, group)) {
  					try {
  						groupServiceInternal.createGroup(DEFAULT_ORGANIZATION_ID, group, description);
  					} catch (GroupAlreadyExistsException e) {
  						throw new IllegalStateException(e);
  					}
  				} else {
                      logger.warn("Default group: " + group + " not created. It already exists.");
                  }
              } catch (ServiceLayerException e) {
                  logger.warn("Error creating group " + group, e);
              }
          }
      }
  
      @Override
      @ValidateParams
      public void createSiteWithRemoteOption(@ValidateStringParam(name = "siteId") String siteId,
                                             @ValidateStringParam(name = "sandboxBranch") String sandboxBranch,
                                             @ValidateNoTagsParam(name = "description") String description,
                                             String blueprintName,
                                             @ValidateStringParam(name = "remoteName") String remoteName,
                                             @ValidateStringParam(name = "remoteUrl") String remoteUrl,
                                             String remoteBranch, boolean singleBranch, String authenticationType,
                                             String remoteUsername, String remotePassword, String remoteToken,
                                             String remotePrivateKey,
                                             @ValidateStringParam(name = "createOption") String createOption,
                                             Map<String, String> params, boolean createAsOrphan)
              throws ServiceLayerException, InvalidRemoteRepositoryException, InvalidRemoteRepositoryCredentialsException,
              RemoteRepositoryNotFoundException, RemoteRepositoryNotBareException, InvalidRemoteUrlException {
          if (exists(siteId)) {
              throw new SiteAlreadyExistsException();
          }
  
          logger.debug("Validate site entitlements");
  		try {
  			entitlementValidator.validateEntitlement(EntitlementType.SITE, 1);
  		} catch (EntitlementException e) {
  			throw new SiteCreationException("Unable to complete request due to entitlement limits. Please contact your "
  				+ "system administrator.", e);
  		}
  
          switch (createOption) {
              case REMOTE_REPOSITORY_CREATE_OPTION_CLONE:
                  logger.info("Clone from remote repository create option selected");
                  createSiteCloneRemote(siteId, sandboxBranch, description, remoteName, remoteUrl, remoteBranch,
                          singleBranch, authenticationType, remoteUsername, remotePassword, remoteToken, remotePrivateKey,
                          params, createAsOrphan);
                  break;
  
              case REMOTE_REPOSITORY_CREATE_OPTION_PUSH:
                  logger.info("Push to remote repository create option selected");
                  createSitePushToRemote(siteId, sandboxBranch, description, blueprintName, remoteName, remoteUrl,
                          remoteBranch, authenticationType, remoteUsername, remotePassword, remoteToken,
                          remotePrivateKey, params, createAsOrphan);
                  break;
  
              default:
                  logger.error("Invalid create option for create site using remote repository: " + createOption +
                          "\nAvailable options: [" + REMOTE_REPOSITORY_CREATE_OPTION_CLONE + ", " +
                          REMOTE_REPOSITORY_CREATE_OPTION_PUSH + "]");
                  break;
          }
      }
  
      @SuppressWarnings("deprecation")
      private void createSiteCloneRemote(String siteId, String sandboxBranch, String description, String remoteName,
                                         String remoteUrl, String remoteBranch, boolean singleBranch,
                                         String authenticationType, String remoteUsername, String remotePassword,
                                         String remoteToken, String remotePrivateKey, Map<String, String> params,
                                         boolean createAsOrphan)
              throws ServiceLayerException, InvalidRemoteRepositoryException, InvalidRemoteRepositoryCredentialsException,
              RemoteRepositoryNotFoundException, InvalidRemoteUrlException {
          boolean success = true;
  
          // We must fail site creation if any of the site creations steps fail and rollback
          // For example: Create site => create Deployer Target (fail) = fail
          // and rollback the whole thing.
          // What we need to do for site creation and the order of execution:
          // 1) git repo, 2) deployer target, 3) database, 4) kick deployer
          String siteUuid = UUID.randomUUID().toString();
  
          try {
              // create site by cloning remote git repo
              logger.info("Creating site " + siteId + " by cloning remote repository " + remoteName +
                  " (" + remoteUrl + ")");
              success = contentRepository.createSiteCloneRemote(siteId, sandboxBranch, remoteName, remoteUrl,
                  remoteBranch, singleBranch, authenticationType, remoteUsername, remotePassword, remoteToken,
                  remotePrivateKey, params, createAsOrphan);
  
          } catch (InvalidRemoteRepositoryException | InvalidRemoteRepositoryCredentialsException |
              RemoteRepositoryNotFoundException | InvalidRemoteUrlException | ServiceLayerException e) {
  
              contentRepository.deleteSite(siteId);
  
              logger.error("Error while creating site: " + siteId + " ID: " + siteId + " as clone from " +
                  "remote repository: " + remoteName + " (" + remoteUrl + "). Rolling back.", e);
  
              throw e;
          }
  
          // try to get the search engine from the blueprint descriptor file
          String searchEngine = studioConfiguration.getProperty(StudioConfiguration.PREVIEW_SEARCH_ENGINE);
  
          PluginDescriptor descriptor = sitesServiceInternal.getSiteBlueprintDescriptor(siteId);
          if (Objects.nonNull(descriptor) && Objects.nonNull(descriptor.getPlugin())) {
              searchEngine = descriptor.getPlugin().getSearchEngine();
              logger.info("Using search engine {0} from plugin descriptor", searchEngine);
          } else if (Objects.nonNull(descriptor) && Objects.nonNull(descriptor.getBlueprint())) {
              searchEngine = descriptor.getBlueprint().getSearchEngine();
              logger.info("Using search engine {0} from blueprint descriptor", searchEngine);
          } else {
              logger.info("Missing descriptor, using default search engine {0}", searchEngine);
          }
  
          if (success) {
              // Create the site in the preview deployer
              try {
                  logger.info("Creating Deployer targets for site " + siteId);
                  deployer.createTargets(siteId, searchEngine);
              } catch (Exception e) {
                  logger.error("Error while creating site: " + siteId + " ID: " + siteId + " as clone from" +
                               " remote repository: " + remoteName + " (" + remoteUrl + "). Rolling back...", e);
  
                  contentRepository.removeRemote(siteId, remoteName);
                  boolean deleted = contentRepository.deleteSite(siteId);
  
                  if (!deleted) {
                      logger.error("Error while rolling back site: " + siteId);
                  }
  
                  throw new DeployerTargetException("Error while creating site: " + siteId + " ID: " + siteId +
                                                    " as clone from remote repository: " + remoteName +
                                                    " (" + remoteUrl + "). The required Deployer targets couldn't " +
                                                    "be created", e);
              }
          }
  
          if (success) {
              try {
                  logger.debug("Adding site UUID.");
                  addSiteUuidFile(siteId, siteUuid);
  
                  // insert database records
                  logger.info("Adding site record to database for site " + siteId);
                  SiteFeed siteFeed = new SiteFeed();
                  siteFeed.setName(siteId);
                  siteFeed.setSiteId(siteId);
                  siteFeed.setSiteUuid(siteUuid);
                  siteFeed.setDescription(description);
                  siteFeed.setPublishingStatusMessage(
                          studioConfiguration.getProperty(JOB_DEPLOY_CONTENT_TO_ENVIRONMENT_STATUS_MESSAGE_DEFAULT));
                  siteFeed.setSandboxBranch(sandboxBranch);
                  siteFeed.setSearchEngine(searchEngine);
                  siteFeedMapper.createSite(siteFeed);
  
                  upgradeManager.upgradeSite(siteId);
  
                  insertCreateSiteAuditLog(siteId, siteId);
  
                  // Add default groups
                  logger.info("Adding default groups for site " + siteId);
                  addDefaultGroupsForNewSite(siteId);
  
                  logger.info("Loading configuration for site " + siteId);
                  reloadSiteConfiguration(siteId);
  
                  logger.info("Sync database with repository for site " + siteId);
                  syncDatabaseWithRepo(siteId, contentRepository.getRepoFirstCommitId(siteId), true);
  
                  // initial deployment
                  logger.info("Executing initial deployement for site " + siteId);
                  List<PublishingTargetTO> publishingTargets = getPublishingTargetsForSite(siteId);
                  if (publishingTargets != null && publishingTargets.size() > 0) {
                      for (PublishingTargetTO target : publishingTargets) {
                          if (StringUtils.isNotEmpty(target.getRepoBranchName())) {
                              contentRepository.initialPublish(siteId, sandboxBranch, target.getRepoBranchName(),
                                      securityService.getCurrentUser(), "Create site.");
                          }
                      }
                  }
                  objectStateService.setStateForSiteContent(siteId, State.EXISTING_UNEDITED_UNLOCKED);
              } catch(Exception e) {
                  success = false;
                  logger.error("Error while creating site: " + siteId + " ID: " + siteId + " as clone from " +
                          "remote repository: " + remoteName + " (" + remoteUrl + "). Rolling back.", e);
  
                  deleteSite(siteId);
  
                  throw new SiteCreationException("Error while creating site: " + siteId + " ID: " + siteId +
                          " as clone from remote repository: " + remoteName + " (" + remoteUrl + "). Rolling back.");
              }
          }
  
          if (success) {
              // Now that everything is created, we can sync the preview deployer with the new content
              logger.info("Sync all site content to preview for " + siteId);
              try {
                  deploymentService.syncAllContentToPreview(siteId, true);
              } catch (ServiceLayerException e) {
                  logger.error("Error while syncing site: " + siteId + " ID: " + siteId + " to preview. Site was "
                      + "successfully created otherwise. Ignoring.", e);
  
                  throw new SiteCreationException("Error while syncing site: " + siteId + " ID: " + siteId +
                      " to preview. Site was successfully created, but it won't be preview-able until the " +
                      "Preview Deployer is reachable.");
              }
          } else {
              throw new SiteCreationException("Error while creating site: " + siteId + " ID: " + siteId + ".");
          }
          logger.info("Finished creating site " + siteId);
      }
  
      private void createSitePushToRemote(String siteId, String sandboxBranch, String description, String blueprintId,
                                          String remoteName, String remoteUrl, String remoteBranch,
                                          String authenticationType, String remoteUsername, String remotePassword,
                                          String remoteToken, String remotePrivateKey, Map<String, String> params,
                                          boolean createAsOrphan)
              throws ServiceLayerException {
          if (exists(siteId)) {
              throw new SiteAlreadyExistsException();
          }
  
          logger.debug("Get blueprint descriptor for " + blueprintId);
          PluginDescriptor descriptor = sitesServiceInternal.getBlueprintDescriptor(blueprintId);
          if (Objects.isNull(descriptor)) {
              throw new BlueprintNotFoundException();
          }
  
          logger.debug("Validate blueprint parameters");
          sitesServiceInternal.validateBlueprintParameters(descriptor, params);
          String blueprintLocation = sitesServiceInternal.getBlueprintLocation(blueprintId);
          String searchEngine = descriptor.getPlugin().getSearchEngine();
  
          boolean success = true;
  
          // We must fail site creation if any of the site creations steps fail and rollback
          // For example: Create site => create Deployer Target (fail) = fail
          // and rollback the whole thing.
          // What we need to do for site creation and the order of execution:
          // 1) deployer target, 2) git repo, 3) database, 4) kick deployer
          String siteUuid = UUID.randomUUID().toString();
  
          logger.info("Starting site creation process for site " + siteId + " from " + blueprintId + " blueprint.");
          // Create the site in the preview deployer
          try {
              logger.info("Creating Deployer targets for site " + siteId);
              deployer.createTargets(siteId, searchEngine);
          } catch (RestServiceException e) {
              String msg = "Error while creating site: " + siteId + " ID: " + siteId + " from blueprint: " +
                           blueprintId + ". The required Deployer targets couldn't be created";
  
              logger.error(msg, e);
  
              throw new DeployerTargetException(msg, e);
          }
  
          if (success) {
              try {
                  logger.info("Creating site " + siteId + " from blueprint " + blueprintId);
                  success = createSiteFromBlueprintGit(blueprintLocation, siteId, siteId, sandboxBranch, description,
                          params);
  
                  addSiteUuidFile(siteId, siteUuid);
  
                  // insert database records
                  logger.info("Adding site record to database for site " + siteId);
                  SiteFeed siteFeed = new SiteFeed();
                  siteFeed.setName(siteId);
                  siteFeed.setSiteId(siteId);
                  siteFeed.setSiteUuid(siteUuid);
                  siteFeed.setDescription(description);
                  siteFeed.setPublishingStatusMessage(
                          studioConfiguration.getProperty(JOB_DEPLOY_CONTENT_TO_ENVIRONMENT_STATUS_MESSAGE_DEFAULT));
                  siteFeed.setSandboxBranch(sandboxBranch);
                  siteFeed.setSearchEngine(searchEngine);
                  siteFeedMapper.createSite(siteFeed);
  
                  logger.info("Upgrading site");
                  upgradeManager.upgradeSite(siteId);
              } catch (Exception e) {
                  success = false;
                  logger.error("Error while creating site: " + siteId + " ID: " + siteId + " from blueprint: " +
                               blueprintId + ". Rolling back...", e);
  
                  contentRepository.deleteSite(siteId);
  
                  try {
                      deployer.deleteTargets(siteId);
                  } catch (Exception ex) {
                      logger.error("Error while rolling back/deleting site: " + siteId + " ID: " + siteId +
                                   " from blueprint: " + blueprintId + ". This means the site's Deployer " +
                                   "targets are still present, but the site was not successfully created", e);
                  }
  
                  throw new SiteCreationException("Error while creating site: " + siteId + " ID: " + siteId +
                                                  " from blueprint: " + blueprintId, e);
              }
  
              if (success) {
                  try {
  
                      logger.info("Pushing site " + siteId + " to remote repository " + remoteName + " (" +
                              remoteUrl + ")");
                      contentRepository.addRemote(siteId, remoteName, remoteUrl, authenticationType, remoteUsername,
                              remotePassword, remoteToken, remotePrivateKey);
                      contentRepository.createSitePushToRemote(siteId, remoteName, remoteUrl, authenticationType,
                              remoteUsername, remotePassword, remoteToken, remotePrivateKey, createAsOrphan);
                  } catch (RemoteRepositoryNotFoundException | InvalidRemoteRepositoryException |
                          InvalidRemoteRepositoryCredentialsException | RemoteRepositoryNotBareException |
                          InvalidRemoteUrlException | ServiceLayerException e) {
                      logger.error("Error while pushing site: " + siteId + " ID: " + siteId + " to remote repository "
                              + remoteName + " (" + remoteUrl + ")", e);
                      contentRepository.removeRemote(siteId, remoteName);
                  }
  
              try {
  
                      logger.debug("Adding audit logs.");
                      insertCreateSiteAuditLog(siteId, siteId);
                      insertAddRemoteAuditLog(siteId, remoteName);
  
                      // Add default groups
                      logger.info("Adding default groups for site " + siteId);
                      addDefaultGroupsForNewSite(siteId);
  
                      logger.info("Loading configuration for site " + siteId);
                      reloadSiteConfiguration(siteId);
  
                      logger.info("Sync database with repository for site " + siteId);
                      syncDatabaseWithRepo(siteId, contentRepository.getRepoFirstCommitId(siteId), true);
  
                      // initial deployment
                      logger.info("Executing initial deployement for site " + siteId);
                      List<PublishingTargetTO> publishingTargets = getPublishingTargetsForSite(siteId);
                      if (publishingTargets != null && publishingTargets.size() > 0) {
                          for (PublishingTargetTO target : publishingTargets) {
                              if (StringUtils.isNotEmpty(target.getRepoBranchName())) {
                                  contentRepository.initialPublish(siteId, sandboxBranch, target.getRepoBranchName(),
                                          securityService.getCurrentUser(), "Create site.");
                              }
                          }
                      }
  
                      objectStateService.setStateForSiteContent(siteId, State.EXISTING_UNEDITED_UNLOCKED);
                  } catch (Exception e) {
                      success = false;
                      logger.error("Error while creating site: " + siteId + " ID: " + siteId + " from blueprint: " +
                              blueprintId + ". Rolling back.", e);
  
                      deleteSite(siteId);
  
                      throw new SiteCreationException("Error while creating site: " + siteId + " ID: " + siteId +
                              " from blueprint: " + blueprintId + ". Rolling back.");
                  }
              }
          }
  
          if (success) {
              // Now that everything is created, we can sync the preview deployer with the new content
              logger.info("Sync all content to preview for site " + siteId);
              try {
                  deploymentService.syncAllContentToPreview(siteId, true);
              } catch (ServiceLayerException e) {
                  logger.error("Error while syncing site: " + siteId + " ID: " + siteId + " to preview. Site was "
                          + "successfully created otherwise. Ignoring.", e);
  
                  throw new SiteCreationException("Error while syncing site: " + siteId + " ID: " + siteId +
                          " to preview. Site was successfully created, but it won't be preview-able until the " +
                          "Preview Deployer is reachable.");
              }
          } else {
              throw new SiteCreationException("Error while creating site: " + siteId + " ID: " + siteId + ".");
          }
          logger.info("Finished creating site " + siteId);
      }
  
      @Override
      @ValidateParams
     	public boolean deleteSite(@ValidateStringParam(name = "siteId") String siteId) {
   		boolean success = true;
          logger.debug("Deleting site:" + siteId);
          try {
              enablePublishing(siteId, false);
          } catch (SiteNotFoundException e) {
              success = false;
              logger.error("Failed to stop publishing for site:" + siteId, e);
          }
  
  		try {
  		    logger.debug("Deleting Deployer targets");
  
  		    deployer.deleteTargets(siteId);
          } catch(Exception e) {
  			success = false;
  			logger.error("Failed to delete the Deployer target for sites:" + siteId, e);
  		}
  
  		try {
              success = success && destroySitePreviewContext(siteId);
          } catch(Exception e) {
              success = false;
              logger.error("Failed to destroy the preview context for site:" + siteId, e);
          }
  
  		try {
  		    logger.debug("Deleting repo");
  		    contentRepository.deleteSite(siteId);
  		} catch(Exception e) {
  			success = false;
  			logger.error("Failed to delete the repository for site:" + siteId, e);
  		}
  
  	    try {
  		    // delete database records
  		    logger.debug("Deleting database records");
  		    SiteFeed siteFeed = getSite(siteId);
  			siteFeedMapper.deleteSite(siteId);
  			dependencyService.deleteSiteDependencies(siteId);
  	        deploymentService.deleteDeploymentDataForSite(siteId);
  	        objectStateService.deleteObjectStatesForSite(siteId);
  	        objectMetadataManager.deleteObjectMetadataForSite(siteId);
  	        dmPageNavigationOrderService.deleteSequencesForSite(siteId);
  	        contentRepository.deleteGitLogForSite(siteId);
  	        contentRepository.removeRemoteRepositoriesForSite(siteId);
  	        insertDeleteSiteAuditLog(siteId, siteFeed.getName());
  	    } catch(Exception e) {
  		    success = false;
  		    logger.error("Failed to delete the database for site:" + siteId, e);
  	    }
  
  	 	return success;
      }
  
      private void insertDeleteSiteAuditLog(String siteId, String siteName) throws SiteNotFoundException {
  	    SiteFeed siteFeed = getSite(studioConfiguration.getProperty(CONFIGURATION_GLOBAL_SYSTEM_SITE));
          String user = securityService.getCurrentUser();
          AuditLog auditLog = auditServiceInternal.createAuditLogEntry();
          auditLog.setOperation(OPERATION_DELETE);
          auditLog.setSiteId(siteFeed.getId());
          auditLog.setActorId(user);
          auditLog.setPrimaryTargetId(siteId);
          auditLog.setPrimaryTargetType(TARGET_TYPE_SITE);
          auditLog.setPrimaryTargetValue(siteName);
          auditServiceInternal.insertAuditLog(auditLog);
      }
  
      private boolean destroySitePreviewContext(String site) {
          boolean toReturn = true;
          String requestUrl = getDestroySitePreviewContextUrl(site);
  
          HttpGet getRequest = new HttpGet(requestUrl);
  		RequestConfig requestConfig = RequestConfig.custom().setExpectContinueEnabled(true).build();
  		getRequest.setConfig(requestConfig);
  
          CloseableHttpClient client = HttpClientBuilder.create().build();
          try {
              CloseableHttpResponse response = client.execute(getRequest);
              if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                  toReturn = false;
              }
          } catch (IOException e) {
              logger.error("Error while sending destroy preview context request for site " + site, e);
              toReturn = false;
          } finally {
              getRequest.releaseConnection();
          }
          return toReturn;
      }
  
      private String getDestroySitePreviewContextUrl(String site) {
          String url = studioConfiguration.getProperty(CONFIGURATION_SITE_PREVIEW_DESTROY_CONTEXT_URL);
          url = url.replaceAll(StudioConstants.CONFIG_SITENAME_VARIABLE, site);
          return url;
      }
  
      @Override
  	public SiteBlueprintTO[] getAvailableBlueprints() {
  		RepositoryItem[] blueprintsFolders =
                  contentRepository.getContentChildren("", studioConfiguration.getProperty(BLUE_PRINTS_PATH));
  		List<SiteBlueprintTO> blueprints = new ArrayList<SiteBlueprintTO>();
  		int idx = 0;
  		for (RepositoryItem folder : blueprintsFolders) {
  		    if (folder.isFolder) {
                  SiteBlueprintTO blueprintTO = new SiteBlueprintTO();
                  blueprintTO.id = folder.name;
                  blueprintTO.label = StringUtils.capitalize(folder.name);
                  blueprintTO.description = ""; // How do we populate this dynamicly
                  blueprintTO.screenshots = null;
                  blueprints.add(blueprintTO);
              }
  		}
  
  		return blueprints.toArray(new SiteBlueprintTO[blueprints.size()]);
  	}
  
      @Override
      @ValidateParams
      public String getPreviewServerUrl(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getPreviewServerUrl(site);
      }
  
      @Override
      @ValidateParams
      public String getPreviewEngineServerUrl(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getPreviewEngineServerUrl(site);
      }
  
      @Override
      @ValidateParams
      public String getGraphqlServerUrl(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getGraphqlServerUrl(site);
      }
  
      @Override
      @ValidateParams
      public String getLiveServerUrl(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getLiveServerUrl(site);
      }
  
      @Override
      @ValidateParams
      public String getAuthoringServerUrl(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getAuthoringServerUrl(site);
      }
  
      @Override
      @ValidateParams
      public String getAdminEmailAddress(@ValidateStringParam(name = "site") String site) {
          return environmentConfig.getAdminEmailAddress(site);
      }
  
  
      @Override
      public void reloadSiteConfigurations() {
          reloadGlobalConfiguration();
          Set<String> sites = getAllAvailableSites();
      }
  
      @Override
      @ValidateParams
      public void reloadSiteConfiguration(@ValidateStringParam(name = "site") String site) {
          reloadSiteConfiguration(site, true);
      }
  
      @Override
      public void reloadSiteConfiguration(String site, boolean triggerEvent) {
          SiteTO siteConfig = new SiteTO();
          siteConfig.setSite(site);
          siteConfig.setEnvironment(getEnvironment());
          servicesConfig.reloadConfiguration(site);
          environmentConfig.reloadConfiguration(site);
          loadSiteEnvironmentConfig(site, siteConfig);
  		notificationService.reloadConfiguration(site);
          securityService.reloadConfiguration(site);
          contentTypeService.reloadConfiguration(site);
      }
  
      @Override
      public void reloadGlobalConfiguration() {
          securityService.reloadGlobalConfiguration();
      }
  
      @Override
      @ValidateParams
      public void syncRepository(@ValidateStringParam(name = "site") String site) throws SiteNotFoundException {
  		if (!exists(site)) {
  			throw new SiteNotFoundException();
  		} else {
  			Map<String, Object> params = new HashMap<String, Object>();
  			params.put("siteId", site);
  			String lastDbCommitId = siteFeedMapper.getLastCommitId(params);
  			if (lastDbCommitId != null) {
                  syncDatabaseWithRepository.execute(site, lastDbCommitId);
  			} else {
  				rebuildDatabase(site);
  			}
  		}
      }
  
      @Override
      @ValidateParams
      public void rebuildDatabase(@ValidateStringParam(name = "site") String site) {
          rebuildRepositoryMetadata.execute(site);
      }
  
      @Override
      @ValidateParams
      public void updateLastCommitId(@ValidateStringParam(name = "site") String site,
                                     @ValidateStringParam(name = "commitId") String commitId) {
          Map<String, Object> params = new HashMap<String, Object>();
          params.put("siteId", site);
          params.put("lastCommitId", commitId);
          siteFeedMapper.updateLastCommitId(params);
      }
  
      private void updateLastVerifiedGitlogCommitId(String site, String commitId) {
          Map<String, Object> params = new HashMap<String, Object>();
          params.put("siteId", site);
          params.put("commitId", commitId);
          siteFeedMapper.updateLastVerifiedGitlogCommitId(params);
      }
  
      @Override
      @ValidateParams
      public boolean syncDatabaseWithRepo(@ValidateStringParam(name = "site") String site,
                                          @ValidateStringParam(name = "fromCommitId") String fromCommitId)
              throws SiteNotFoundException {
          return syncDatabaseWithRepo(site, fromCommitId, true);
      }
  
      @Override
      @ValidateParams
      public boolean syncDatabaseWithRepo(@ValidateStringParam(name = "site") String site,
                                          @ValidateStringParam(name = "fromCommitId") String fromCommitId,
                                          boolean generateAuditLog) throws SiteNotFoundException {
  		boolean toReturn = true;
          String repoLastCommitId = contentRepository.getRepoLastCommitId(site);
          List<RepoOperationTO> repoOperations = contentRepository.getOperations(site, fromCommitId, repoLastCommitId);
          if (CollectionUtils.isEmpty(repoOperations)) {
              logger.debug("Database is up to date with repository for site: " + site);
              contentRepository.markGitLogVerifiedProcessed(site, fromCommitId);
              return toReturn;
          }
  
          logger.info("Syncing database with repository for site: " + site + " fromCommitId = " +
                  (StringUtils.isEmpty(fromCommitId) ? "Empty repo" : fromCommitId));
          logger.debug("Operations to sync: ");
  	    for (RepoOperationTO repoOperation: repoOperations) {
  	    	logger.debug("\tOperation: " + repoOperation.getOperation().toString() + " " + repoOperation.getPath());
  	    }
  
  	    boolean diverged = false;
  	    GitLog current = null;
  	    SiteFeed siteFeed = getSite(site);
  	    boolean isPreviewSyncNeeded = !StringUtils.equals(repoLastCommitId, siteFeed.getLastCommitId());
  
  	    // Process all operations and track if one or more have failed
  