/* * Copyright 2016 ThoughtWorks, Inc. * * Licensed 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.thoughtworks.go.server.materials; import com.thoughtworks.go.config.GoRepoConfigDataSource; import com.thoughtworks.go.config.materials.SubprocessExecutionContext; import com.thoughtworks.go.domain.MaterialRevision; import com.thoughtworks.go.domain.MaterialRevisions; import com.thoughtworks.go.domain.materials.Material; import com.thoughtworks.go.domain.materials.Revision; import com.thoughtworks.go.server.messaging.GoMessageListener; import com.thoughtworks.go.server.persistence.MaterialRepository; import com.thoughtworks.go.server.service.MaterialService; import com.thoughtworks.go.server.service.materials.MaterialPoller; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.File; import static java.lang.String.format; /** * Updates configuration from repositories. */ @Service public class ConfigMaterialUpdater implements GoMessageListener<MaterialUpdateCompletedMessage> { private static final Logger LOGGER = Logger.getLogger(ConfigMaterialUpdater.class); private GoRepoConfigDataSource repoConfigDataSource; private MaterialRepository materialRepository; private MaterialChecker materialChecker; private ConfigMaterialUpdateCompletedTopic configCompleted; private MaterialUpdateCompletedTopic topic; private MaterialService materialService; private SubprocessExecutionContext subprocessExecutionContext; @Autowired public ConfigMaterialUpdater(GoRepoConfigDataSource repoConfigDataSource, MaterialRepository materialRepository, MaterialChecker materialChecker, ConfigMaterialUpdateCompletedTopic configCompletedTopic, MaterialUpdateCompletedTopic topic, MaterialService materialService, SubprocessExecutionContext subprocessExecutionContext) { this.repoConfigDataSource = repoConfigDataSource; this.materialChecker = materialChecker; this.materialRepository = materialRepository; this.configCompleted = configCompletedTopic; this.topic = topic; this.materialService = materialService; this.subprocessExecutionContext = subprocessExecutionContext; this.configCompleted.addListener(this); } @Override public void onMessage(MaterialUpdateCompletedMessage message) { Material material = message.getMaterial(); //MDU is done using the checkout, it has done db update and stored latest changes // but MUS is still waiting for material updated message on MaterialUpdateCompletedTopic if (LOGGER.isDebugEnabled()) { LOGGER.debug(format("[Config Material Update] Config material update completed for material %s. Starting parse process", material)); } try { if(message instanceof MaterialUpdateFailedMessage) { MaterialUpdateFailedMessage failure = (MaterialUpdateFailedMessage)message; LOGGER.warn(String.format("[Config Material Update] Cannot update configuration part because material update has failed. Reason: %s", failure.getReason())); } else { File folder = materialRepository.folderFor(material); MaterialRevisions latestModification = materialRepository.findLatestModification(material); Revision revision = latestModification.firstModifiedMaterialRevision().getRevision(); MaterialRevision lastParseRevision = getMaterialRevisionAtLastParseAttempt(message); if (lastParseRevision == null) { //never parsed updateConfigurationFromCheckout(folder, revision, material); } else if (latestModification.findRevisionFor(material.config()) .hasChangedSince(lastParseRevision)) { // revision has changed. the config files might have been updated updateConfigurationFromCheckout(folder, revision, material); } else { // revision is the same as last time, no need to parse again } } } finally { // always post the original message further // this will remove material from inProgress in MUS topic.post(message); } } private void updateConfigurationFromCheckout(File folder, Revision revision, Material material) { MaterialPoller poller = this.materialService.getPollerImplementation(material); poller.checkout(material,folder, revision,this.subprocessExecutionContext); this.repoConfigDataSource.onCheckoutComplete(material.config(),folder, revision.getRevision()); } private MaterialRevision getMaterialRevisionAtLastParseAttempt(MaterialUpdateCompletedMessage message) { MaterialRevision lastParseRevision; try { String materialRevisionAtLastAttempt = repoConfigDataSource.getRevisionAtLastAttempt(message.getMaterial().config()); if(materialRevisionAtLastAttempt == null) return null; lastParseRevision = materialChecker.findSpecificRevision(message.getMaterial(), materialRevisionAtLastAttempt); } catch (Exception ex) { LOGGER.error(String.format("[Config Material Update] failed to get last parsed material revision. Reason: %s", ex.getMessage())); lastParseRevision = null; } return lastParseRevision; } }