// Copyright 2011 Google 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.google.appengine.tools.pipeline.impl.model;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.tools.pipeline.impl.PipelineManager;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* A slot to be filled in with a value.
*
* @author rudominer@google.com (Mitch Rudominer)
*/
public class Slot extends PipelineModelObject {
public static final String DATA_STORE_KIND = "pipeline-slot";
private static final String FILLED_PROPERTY = "filled";
private static final String VALUE_PROPERTY = "value";
private static final String WAITING_ON_ME_PROPERTY = "waitingOnMe";
private static final String FILL_TIME_PROPERTY = "fillTime";
private static final String SOURCE_JOB_KEY_PROPERTY = "sourceJob";
// persistent
private boolean filled;
private Date fillTime;
private Object value;
private Key sourceJobKey;
private final List<Key> waitingOnMeKeys;
// transient
private List<Barrier> waitingOnMeInflated;
private Object serializedVersion;
public Slot(Key rootJobKey, Key generatorJobKey, String graphGUID) {
super(rootJobKey, generatorJobKey, graphGUID);
waitingOnMeKeys = new LinkedList<>();
}
public Slot(Entity entity) {
this(entity, false);
}
public Slot(Entity entity, boolean lazy) {
super(entity);
filled = (Boolean) entity.getProperty(FILLED_PROPERTY);
fillTime = (Date) entity.getProperty(FILL_TIME_PROPERTY);
sourceJobKey = (Key) entity.getProperty(SOURCE_JOB_KEY_PROPERTY);
waitingOnMeKeys = getListProperty(WAITING_ON_ME_PROPERTY, entity);
if (lazy) {
serializedVersion = entity.getProperty(VALUE_PROPERTY);
} else {
value = deserializeValue(entity.getProperty(VALUE_PROPERTY));
}
}
private Object deserializeValue(Object serializedValue) {
try {
return PipelineManager.getBackEnd().deserializeValue(this, serializedValue);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public Entity toEntity() {
Entity entity = toProtoEntity();
entity.setUnindexedProperty(FILLED_PROPERTY, filled);
if (null != fillTime) {
entity.setUnindexedProperty(FILL_TIME_PROPERTY, fillTime);
}
if (null != sourceJobKey) {
entity.setProperty(SOURCE_JOB_KEY_PROPERTY, sourceJobKey);
}
entity.setProperty(WAITING_ON_ME_PROPERTY, waitingOnMeKeys);
if (serializedVersion != null) {
entity.setUnindexedProperty(VALUE_PROPERTY, serializedVersion);
} else {
try {
entity.setUnindexedProperty(VALUE_PROPERTY,
PipelineManager.getBackEnd().serializeValue(this, value));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return entity;
}
@Override
protected String getDatastoreKind() {
return DATA_STORE_KIND;
}
public void inflate(Map<Key, Barrier> pool) {
waitingOnMeInflated = buildInflated(waitingOnMeKeys, pool);
}
public void addWaiter(Barrier waiter) {
waitingOnMeKeys.add(waiter.getKey());
if (null == waitingOnMeInflated) {
waitingOnMeInflated = new LinkedList<>();
}
waitingOnMeInflated.add(waiter);
}
public boolean isFilled() {
return filled;
}
public Object getValue() {
if (serializedVersion != null) {
value = deserializeValue(serializedVersion);
serializedVersion = null;
}
return value;
}
/**
* Will return {@code null} if this slot is not filled.
*/
public Date getFillTime() {
return fillTime;
}
public Key getSourceJobKey() {
return sourceJobKey;
}
public void setSourceJobKey(Key key) {
sourceJobKey = key;
}
public void fill(Object value) {
filled = true;
this.value = value;
serializedVersion = null;
fillTime = new Date();
}
public List<Key> getWaitingOnMeKeys() {
return waitingOnMeKeys;
}
/**
* If this slot has not yet been inflated this method returns null;
*/
public List<Barrier> getWaitingOnMeInflated() {
return waitingOnMeInflated;
}
@Override
public String toString() {
return "Slot[" + getKeyName(getKey()) + ", value=" + (serializedVersion != null ? "..." : value)
+ ", filled=" + filled + ", waitingOnMe=" + waitingOnMeKeys + ", parent="
+ getKeyName(getGeneratorJobKey()) + ", guid=" + getGraphGuid() + "]";
}
}