@Override public List<StellarFunctionDescription> getStellarFunctions() { List<StellarFunctionDescription> stellarFunctionDescriptions = new ArrayList<>(); Iterable<StellarFunctionInfo> stellarFunctionsInfo = StellarFunctions.FUNCTION_RESOLVER().getFunctionInfo(); stellarFunctionsInfo.forEach(stellarFunctionInfo -> { stellarFunctionDescriptions.add(new StellarFunctionDescription( stellarFunctionInfo.getName(), stellarFunctionInfo.getDescription(), stellarFunctionInfo.getParams(), stellarFunctionInfo.getReturns())); }); return stellarFunctionDescriptions; }
/** * Performs the core process of function resolution. */ protected Map<String, StellarFunctionInfo> resolveFunctions() { // maps a function name to its definition Map<String, StellarFunctionInfo> functions = new HashMap<>(); for(Class<? extends StellarFunction> clazz : resolvables()) { StellarFunctionInfo fn = resolveFunction(clazz); if(fn != null) { // check for duplicate function names StellarFunctionInfo fnSameName = functions.get(fn.getName()); if (fnSameName != null && ObjectUtils.notEqual(fnSameName, fn)) { LOG.warn("Namespace conflict: duplicate function names; `{}` implemented by [{}, {}]", fn.getName(), fnSameName.getFunction(), fn.getFunction()); } functions.put(fn.getName(), fn); } } return functions; }
@Override public StellarResult execute(String command, StellarShellExecutor executor) { // if '%functions FOO' then show only functions that contain 'FOO' String startsWith = StringUtils.trimToEmpty(command.substring(MAGIC_FUNCTIONS.length())); Predicate<String> nameFilter = (name -> true); if (StringUtils.isNotBlank(startsWith)) { nameFilter = (name -> name.contains(startsWith)); } // '%functions' -> list all functions in scope String functions = StreamSupport .stream(executor.getFunctionResolver().getFunctionInfo().spliterator(), false) .map(info -> String.format("%s", info.getName())) .filter(nameFilter) .sorted() .collect(Collectors.joining(", ")); return StellarResult.success(functions); } }
/** * Resolves a function by name. * @param functionName The name of the function to resolve. * @return The executable StellarFunction. */ @Override public StellarFunction apply(String functionName) { StellarFunctionInfo info = functions.get().get(functionName); if(info == null) { throw new IllegalStateException(format("Unknown function: `%s`", functionName)); } return info.getFunction(); }
/** * Resolves a Stellar function from a given class. * @param clazz The class. */ public static StellarFunctionInfo resolveFunction(Class<? extends StellarFunction> clazz) { StellarFunctionInfo info = null; // the class must be annotated if (clazz.isAnnotationPresent(Stellar.class)) { Stellar annotation = clazz.getAnnotation(Stellar.class); String fullyQualifiedName = getNameFromAnnotation(annotation); StellarFunction function = createFunction(clazz); if (fullyQualifiedName != null && function != null) { info = new StellarFunctionInfo( annotation.description(), fullyQualifiedName, annotation.params(), annotation.returns(), function); } } return info; }
@Override public StellarResult execute(String command, StellarShellExecutor executor) { StellarResult result; // expect ?functionName String functionName = StringUtils.substring(command, 1); // grab any docs for the given function Spliterator<StellarFunctionInfo> fnIterator = executor.getFunctionResolver().getFunctionInfo().spliterator(); Optional<StellarFunctionInfo> functionInfo = StreamSupport .stream(fnIterator, false) .filter(info -> StringUtils.equals(functionName, info.getName())) .findFirst(); if(functionInfo.isPresent()) { result = success(docFormat(functionInfo.get())); } else { result = error(String.format("No docs available for function '%s'", functionName)); } return result; }
/** * Formats the Stellar function info object into a readable string. * @param info The stellar function info object. * @return A readable string. */ private String docFormat(StellarFunctionInfo info) { StringBuffer docString = new StringBuffer(); // name docString.append(info.getName() + "\n"); // description docString.append(String.format("Description: %-60s\n\n", info.getDescription())); // params if(info.getParams().length > 0) { docString.append("Arguments:\n"); for(String param : info.getParams()) { docString.append(String.format("\t%-60s\n", param)); } docString.append("\n"); } // returns docString.append(String.format("Returns: %-60s\n", info.getReturns())); return docString.toString(); } }
for (StellarFunctionInfo info : getFunctionInfo()) { try { info.getFunction().close(); } catch (Throwable t) { errors.put(info.getName(), t);
/** * Creates the Stellar execution environment. * @param commandLine The command line arguments. * @param console The console which drives the REPL. * @param properties Stellar properties. */ private StellarShellExecutor createExecutor( CommandLine commandLine, Console console, Properties properties, StellarAutoCompleter autoCompleter) throws Exception { // setup zookeeper client Optional<String> zookeeperUrl = Optional.empty(); if(commandLine.hasOption("z")) { zookeeperUrl = Optional.of(commandLine.getOptionValue("z")); } StellarShellExecutor executor = new DefaultStellarShellExecutor(properties, zookeeperUrl); // the 'CONSOLE' capability is only available with the CLI REPL executor.getContext().addCapability(CONSOLE, () -> console); // allows some Stellar functions to access Stellar internals; should probably use %magics instead executor.getContext().addCapability(SHELL_VARIABLES, () -> executor.getState()); // register the auto-completer to be notified when needed executor.addSpecialListener( (special) -> autoCompleter.addCandidateFunction(special.getCommand())); executor.addFunctionListener( (function) -> autoCompleter.addCandidateFunction(function.getName())); executor.addVariableListener((name, val) -> autoCompleter.addCandidateVariable(name)); executor.init(); return executor; }
public static void main(String... argv) { List<StellarFunctionInfo> functions = Lists.newArrayList(SingletonFunctionResolver.getInstance().getFunctionInfo()); Collections.sort(functions, (o1, o2) -> o1.getName().compareTo(o2.getName())); for(StellarFunctionInfo info: functions) { System.out.println( "### `" + info.getName() + "`"); System.out.println( " * Description: " + info.getDescription() ); System.out.println( " * Input:"); for(String param :info.getParams()) { System.out.println( " * " + param ); } System.out.println( " * Returns: " + info.getReturns() ); System.out.println(""); } }
@Test public void testNotifyFunctionListeners() throws Exception { // setup an executor notified = false; Properties props = new Properties(); DefaultStellarShellExecutor executor = new DefaultStellarShellExecutor(props, Optional.empty()); // setup listener notified = false; executor.addFunctionListener((fn) -> { assertNotNull(fn); assertNotNull(fn.getName()); assertNotNull(fn.getFunction()); notified = true; }); // initialize... magics should be setup during initialization executor.init(); assertTrue(notified); }
/** * Create an executor that will run the Stellar code for the Zeppelin Notebook. * @return The stellar executor. */ private StellarShellExecutor createExecutor(Properties properties) throws Exception { // a zookeeper URL may be defined String zookeeperURL = StellarInterpreterProperty.ZOOKEEPER_URL.get(properties, String.class); StellarShellExecutor executor = new DefaultStellarShellExecutor(properties, Optional.ofNullable(zookeeperURL)); // register the auto-completer to be notified executor.addSpecialListener((magic) -> autoCompleter.addCandidateFunction(magic.getCommand())); executor.addFunctionListener((fn) -> autoCompleter.addCandidateFunction(fn.getName())); executor.addVariableListener((name, val) -> autoCompleter.addCandidateVariable(name)); executor.init(); return executor; }