Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions javadocs/readme.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
Put a ZIP file here named "java8.zip" containing Java's Javadocs (or where ever "BotConfig.JAVADOCS_DIR" points to)
This folder contains ZIP files generated by OakbotDoclet.

The ZIP file should contain the files that are in the "api" directory of the "Documentation" download, found here:
http://www.oracle.com/technetwork/java/javase/documentation/jdk8-doc-downloads-2133158.html
* Each ZIP file contains a collection of XML files, which contain parsed Javadoc information of a particular library.
* Each XML file contains the Javadoc information of a single class.
* The ZIP file also contains a "info.xml" file, which contains information about the library itself.

Make sure that a file called "allclasses-frames.html" is at the root of the ZIP.
=======================

I don't want to commit the real Javadoc file to version control, due to its large file size (~50MB), so I've committed a smaller, sample file instead.
To generate a ZIP file:

1. Clone and open the OakBot project: http://github.com/mangstadt/OakBot
2. Compile the OakbotDoclet class. You will need to include the JVM's "tools.jar" file on the classpath during compilation. This file can be found at "$JAVA_HOME/lib/tools.jar"
3. Tweak the "build-zip.sh" file as necessary and then execute it. Note that you'll need a copy of the library's source code on your computer.

=======================

I don't want to commit the ZIP for the Java 8 API to version control, due to its large file size (~6MB), so I've committed a smaller, sample file instead.
The sample ZIP file contains just a single class (java.lang.String).

ZIP files for various libraries (including the core Java 8 API) can be downloaded here:
https://www.dropbox.com/sh/xkf7kua3hzd8xvo/AAC1sOkVTNUE2MKPAXTm28bna?dl=0

-Michael
Binary file modified javadocs/sample.zip
Binary file not shown.
18 changes: 16 additions & 2 deletions src/main/java/com/gmail/inverseconduit/bot/DefaultBot.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class DefaultBot extends AbstractBot implements Subscribable<CommandHandl
protected final ChatInterface chatInterface;

protected final Set<CommandHandle> commands = new HashSet<>();
protected final Set<CommandHandle> listeners = new HashSet<>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be interesting to get oakBot a completely separate bot, given how he internally works different...

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this isn't a merge of OakBot into JavaBot, it's a merge of OakBot's "javadoc" command into JavaBot. :P

The reason I added the "listeners" Set is because I need a way to listen for numbers that people type into the chat.


