/** * 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 org.jledit; import jline.Terminal; import org.jledit.utils.Resources; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; public class ConcreteEditorFactory implements EditorFactory { private static final String DEFAULT_FLAVOR = "simple"; private static final String RESOURCE_PATH = "META-INF/services/org/jledit/"; private final Map<String, Class<? extends ConsoleEditor>> flavorMap = new HashMap<String, Class<? extends ConsoleEditor>>(); /** * Creates a {@link ConsoleEditor}. * * @return */ @Override public ConsoleEditor create() throws EditorInitializationException { return create(DEFAULT_FLAVOR); } /** * Creates a {@link ConsoleEditor} using the specified {@link jline.Terminal}. * * @return * @throws org.jledit.EditorInitializationException * */ @Override public ConsoleEditor create(Terminal terminal) throws EditorInitializationException { return create(DEFAULT_FLAVOR, terminal); } /** * Creates a {@link ConsoleEditor} based on the specified flavor. * * @param flavor * @return */ @Override public ConsoleEditor create(String flavor) throws EditorInitializationException { return create(flavor, null); } /** * Creates a {@link ConsoleEditor} based on the specified flavor & {@link jline.Terminal}. * * @param flavor * @param terminal * @return * @throws org.jledit.EditorInitializationException * */ @Override public ConsoleEditor create(String flavor, Terminal terminal) throws EditorInitializationException { if (flavorMap.containsKey(flavor)) { Class<? extends ConsoleEditor> editorClass = flavorMap.get(flavor); try { return instantiate(editorClass, terminal); } catch (Exception e) { throw new EditorInitializationException("Failed to create Editor instance of class:" + editorClass.getName(), e); } } else { Class<? extends ConsoleEditor> editorClass = resolve(flavor); if (editorClass != null) { flavorMap.put(flavor, editorClass); return create(flavor, terminal); } else { throw new EditorInitializationException("Unknown flavor:" + flavor); } } } /** * Resolves the {@link ConsoleEditor} class for the specified flavor. * @param flavor * @return * @throws EditorInitializationException */ private Class<? extends ConsoleEditor> resolve(String flavor) throws EditorInitializationException { ClassLoader classLoader = getClass().getClassLoader(); try { Enumeration<URL> urls = classLoader.getResources(RESOURCE_PATH + flavor); while (urls.hasMoreElements()) { URL url = urls.nextElement(); String txt = Resources.toString(url); String[] jleditClasses = txt.split("\n"); for (String jleditClass : jleditClasses) { if (!jleditClass.isEmpty()) { Class clazz = classLoader.loadClass(jleditClass); if (ConsoleEditor.class.isAssignableFrom(clazz)) { return clazz; } } } } } catch (Exception e) { throw new EditorInitializationException(e); } throw new EditorInitializationException("No Editor found for flavor:" + flavor); } /** * Instantiates the {@link ConsoleEditor}. * @param editorClass * @param terminal * @return * @throws IllegalAccessException * @throws InvocationTargetException * @throws InstantiationException * @throws NoSuchMethodException */ private ConsoleEditor instantiate(Class<? extends ConsoleEditor> editorClass, Terminal terminal) throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException { Constructor constructor = editorClass.getConstructor(Terminal.class); return (ConsoleEditor) constructor.newInstance(terminal); } /** * Binds the specified flavor to the specified class. * * @param flavor * @param editorClass */ @Override public void bind(String flavor, Class<? extends ConsoleEditor> editorClass) { flavorMap.put(flavor, editorClass); } /** * Unbinds flavor. * * @param flavor */ @Override public void unbind(String flavor) { flavorMap.remove(flavor); } }