/* * 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.data.query; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.List; import com.addthis.basis.util.LessFiles; import com.addthis.basis.util.Parameter; import com.addthis.bundle.channel.DataChannelError; import com.addthis.bundle.channel.DataChannelOutput; import com.addthis.bundle.core.Bundle; import com.addthis.bundle.core.BundleField; import com.addthis.bundle.core.BundleFormat; import com.addthis.bundle.core.list.ListBundle; import com.addthis.bundle.core.list.ListBundleFormat; import com.addthis.bundle.value.ValueFactory; import com.addthis.bundle.value.ValueObject; import com.addthis.bundle.value.ValueString; import com.addthis.hydra.data.util.Tokenizer; /** * command-line operation processor for performing queries on unix streams cat * [file] | clop 'sort=0:s:a;merge=ksu' [in-sep] [out-sep] [grouping] */ public class CLIQuery { private static final boolean debug = Parameter.boolValue("cliquery.debug", false); public static void main(String[] args) throws Exception { if (args.length == 0) { System.out.println("usage: [ops] <input-separator> <output-separator> <grouping>"); System.out.println(" this utility reads from stdin using newline for record delimiters."); System.out.println(" [ops] is the shorthand notation for pipelined query transforms."); System.out.println(" field separators can be specified for input and output and default to comma."); System.out.println(" grouping is possible if fields contain separators. ex: (), {}, [], ''"); return; } // setup result processor String insep = args.length > 1 ? args[1] : ","; String outsep = args.length > 2 ? args[2] : ","; String[] group = new String[]{"\"", "'", "()", "[]", "{}"}; File tempDir = LessFiles.createTempDir(); QueryOpProcessor rp = new QueryOpProcessor.Builder(new CMDLineDataChannelOutput(outsep), args[0]) .tempDir(tempDir).build(); if (args.length > 3) { group = new String[args.length - 3]; System.arraycopy(args, 3, group, 0, group.length); } if (debug) { System.out.println("ops -- " + rp.printOps()); } // create tokenizer Tokenizer tk = new Tokenizer(insep, group, false); // setup input stream String line; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while ((line = br.readLine()) != null) { List<String> tok = tk.tokenize(line); if (tok == null || tok.size() == 0) { continue; } String[] cols = new String[tok.size()]; for (int i = 0; i < tok.size(); i++) { cols[i] = "" + i; } Bundle b = new ListBundle(); BundleFormat f = b.getFormat(); int col = 0; for (String t : tok) { b.setValue(f.getField(Integer.toString(col++)), ValueFactory.create(t)); } if (b != null) { rp.send(b); } } // pass input results to processor, it will print rp.sendComplete(); LessFiles.deleteDir(tempDir); } } /** */ class CMDLineDataChannelOutput implements DataChannelOutput { private final BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out)); private final ListBundleFormat format = new ListBundleFormat(); private final String outsep; public CMDLineDataChannelOutput(String outsep) { this.outsep = outsep; } @Override public String toString() { return getClass().getSimpleName().toString(); } @Override public void send(Bundle rl) throws DataChannelError { try { int tc = 0; for (BundleField bf : rl.getFormat()) { ValueObject qv = rl.getValue(bf); if (tc++ > 0) { out.append(outsep); } if (qv == null) { continue; } String sv = qv.toString(); if (qv.getClass() == ValueString.class) { if (sv.indexOf("\"") >= 0) { sv = sv.replace("\"", "\\\""); } out.append("\"").append(sv).append("\""); } else { out.append(sv); } } out.append("\n"); out.flush(); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void sendComplete() { try { out.flush(); } catch (IOException e) { e.printStackTrace(); } } @Override public Bundle createBundle() { return new ListBundle(format); } @Override public void sourceError(Throwable er) { throw new RuntimeException(er); } @Override public void send(List<Bundle> bundles) { if (bundles != null && !bundles.isEmpty()) { for (Bundle bundle : bundles) { send(bundle); } } } }