public DefaultBot(ChatInterface chatInterface) {
this.chatInterface = chatInterface;
Expand All @@ -52,6 +53,8 @@ private void processMessageQueue() {
}

private void processMessage(final ChatMessage chatMessage) {
listeners.stream().map(l -> l.execute(chatMessage)).filter(l -> null != l).forEach(result -> chatInterface.sendMessage(SeChatDescriptor.buildSeChatDescriptorFrom(chatMessage), result));

final String trigger = AppContext.INSTANCE.get(BotConfig.class).getTrigger();
if ( !chatMessage.getMessage().startsWith(trigger)) { return; }

Expand All @@ -62,14 +65,23 @@ private void processMessage(final ChatMessage chatMessage) {
public Set<CommandHandle> getCommands() {
return Collections.unmodifiableSet(commands);
}

public Set<CommandHandle> getListeners(){
return Collections.unmodifiableSet(listeners);
}

@Override
public void subscribe(CommandHandle subscriber) {
commands.add(subscriber);
if (subscriber.getName() == null){
listeners.add(subscriber);
} else {
commands.add(subscriber);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one smells... See above comments about extracting a separate bot. It shouldn't be that much of a problem to set OakBot up as separate class

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it is very smelly. Maybe add a different interface for listerners, like ListenerHandle?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be interesting, yes. This would be a step to extracting OakBot, though. Your call ;)

}

@Override
public void unSubscribe(CommandHandle subscriber) {
listeners.remove(subscriber);
commands.remove(subscriber);
}

Expand All @@ -79,7 +91,9 @@ public void shutdown() {

@Override
public Collection<CommandHandle> getSubscriptions() {
return Collections.unmodifiableCollection(commands);
Set<CommandHandle> set = new HashSet<CommandHandle>(commands);
set.addAll(listeners);
return set;
}

}
17 changes: 16 additions & 1 deletion src/main/java/com/gmail/inverseconduit/bot/Program.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,30 @@ private void login() {

private void bindDefaultCommands() {
bindShutdownCommand();
bindNumberCommand();
bindJavaDocCommand();
new CoreBotCommands(chatInterface, bot).allCommands().forEach(bot::subscribe);
}

private void bindNumberCommand() {
final Pattern p = Pattern.compile("^\\d+$");
CommandHandle javaDoc = new CommandHandle.Builder(null, message -> {
Matcher matcher = p.matcher(message.getMessage());
if (!matcher.find()){
return null;
}

int choice = Integer.parseInt(matcher.group(0));
return javaDocAccessor.showChoice(message, choice);
}).build();
bot.subscribe(javaDoc);
}

private void bindJavaDocCommand() {
CommandHandle javaDoc = new CommandHandle.Builder("javadoc", message -> {
Matcher matcher = javadocPattern.matcher(message.getMessage());
matcher.find();
return javaDocAccessor.javadoc(message, matcher.group(1).trim());
return javaDocAccessor.javadoc(message, matcher.group(1));
}).build();
bot.subscribe(javaDoc);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@ public String execute(ChatMessage message) {
@Deprecated
public boolean matchesSyntax(String commandCall) {
// FIXME: Interimsimplementation. To be removed!
return commandCall.contains(name);
if (commandCall != null && name != null){
return commandCall.contains(name);
}
return false;
}

public String getHelpText() {
Expand Down
168 changes: 146 additions & 22 deletions src/main/java/com/gmail/inverseconduit/javadoc/ClassInfo.java
Original file line number Diff line number Diff line change
@@ -1,63 +1,187 @@
package com.gmail.inverseconduit.javadoc;

import java.util.Collection;
import java.util.List;
import java.util.Set;

import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;

/**
* Holds the Javadoc info of a class.
* @author Michael Angstadt
*/
public class ClassInfo {
private final String fullName;
private final ClassName name;
private final ClassName superClass;
private final String description;
private final String url;
private final List<String> modifiers;
private final Set<String> modifiers;
private final Set<ClassName> interfaces;
private final Multimap<String, MethodInfo> methods;
private final boolean deprecated;
private final LibraryZipFile zipFile;

private ClassInfo(Builder builder) {
name = builder.name;
superClass = builder.superClass;
description = builder.description;
modifiers = builder.modifiers.build();
interfaces = builder.interfaces.build();
methods = builder.methods.build();
deprecated = builder.deprecated;
zipFile = builder.zipFile;
}

public ClassInfo(String fullName, String description, String url, List<String> modifiers, boolean deprecated) {
this.fullName = fullName;
this.description = description;
this.url = url;
this.modifiers = modifiers;
this.deprecated = deprecated;
/**
* Gets the name of the class.
* @return the class name
*/
public ClassName getName() {
return name;
}

/**
* Gets the class's fully-qualified name.
* @return the fully-qualified name (e.g. "java.lang.String")
* Gets the name of the class's parent class.
* @return the parent class name or null if it doesn't have one
*/
public String getFullName() {
return fullName;
public ClassName getSuperClass() {
return superClass;
}

/**
* Gets the class's description.
* @return the class description, formatted in SO Chat's markdown language
* Gets the class description.
* @return the class description (in SO-Chat markdown)
*/
public String getDescription() {
return description;
}

/**
* Gets the URL where this class's Javadocs can be viewed online.
* @return the URL or null if unknown
* Gets the URL to this class's Javadoc page (with frames).
* @return the URL or null if no base URL was given
*/
public String getFrameUrl() {
return zipFile.getFrameUrl(this);
}

/**
* Gets the URL to this class's Javadoc page (without frames).
* @return the URL or null if no base URL was given
*/
public String getUrl() {
return url;
return zipFile.getUrl(this);
}

/**
* Gets the modifiers of this class.
* @return the modifiers (e.g. "public", "final", "class")
* Gets the class modifiers.
* @return the class modifiers (e.g. "public, final")
*/
public List<String> getModifiers() {
public Collection<String> getModifiers() {
return modifiers;
}

/**
* Gets whether the class is deprecated or not.
* Gets the names of the interfaces that the class implements.
* @return the class's interfaces
*/
public Collection<ClassName> getInterfaces() {
return interfaces;
}

/**
* Gets info on all of the methods that have the given name.
* @param name the method name (case insensitive)
* @return the methods
*/
public Collection<MethodInfo> getMethod(String name) {
return methods.get(name.toLowerCase());
}

/**
* Gets the class's methods.
* @return the class's methods
*/
public Collection<MethodInfo> getMethods() {
return methods.values();
}

/**
* Determines whether the class is deprecated or not.
* @return true if it's deprecated, false if not
*/
public boolean isDeprecated() {
return deprecated;
}

/**
* Gets the ZIP file that the class's parsed Javadoc info is stored in.
* @return the ZIP file
*/
public LibraryZipFile getZipFile() {
return zipFile;
}

/**
* Builds new instances of {@link ClassInfo}.
*/
public static class Builder {
private ClassName name;
private ClassName superClass;
private String description;
private ImmutableSet.Builder<String> modifiers = ImmutableSet.builder();
private ImmutableSet.Builder<ClassName> interfaces = ImmutableSet.builder();
private ImmutableMultimap.Builder<String, MethodInfo> methods = ImmutableMultimap.builder();
private boolean deprecated = false;
private LibraryZipFile zipFile;

public Builder name(String full, String simple) {
this.name = new ClassName(full, simple);
return this;
}

public Builder description(String description) {
this.description = description;
return this;
}

public Builder superClass(String superClass) {
this.superClass = new ClassName(superClass);
return this;
}

public Builder modifiers(List<String> modifiers) {
this.modifiers.addAll(modifiers);
return this;
}

public Builder interface_(String interface_) {
interfaces.add(new ClassName(interface_));
return this;
}

public Builder interfaces(List<ClassName> interfaces) {
this.interfaces.addAll(interfaces);
return this;
}

public Builder method(MethodInfo method) {
this.methods.put(method.getName().toLowerCase(), method);
return this;
}

public Builder deprecated(boolean deprecated) {
this.deprecated = deprecated;
return this;
}

public Builder zipFile(LibraryZipFile zipFile) {
this.zipFile = zipFile;
return this;
}

public ClassInfo build() {
return new ClassInfo(this);
}
}
}
Loading