/**
* 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 org.apache.falcon.state.store.jdbc;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.apache.falcon.FalconException;
import org.apache.falcon.entity.EntityUtil;
import org.apache.falcon.entity.v0.Entity;
import org.apache.falcon.entity.v0.EntityType;
import org.apache.falcon.exception.StateStoreException;
import org.apache.falcon.execution.ExecutionInstance;
import org.apache.falcon.execution.ProcessExecutionInstance;
import org.apache.falcon.persistence.EntityBean;
import org.apache.falcon.persistence.InstanceBean;
import org.apache.falcon.predicate.Predicate;
import org.apache.falcon.state.EntityID;
import org.apache.falcon.state.EntityState;
import org.apache.falcon.state.InstanceID;
import org.apache.falcon.state.InstanceState;
import org.joda.time.DateTime;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
/**
* Mapping util for Persistent Store.
*/
public final class BeanMapperUtil {
private BeanMapperUtil() {
}
/**
* Converts Entity object to EntityBean which will be stored in DB.
* @param entityState
* @return
*/
public static EntityBean convertToEntityBean(EntityState entityState) throws IOException {
EntityBean entityBean = new EntityBean();
Entity entity = entityState.getEntity();
String id = new EntityID(entity).getKey();
entityBean.setId(id);
entityBean.setName(entity.getName());
entityBean.setState(entityState.getCurrentState().toString());
entityBean.setType(entity.getEntityType().toString());
if (entityState.getProperties() != null && !entityState.getProperties().isEmpty()) {
byte[] props = getProperties(entityState);
entityBean.setProperties(props);
}
return entityBean;
}
/**
* Converts EntityBean of Data Base to EntityState.
* @param entityBean
* @return
* @throws StateStoreException
*/
public static EntityState convertToEntityState(EntityBean entityBean) throws StateStoreException, IOException {
try {
Entity entity = EntityUtil.getEntity(entityBean.getType(), entityBean.getName());
EntityState entityState = new EntityState(entity);
entityState.setCurrentState(EntityState.STATE.valueOf(entityBean.getState()));
byte[] result = entityBean.getProperties();
if (result != null && result.length != 0) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(result);
ObjectInputStream in = null;
Properties properties = null;
try {
in = new ObjectInputStream(byteArrayInputStream);
properties = (Properties) in.readObject();
} catch (ClassNotFoundException e) {
throw new IOException(e);
} finally {
IOUtils.closeQuietly(in);
}
entityState.setProperties(properties);
}
return entityState;
} catch (FalconException e) {
throw new StateStoreException(e);
}
}
/**
* Converts list of EntityBeans of Data Base to EntityStates.
* @param entityBeans
* @return
* @throws StateStoreException
*/
public static Collection<EntityState> convertToEntityState(Collection<EntityBean> entityBeans)
throws StateStoreException, IOException {
List<EntityState> entityStates = new ArrayList<>();
if (entityBeans != null && !entityBeans.isEmpty()) {
for (EntityBean entityBean : entityBeans) {
entityStates.add(convertToEntityState(entityBean));
}
}
return entityStates;
}
/**
* Converts list of EntityBeans of Data Base to Entities.
* @param entityBeans
* @return
* @throws StateStoreException
*/
public static Collection<Entity> convertToEntities(Collection<EntityBean> entityBeans) throws StateStoreException {
List<Entity> entities = new ArrayList<>();
try {
if (entityBeans != null && !entityBeans.isEmpty()) {
for (EntityBean entityBean : entityBeans) {
Entity entity = EntityUtil.getEntity(entityBean.getType(), entityBean.getName());
entities.add(entity);
}
}
return entities;
} catch (FalconException e) {
throw new StateStoreException(e);
}
}
/**
* Convert instance of Entity's instance to InstanceBean of DB.
* @param instanceState
* @return
* @throws StateStoreException
* @throws IOException
*/
public static InstanceBean convertToInstanceBean(InstanceState instanceState) throws StateStoreException,
IOException {
InstanceBean instanceBean = new InstanceBean();
ExecutionInstance instance = instanceState.getInstance();
if (instance.getActualEnd() != null) {
instanceBean.setActualEndTime(new Timestamp(instance.getActualEnd().getMillis()));
}
if (instance.getActualStart() != null) {
instanceBean.setActualStartTime(new Timestamp(instance.getActualStart().getMillis()));
}
if (instanceState.getCurrentState() != null) {
instanceBean.setCurrentState(instanceState.getCurrentState().toString());
}
if (instance.getExternalID() != null) {
instanceBean.setExternalID(instanceState.getInstance().getExternalID());
}
instanceBean.setCluster(instance.getCluster());
instanceBean.setCreationTime(new Timestamp(instance.getCreationTime().getMillis()));
instanceBean.setId(instance.getId().toString());
instanceBean.setInstanceTime(new Timestamp(instance.getInstanceTime().getMillis()));
instanceBean.setEntityId(new InstanceID(instance).getEntityID().toString());
instanceBean.setInstanceSequence(instance.getInstanceSequence());
if (instance.getAwaitingPredicates() != null && !instance.getAwaitingPredicates().isEmpty()) {
ObjectOutputStream out = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
out = new ObjectOutputStream(byteArrayOutputStream);
out.writeInt(instance.getAwaitingPredicates().size());
for (Predicate predicate : instance.getAwaitingPredicates()) {
out.writeObject(predicate);
}
instanceBean.setAwaitedPredicates(byteArrayOutputStream.toByteArray());
} finally {
IOUtils.closeQuietly(out);
}
}
if (instance.getProperties() != null && !instance.getProperties().isEmpty()) {
byte[] props = getProperties(instanceState);
instanceBean.setProperties(props);
}
return instanceBean;
}
/**
* Converts instance entry of DB to instance of ExecutionInstance.
* @param instanceBean
* @return
* @throws StateStoreException
* @throws IOException
*/
public static InstanceState convertToInstanceState(InstanceBean instanceBean) throws StateStoreException,
IOException {
EntityType entityType = InstanceID.getEntityType(instanceBean.getId());
ExecutionInstance executionInstance = getExecutionInstance(entityType, instanceBean);
if (instanceBean.getActualEndTime() != null) {
executionInstance.setActualEnd(new DateTime(instanceBean.getActualEndTime().getTime()));
}
if (instanceBean.getActualStartTime() != null) {
executionInstance.setActualStart(new DateTime(instanceBean.getActualStartTime().getTime()));
}
executionInstance.setExternalID(instanceBean.getExternalID());
executionInstance.setInstanceSequence(instanceBean.getInstanceSequence());
byte[] result = instanceBean.getAwaitedPredicates();
List<Predicate> predicates = new ArrayList<>();
if (result != null && result.length != 0) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(result);
ObjectInputStream in = null;
try {
in = new ObjectInputStream(byteArrayInputStream);
int length = in.readInt();
for (int i = 0; i < length; i++) {
Predicate predicate = (Predicate) in.readObject();
predicates.add(predicate);
}
} catch (ClassNotFoundException e) {
throw new IOException(e);
} finally {
IOUtils.closeQuietly(in);
}
}
executionInstance.setAwaitingPredicates(predicates);
result = instanceBean.getProperties();
if (result != null && result.length != 0) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(result);
ObjectInputStream in = null;
Properties properties = null;
try {
in = new ObjectInputStream(byteArrayInputStream);
properties = (Properties) in.readObject();
} catch (ClassNotFoundException e) {
throw new IOException(e);
} finally {
IOUtils.closeQuietly(in);
}
executionInstance.setProperties(properties);
}
InstanceState instanceState = new InstanceState(executionInstance);
instanceState.setCurrentState(InstanceState.STATE.valueOf(instanceBean.getCurrentState()));
return instanceState;
}
/**
* Converting list of instance entries of DB to instance of ExecutionInstance.
* @param instanceBeanList
* @return
* @throws StateStoreException
* @throws IOException
*/
public static Collection<InstanceState> convertToInstanceState(List<InstanceBean> instanceBeanList)
throws StateStoreException, IOException {
List<InstanceState> instanceStates = new ArrayList<>();
for (InstanceBean instanceBean : instanceBeanList) {
instanceStates.add(convertToInstanceState(instanceBean));
}
return instanceStates;
}
private static ExecutionInstance getExecutionInstance(EntityType entityType,
InstanceBean instanceBean) throws StateStoreException {
try {
Entity entity = EntityUtil.getEntity(entityType, InstanceID.getEntityName(instanceBean.getId()));
return getExecutionInstance(entityType, entity, instanceBean.getInstanceTime().getTime(),
instanceBean.getCluster(), instanceBean.getCreationTime().getTime());
} catch (FalconException e) {
throw new StateStoreException(e);
}
}
public static ExecutionInstance getExecutionInstance(EntityType entityType, Entity entity, long instanceTime,
String cluster, long creationTime) throws StateStoreException {
if (entityType == EntityType.PROCESS) {
try {
return new ProcessExecutionInstance((org.apache.falcon.entity.v0.process.Process) entity,
new DateTime(instanceTime), cluster, new DateTime(creationTime));
} catch (FalconException e) {
throw new StateStoreException("Entity not found");
}
} else {
throw new UnsupportedOperationException("Not supported for entity type " + entityType.toString());
}
}
public static byte[] getAwaitedPredicates(InstanceState instanceState) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(byteArrayOutputStream);
out.writeInt(instanceState.getInstance().getAwaitingPredicates().size());
for (Predicate predicate : instanceState.getInstance().getAwaitingPredicates()) {
out.writeObject(predicate);
}
return byteArrayOutputStream.toByteArray();
} finally {
IOUtils.closeQuietly(out);
}
}
public static byte [] getProperties(InstanceState instanceState) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(byteArrayOutputStream);
out.writeObject(instanceState.getInstance().getProperties());
return byteArrayOutputStream.toByteArray();
} finally {
IOUtils.closeQuietly(out);
}
}
public static byte [] getProperties(EntityState entityState) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream out = null;
try {
out = new ObjectOutputStream(byteArrayOutputStream);
out.writeObject(entityState.getProperties());
return byteArrayOutputStream.toByteArray();
} finally {
IOUtils.closeQuietly(out);
}
}
/**
* @param summary
* @return A map of state and count given the JQL result.
*/
public static Map<InstanceState.STATE, Long> getInstanceStateSummary(Collection<Object[]> summary) {
Map<InstanceState.STATE, Long> stateSummary = new HashMap<>();
if (summary != null && !summary.isEmpty()) {
for (Object[] projection : summary) {
// Has to have 2 columns (state and count), else Array will be out of bounds.
if (projection.length == 2) {
stateSummary.put(InstanceState.STATE.valueOf((String)projection[0]),
Long.valueOf(((Number)projection[1]).longValue()));
}
}
}
return stateSummary;
}
}