001/** 002 * Copyright (C) 2007-2010, Jens Lehmann 003 * 004 * This file is part of DL-Learner. 005 * 006 * DL-Learner is free software; you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation; either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * DL-Learner is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 018 * 019 */ 020package org.dllearner.cli; 021 022import com.google.common.base.CaseFormat; 023import com.google.common.base.Strings; 024import com.google.common.collect.Sets; 025import org.apache.commons.lang.StringUtils; 026import org.apache.log4j.Level; 027import org.dllearner.cli.DocumentationGeneratorMeta.GlobalDoc; 028import org.dllearner.configuration.spring.editors.ConfigHelper; 029import org.dllearner.core.*; 030import org.dllearner.core.config.ConfigOption; 031import org.dllearner.utilities.Files; 032import org.reflections.Reflections; 033import org.semanticweb.owlapi.model.OWLClass; 034 035import java.io.File; 036import java.lang.reflect.Field; 037import java.util.*; 038import java.util.Map.Entry; 039 040/** 041 * 042 * @author Jens Lehmann 043 * 044 */ 045@SuppressWarnings("StringConcatenationInsideStringBufferAppend") 046public class DocumentationGenerator { 047 static { 048 if (System.getProperty("log4j.configuration") == null) 049 System.setProperty("log4j.configuration", "log4j.properties"); 050 //AnnComponentManager.setReflectionScanner(new Reflections()); 051 org.apache.log4j.Logger.getLogger(AnnComponentManager.class).setLevel(Level.DEBUG); 052 } 053 private AnnComponentManager cm = AnnComponentManager.getInstance(); 054 055 private static final Map<Class, String> varNameMapping = new HashMap<>(); 056 057 static { 058 varNameMapping.put(LearningAlgorithm.class, "la"); 059 varNameMapping.put(LearningProblem.class, "lp"); 060 varNameMapping.put(KnowledgeSource.class, "ks"); 061 varNameMapping.put(AbstractReasonerComponent.class, "reasoner"); 062 varNameMapping.put(org.dllearner.core.Heuristic.class, "h"); 063 varNameMapping.put(org.dllearner.refinementoperators.RefinementOperator.class, "op"); 064 } 065 066 public String getConfigDocumentationString() { 067 String doc = ""; 068 doc += "This file contains an automatically generated files of all components and their config options.\n\n"; 069 070 Set<Class<?>> componentsDone = new HashSet<>(); 071 Class<?>[] nonComponentClasses = { 072 CLI.class, 073 GlobalDoc.class 074 }; 075 076 // go through all types of components and write down their documentation 077 List<Class> coreComps = Arrays.asList(AnnComponentManager.coreComponentClasses); 078 Collections.reverse(coreComps); 079 LinkedList<String> cc = new LinkedList<>(); 080 doc += "*************************\n" 081 + "* Non-component classes *\n" 082 + "*************************\n\n"; 083 for (Class<?> comp : nonComponentClasses) { 084 if (componentsDone.contains(comp)) continue; 085 doc += getComponentConfigString(comp, Class.class); 086 componentsDone.add(comp); 087 } 088 089 for (Class<?> cats : coreComps) { 090 ComponentAnn ann = cats.getAnnotation(ComponentAnn.class); 091 String name = cats.getSimpleName(); 092 if (ann != null) { 093 name = ann.name(); 094 } 095 StringBuilder sc = new StringBuilder(); 096 sc.append("\n" + Strings.repeat("*", name.length() + 4) + "\n" 097 + "* " + name + " *\n" 098 + Strings.repeat("*", name.length() + 4) + "\n\n"); 099 100 for(Class<? extends Component> comp : cm.getComponentsOfType(cats)) { 101 if (componentsDone.contains(comp)) continue; 102 sc.append(getComponentConfigString(comp, cats)); 103 componentsDone.add(comp); 104 } 105 cc.addFirst(sc.toString()); 106 } 107 doc += StringUtils.join(cc, "\n"); 108 for (Class<?> comp : cm.getComponents()) { 109 StringBuilder sc = new StringBuilder(); 110 if (!componentsDone.contains(comp)) { 111 if (componentsDone.contains(comp)) continue; 112 sc.append(getComponentConfigString(comp, Component.class)); 113 componentsDone.add(comp); 114 } 115 if (sc.length() != 0) { 116 doc += "\n********************\n" 117 + "* Other Components *\n" 118 + "********************\n\n" 119 + sc.toString(); 120 } 121 } 122 123 return doc; 124 } 125 126 /** 127 * Writes documentation for all components available in this 128 * <code>ComponentManager</code> instance. It goes through 129 * all components (sorted by their type) and all the configuration 130 * options of the components. Explanations, default values, allowed 131 * values for the options are collected and the obtained string is 132 * written in a file. 133 * @param file The documentation file. 134 */ 135 public void writeConfigDocumentation(File file) { 136 Files.createFile(file, getConfigDocumentationString()); 137 } 138 139 private String getComponentConfigString( 140 Class<?> component, Class<?> category) { 141 // heading + anchor 142 StringBuilder sb = new StringBuilder(); 143 String klass = component.getName(); 144 145 String header = "component: " + klass; 146 String description = ""; 147 String catString = "component"; 148 String usage = null; 149 150 // some information about the component 151 if (Component.class.isAssignableFrom(component)) { 152 Class<? extends Component> ccomp = (Class<? extends Component>) component; 153 header = "component: " + AnnComponentManager.getName(ccomp) + " (" + klass + ") v" + AnnComponentManager.getVersion(ccomp); 154 description = AnnComponentManager.getDescription(ccomp); 155 catString = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, category.getSimpleName()); 156 ComponentAnn catAnn = category.getAnnotation(ComponentAnn.class); 157 if (catAnn != null) { 158 catString = catAnn.shortName(); 159 } 160 161 for (Entry<Class, String> entry : varNameMapping.entrySet()) { 162 Class cls = entry.getKey(); 163 if(cls.isAssignableFrom(component)) { 164 catString = entry.getValue(); 165 } 166 } 167 168 169 usage = "conf file usage: " + catString + ".type = \"" + AnnComponentManager.getShortName(ccomp) + "\"\n"; 170 171 } else { 172 ComponentAnn ann = component.getAnnotation(ComponentAnn.class); 173 if (ann != null) { 174 header = "component: " + ann.name() + " (" + klass + ") v" + ann.version(); 175 } 176 description = ann.description(); 177 if (component.equals(GlobalDoc.class)) { 178 catString=""; 179 usage = ""; 180 } else { 181 catString = "cli"; 182 183 usage = "conf file usage: " + catString + ".type = \"" + klass + "\"\n"; 184 } 185 } 186 header += "\n" + Strings.repeat("=", header.length()) + "\n"; 187 sb.append(header); 188 if(description.length() > 0) { 189 sb.append(description + "\n"); 190 } 191 sb.append("\n"); 192 sb.append(usage + "\n"); 193 optionsTable(sb, component, catString); 194 return sb.toString(); 195 } 196 197 private void optionsTable(StringBuilder sb, Class<?> component, String catString) { 198 // generate table for configuration options 199 Map<Field,Class<?>> options = ConfigHelper.getConfigOptionTypes(component); 200 for(Entry<Field,Class<?>> entry : options.entrySet()) { 201 String optionName = AnnComponentManager.getName(entry.getKey()); 202 ConfigOption option = entry.getKey().getAnnotation(ConfigOption.class); 203 String type = entry.getValue().getSimpleName(); 204 if(entry.getValue().equals(OWLClass.class)) { 205 type = "IRI"; 206 } 207 String exampleValue = !option.exampleValue().isEmpty() ? option.exampleValue() : option.defaultValue(); 208 Set<Class> noQuoteClasses = Sets.<Class>newHashSet(boolean.class, int.class, long.class, float.class, double.class, short.class, List.class, Set.class, Map.class); 209 Set<Class> collectionClasses = Sets.<Class>newHashSet(List.class, Set.class); 210 Set<Class> mapClasses = Sets.<Class>newHashSet(Map.class); 211 212 boolean needsQuotes = !noQuoteClasses.contains(entry.getValue()); 213 boolean isCollection = collectionClasses.contains(entry.getValue()); 214 boolean isMap = mapClasses.contains(entry.getValue()); 215 216 if(needsQuotes) { 217 exampleValue = "\"" + exampleValue + "\""; 218 } else if(isCollection && exampleValue.isEmpty()){ 219 exampleValue = "{" + exampleValue + "}"; 220 } else if (isMap && exampleValue.isEmpty()) { 221 exampleValue = "[]"; 222 } 223 224 sb.append("option name: " + optionName + "\n" 225 + "description: " + option.description() + "\n" 226 + "type: " + type + "\n" 227 + "required: " + option.required() + "\n" 228 + "default value: " + option.defaultValue() + "\n" 229 + "conf file usage: " + (catString.isEmpty()? "" : catString + ".") + optionName + " = " + exampleValue +"\n"); 230 231 sb.append("\n"); 232 } 233 } 234 235 /** 236 * @param args 237 */ 238 public static void main(String[] args) { 239 File file = new File("doc/configOptions.txt"); 240 DocumentationGenerator dg = new DocumentationGenerator(); 241 dg.writeConfigDocumentation(file); 242 System.out.println("Done"); 243 } 244 245}