/*
* 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.addthis.hydra.job.spawn;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import com.addthis.basis.util.LessBytes;
import com.addthis.basis.util.Parameter;
import com.addthis.codec.Codec;
import com.addthis.codec.codables.Codable;
import com.addthis.codec.json.CodecJSON;
import com.addthis.hydra.job.Job;
import com.addthis.hydra.job.JobTask;
import com.addthis.hydra.job.mq.CommandTaskKick;
import com.addthis.meshy.MeshyClient;
import com.addthis.meshy.MeshyClientConnector;
import com.addthis.meshy.service.message.MessageFileProvider;
import com.addthis.meshy.service.message.MessageListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Date: 10/22/12
* Time: 5:23 PM
* <p/>
* Attach Spawn to Mesh and present an API / Filesystem for Minions and others
*/
public class SpawnMesh implements MessageListener {
private static final Logger log = LoggerFactory.getLogger(SpawnMesh.class);
private static final Codec codec = CodecJSON.INSTANCE;
private static final String meshHost = Parameter.value("mesh.host", "localhost");
private static final int meshPort = Parameter.intValue("mesh.port", 0);
private static final int meshRetryTimeout = Parameter.intValue("mesh.retry.timeout", 5000);
private static final boolean meshQueue = Parameter.boolValue("queue.mesh", false);
private final Spawn spawn;
private final String meshPrefix;
private MeshyClientConnector meshClient;
private MessageFileProvider provider;
private AtomicBoolean linkUp = new AtomicBoolean(false);
SpawnMesh(final Spawn spawn) {
this.spawn = spawn;
this.meshPrefix = "/spawn/" + spawn.getUuid();
if (meshPort == 0) {
if (!meshQueue) return;
throw new RuntimeException("invalid mesh port 0");
}
meshClient = new MeshyClientConnector(meshHost, meshPort, 1000, meshRetryTimeout) {
@Override
public void linkUp(MeshyClient client) {
log.warn("connected to mesh on " + client);
provider = new MessageFileProvider(client);
provider.setListener(meshPrefix + "/status", SpawnMesh.this);
provider.setListener(meshPrefix + "/shutdown", SpawnMesh.this);
provider.setListener(meshPrefix + "/task/get.config", SpawnMesh.this);
linkUp.set(true);
synchronized (this) { this.notifyAll(); }
}
@Override
public void linkDown(MeshyClient client) {
log.warn("disconnected from mesh on " + client);
linkUp.set(false);
}
};
}
public void waitLinkUp() {
while (!linkUp.get()) {
synchronized (meshClient) {
try {
meshClient.wait(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public MeshyClient getClient() {
return meshClient.getClient();
}
private String getString(Map<String, String> map, String key, String defVal) {
try {
String v = map.get(key);
return v != null ? v : defVal;
} catch (Exception ex) {
return defVal;
}
}
private int getInt(Map<String, String> map, String key, int defVal) {
try {
return Integer.parseInt(map.get(key));
} catch (Exception ex) {
return defVal;
}
}
@Override
public void requestContents(String fileName, Map<String, String> options, OutputStream out) throws IOException {
if (fileName.endsWith("/status")) {
send(out, spawn);
} else if (fileName.endsWith("/shutdown")) {
if (options != null && options.containsKey("yes")) {
send(out, "shutting down");
System.exit(1);
} else {
send(out, "ignored. send yes=1 to initiate shutdown");
}
}
}
private void send(OutputStream out, String msg) {
try {
out.write(LessBytes.toBytes(msg));
out.write('\n');
out.close();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private void send(OutputStream out, Codable msg) {
try {
out.write(codec.encode(msg));
out.write('\n');
out.close();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private void send(OutputStream out, byte[] msg) {
try {
out.write(msg);
out.close();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static String getMeshHost() {
return meshHost;
}
public static int getMeshPort() {
return meshPort;
}
}