/** * Copyright 2011 LiveRamp * <p> * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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.liveramp.hank.storage.incremental; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; import java.util.TreeMap; import com.liveramp.hank.config.InvalidConfigurationException; import com.liveramp.hank.config.yaml.YamlConfigurator; import com.liveramp.hank.coordinator.Domain; import com.liveramp.hank.coordinator.DomainVersion; import com.liveramp.hank.coordinator.DomainVersionProperties; import com.liveramp.hank.coordinator.DomainVersionPropertiesSerialization; import com.liveramp.hank.coordinator.Domains; public class IncrementalDomainVersionProperties implements DomainVersionProperties { private final Integer parentVersion; private final String source; // Static helper classes to create properties objects public static class Base extends IncrementalDomainVersionProperties { public Base() { super(null); } public Base(String source) { super(null, source); } } public static class Delta extends IncrementalDomainVersionProperties { public Delta(int parentVersion) { this(parentVersion, null); } public Delta(int parentVersion, String source) { super(parentVersion, source); } public Delta(Domain domain) throws IOException { this(domain, null); } public Delta(Domain domain, String source) throws IOException { this(Domains.getLatestVersion(domain), source); } public Delta(DomainVersion parentVersion) { this(parentVersion, null); } public Delta(DomainVersion parentVersion, String source) { super(parentVersion == null ? null : parentVersion.getVersionNumber(), source); } } public IncrementalDomainVersionProperties(Integer parentVersion) { this(parentVersion, null); } public IncrementalDomainVersionProperties(Integer parentVersion, String source) { this.parentVersion = parentVersion; this.source = source; } public Integer getParentVersionNumber() { return parentVersion; } public String getSource() { return source; } public boolean isBase() { return getParentVersionNumber() == null; } public static boolean isBase(DomainVersion domainVersion) throws IOException { IncrementalDomainVersionProperties properties = (IncrementalDomainVersionProperties)domainVersion.getProperties(); if (properties == null) { throw new RuntimeException("Given Domain Version properties are null."); } return properties.isBase(); } public static DomainVersion getParentDomainVersion(Domain domain, DomainVersion version) throws IOException { IncrementalDomainVersionProperties properties = (IncrementalDomainVersionProperties)version.getProperties(); if (properties == null) { throw new IOException("Failed to get parent of Domain Version since corresponding properties are empty: " + version); } else { Integer parentVersionNumber = properties.getParentVersionNumber(); if (parentVersionNumber == null) { return null; } else { DomainVersion result = domain.getVersion(parentVersionNumber); if (result == null) { throw new IOException("Failed to get parent Domain Version since specified parent version number (" + parentVersionNumber + ") of version " + version.getVersionNumber() + " of Domain " + domain.getName() + " does not correspond to any version."); } return result; } } } public static class Serialization implements DomainVersionPropertiesSerialization { private static final String PARENT_KEY = "parent"; private static final String SOURCE_KEY = "source"; private static final String SERIALIZATION_CHARSET = "UTF-8"; private static class Configurator extends YamlConfigurator { @Override protected void validate() throws InvalidConfigurationException { this.checkNonEmptyConfiguration(); this.getRequiredInteger(PARENT_KEY); } protected Integer getParentVersionNumber() throws InvalidConfigurationException { return getRequiredInteger(PARENT_KEY); } protected String getSource() { return getOptionalString(SOURCE_KEY); } } @Override public DomainVersionProperties deserializeProperties(byte[] serializedProperties) throws IOException { String yaml; try { yaml = new String(serializedProperties, SERIALIZATION_CHARSET); } catch (UnsupportedEncodingException e) { throw new IOException("Failed to deserialize domain version properties.", e); } Configurator configurator = new Configurator(); try { configurator.loadFromYaml(yaml); return new IncrementalDomainVersionProperties( configurator.getParentVersionNumber(), configurator.getSource()); } catch (InvalidConfigurationException e) { throw new IOException("Failed to deserialize domain version properties.", e); } } @Override public byte[] serializeProperties(DomainVersionProperties propertiesObj) throws IOException { IncrementalDomainVersionProperties properties = (IncrementalDomainVersionProperties)propertiesObj; Configurator configurator = new Configurator(); Map<String, Object> yaml = new TreeMap<String, Object>(); yaml.put(PARENT_KEY, properties.getParentVersionNumber()); if (properties.getSource() != null) { yaml.put(SOURCE_KEY, properties.getSource()); } try { configurator.loadFromObjectMap(yaml); } catch (InvalidConfigurationException e) { throw new IOException("Failed to serialize domain version properties.", e); } return configurator.toYaml().getBytes(SERIALIZATION_CHARSET); } } @Override public String toString() { StringBuilder result = new StringBuilder(); Integer parentVersionNumber = getParentVersionNumber(); String source = getSource(); if (parentVersionNumber == null) { result.append("Base"); } else { result.append("Delta (parent: " + parentVersionNumber + ")"); } if (source != null) { result.append(", Source: "); result.append(source); } return result.toString(); } }