/* * 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.task.source; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.util.IdentityHashMap; import java.util.concurrent.LinkedBlockingQueue; import com.addthis.codec.annotations.FieldConfig; import com.addthis.codec.annotations.Pluggable; import com.addthis.codec.codables.Codable; /** * This section of the job specification handles input sources. * <p>The following factories are available: * <ul> * <li>{@link FileInputStreamSource file}</li> * <li>{@link InjectorStreamSource inject}</li> * <li>{@link SocketInputStreamSource socket}</li> * </ul> * * @user-reference */ @Pluggable("factory input stream") public abstract class FactoryInputStream implements Codable { /** * @return an InputStream */ public abstract InputStream createInputStream() throws IOException; /** * @user-reference */ public static final class FileInputStreamSource extends FactoryInputStream { @FieldConfig(codable = true, required = true) private String file; @Override public InputStream createInputStream() throws IOException { return new FileInputStream(file); } } /** * @user-reference */ public static final class SocketInputStreamSource extends FactoryInputStream { @FieldConfig(codable = true, required = true) private String host; @FieldConfig(codable = true, required = true) private int port; @Override public InputStream createInputStream() throws IOException { Socket socket = new Socket(host, port); socket.setTcpNoDelay(true); socket.setSoTimeout(60000 * 5); return socket.getInputStream(); } } /** * @user-reference */ public static final class InjectorStreamSource extends FactoryInputStream { public static final String DefautlInjectorKey = "secretDefaultInjectorKey"; private static final IdentityHashMap<String, LinkedBlockingQueue<InputStream>> park = new IdentityHashMap<>(); public static final void inject(String key, InputStream in) { key = key.intern(); synchronized (key) { try { LinkedBlockingQueue<InputStream> queue = null; synchronized (park) { queue = park.get(key); if (queue == null) { queue = new LinkedBlockingQueue<>(); park.put(key, queue); key.notifyAll(); } } queue.put(in); } catch (InterruptedException e) { throw new RuntimeException(e); } } } /** * The default value is "secretDefaultInjectorKey". */ @FieldConfig(codable = true) private String key = DefautlInjectorKey; private LinkedBlockingQueue<InputStream> queue = null; @Override public InputStream createInputStream() throws IOException { try { while (queue == null) { key = key.intern(); synchronized (key) { synchronized (park) { queue = park.get(key); } if (queue == null) { key.wait(); continue; } break; } } return queue.take(); } catch (Exception ex) { throw new RuntimeException(ex); } } } }