/*
* 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.config.materials;
import com.thoughtworks.go.config.CaseInsensitiveString;
import com.thoughtworks.go.domain.PersistentObject;
import com.thoughtworks.go.domain.materials.Material;
import com.thoughtworks.go.domain.materials.MaterialConfig;
import com.thoughtworks.go.util.CachedDigestUtils;
import com.thoughtworks.go.util.ListUtil;
import com.thoughtworks.go.util.StringUtil;
import java.util.*;
/**
* @understands material configuration
*/
public abstract class AbstractMaterial extends PersistentObject implements Material {
/**
* CAREFUL!, this should be the same as the one used in migration 47_create_new_materials.sql
*/
public static final String FINGERPRINT_DELIMITER = "<|>";
public static final String SQL_CRITERIA_TYPE = "type";
private static final int TRUNCATED_NAME_MAX_LENGTH = 20;
protected CaseInsensitiveString name;
protected String type;
private Map<String, Object> sqlCriteria;
private Map<String, Object> attributesForXml;
private String pipelineUniqueFingerprint;
protected String fingerprint;
public AbstractMaterial(String typeName) {
type = typeName;
}
public CaseInsensitiveString getName() {
return name;
}
public final Map<String, Object> getSqlCriteria() {
if (sqlCriteria == null) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("type", type);
appendCriteria(map);
sqlCriteria = Collections.unmodifiableMap(map);
}
return sqlCriteria;
}
public final Map<String, Object> getAttributesForXml() {
if (attributesForXml == null) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("type", type);
appendAttributes(map);
attributesForXml = Collections.unmodifiableMap(map);
}
return attributesForXml;
}
public String getFingerprint() {
if (fingerprint == null) {
fingerprint = generateFingerprintFromCriteria(getSqlCriteria());
}
return fingerprint;
}
public String getPipelineUniqueFingerprint() {
if (pipelineUniqueFingerprint == null) {
Map<String, Object> basicCriteria = new LinkedHashMap<>(getSqlCriteria());
appendPipelineUniqueCriteria(basicCriteria);
pipelineUniqueFingerprint = generateFingerprintFromCriteria(basicCriteria);
}
return pipelineUniqueFingerprint;
}
private String generateFingerprintFromCriteria(Map<String, Object> sqlCriteria) {
List<String> list = new ArrayList<>();
for (Map.Entry<String, Object> criteria : sqlCriteria.entrySet()) {
list.add(new StringBuilder().append(criteria.getKey()).append("=").append(criteria.getValue()).toString());
}
String fingerprint = ListUtil.join(list, FINGERPRINT_DELIMITER);
// CAREFUL! the hash algorithm has to be same as the one used in 47_create_new_materials.sql
return CachedDigestUtils.sha256Hex(fingerprint);
}
public String getTruncatedDisplayName() {
String displayName = getDisplayName();
if (displayName.length() > TRUNCATED_NAME_MAX_LENGTH) {
StringBuffer buffer = new StringBuffer();
buffer.append(displayName.substring(0, TRUNCATED_NAME_MAX_LENGTH / 2));
buffer.append("...");
buffer.append(displayName.substring(displayName.length() - TRUNCATED_NAME_MAX_LENGTH / 2));
displayName = buffer.toString();
}
return displayName;
}
protected abstract void appendCriteria(Map<String, Object> parameters);
protected abstract void appendAttributes(Map<String,Object> parameters);
protected abstract void appendPipelineUniqueCriteria(Map<String, Object> basicCriteria);
public void setName(final CaseInsensitiveString name) {
this.name = name;
}
public String getType() {
return type;
}
public String getShortRevision(String revision) {
return revision;
}
public boolean isSameFlyweight(Material other) {
return getFingerprint().equals(other.getFingerprint());
}
@Override
public boolean hasSameFingerprint(MaterialConfig materialConfig) {
return getFingerprint().equals(materialConfig.getFingerprint());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AbstractMaterial that = (AbstractMaterial) o;
if (name != null ? !name.equals(that.name) : that.name != null) {
return false;
}
if (type != null ? !type.equals(that.type) : that.type != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (type != null ? type.hashCode() : 0);
return result;
}
@Override public String toString() {
return String.format("AbstractMaterial{name=%s, type=%s}", name, type);
}
protected void resetCachedIdentityAttributes() {
sqlCriteria = null;
attributesForXml = null;
pipelineUniqueFingerprint = null;
}
@Override
public MaterialConfig config() {
throw new RuntimeException("You need to implement this");
}
@Override
public Map<String, Object> getAttributes(boolean addSecureFields) {
throw new RuntimeException("You need to implement this");
}
protected boolean hasDestinationFolder() {
return !StringUtil.isBlank(getFolder());
}
public boolean supportsDestinationFolder() {
return false;
}
@Override
public void updateFromConfig(MaterialConfig materialConfig) {
if(materialConfig instanceof PasswordAwareMaterial) {
PasswordAwareMaterial passwordConfig = (PasswordAwareMaterial) materialConfig;
((PasswordAwareMaterial) this).setPassword(passwordConfig.getPassword());
}
}
}