Skip to content
Open
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
128 changes: 47 additions & 81 deletions src/main/java/edu/ksu/canvas/CanvasApiFactory.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package edu.ksu.canvas;

import com.google.common.reflect.ClassPath;
import edu.ksu.canvas.annotation.AbstainRegister;
import edu.ksu.canvas.impl.*;
import edu.ksu.canvas.interfaces.*;
import edu.ksu.canvas.net.RestClient;
Expand All @@ -8,10 +10,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Entry point for using the Canvas API library. It constructs concrete
Expand All @@ -24,13 +29,14 @@ public class CanvasApiFactory {

public static final Integer CANVAS_API_VERSION = 1;
private static final Logger LOG = LoggerFactory.getLogger(CanvasApiFactory.class);
private static final String IMPLEMENTATION_PACKAGE = "edu.ksu.canvas.impl";
private static final int DEFAULT_CONNECT_TIMEOUT_MS = 5000;
private static final int DEFAULT_READ_TIMEOUT_MS = 120000;
Map<Class<? extends CanvasReader>, Class<? extends BaseImpl>> readerMap;
Map<Class<? extends CanvasWriter>, Class<? extends BaseImpl>> writerMap;
private String canvasBaseUrl;
private int connectTimeout;
private int readTimeout;
private final Map<Class<? extends CanvasReader>, Class<? extends BaseImpl>> readerMap = new HashMap<>();
private final Map<Class<? extends CanvasWriter>, Class<? extends BaseImpl>> writerMap = new HashMap<>();
private final String canvasBaseUrl;
private final int connectTimeout;
private final int readTimeout;

/**
* Construct an API factory for a given instance of Canvas.
Expand All @@ -41,7 +47,12 @@ public CanvasApiFactory(String canvasBaseUrl) {
this.canvasBaseUrl = canvasBaseUrl;
this.connectTimeout = DEFAULT_CONNECT_TIMEOUT_MS;
this.readTimeout = DEFAULT_READ_TIMEOUT_MS;
setupClassMap();
try {
setupClassMap();
} catch (IOException e) {
LOG.error("Error setting up class map", e);
throw new RuntimeException("Error setting up class map", e);
}
}

/**
Expand All @@ -55,7 +66,12 @@ public CanvasApiFactory(String canvasBaseUrl, int connectTimeout, int readTimeou
this.canvasBaseUrl = canvasBaseUrl;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
setupClassMap();
try {
setupClassMap();
} catch (IOException e) {
LOG.error("Error setting up class map", e);
throw new RuntimeException("Error setting up class map", e);
}
}

/**
Expand Down Expand Up @@ -146,79 +162,29 @@ public <T extends CanvasWriter> T getWriter(Class<T> type, OauthToken oauthToken
}
}

private void setupClassMap() {
readerMap = new HashMap<>();
writerMap = new HashMap<>();
readerMap.put(AccountReader.class, AccountImpl.class);
readerMap.put(AdminReader.class, AdminImpl.class);
readerMap.put(AssignmentOverrideReader.class, AssignmentOverrideImpl.class);
readerMap.put(AssignmentReader.class, AssignmentImpl.class);
readerMap.put(ConversationReader.class, ConversationImpl.class);
readerMap.put(CourseReader.class, CourseImpl.class);
readerMap.put(TabReader.class, TabImpl.class);
readerMap.put(EnrollmentReader.class, EnrollmentImpl.class);
readerMap.put(QuizQuestionReader.class, QuizQuestionImpl.class);
readerMap.put(QuizReader.class, QuizImpl.class);
readerMap.put(QuizSubmissionQuestionReader.class, QuizSubmissionQuestionImpl.class);
readerMap.put(QuizSubmissionReader.class, QuizSubmissionImpl.class);
readerMap.put(SectionReader.class, SectionsImpl.class);
readerMap.put(UserReader.class, UserImpl.class);
readerMap.put(PageReader.class, PageImpl.class);
readerMap.put(EnrollmentTermReader.class, EnrollmentTermImpl.class);
readerMap.put(SubmissionReader.class, SubmissionImpl.class);
readerMap.put(AssignmentGroupReader.class, AssignmentGroupImpl.class);
readerMap.put(RoleReader.class, RoleImpl.class);
readerMap.put(ExternalToolReader.class, ExternalToolImpl.class);
readerMap.put(FileReader.class, FileImpl.class);
readerMap.put(LoginReader.class, LoginImpl.class);
readerMap.put(CalendarReader.class, CalendarEventImpl.class);
readerMap.put(AccountReportSummaryReader.class, AccountReportSummaryImpl.class);
readerMap.put(AccountReportReader.class, AccountReportImpl.class);
readerMap.put(ContentMigrationReader.class, ContentMigrationImpl.class);
readerMap.put(ProgressReader.class, ProgressImpl.class);
readerMap.put(CourseSettingsReader.class, CourseSettingsImpl.class);
readerMap.put(GradingStandardReader.class, GradingStandardImpl.class);
readerMap.put(ModuleReader.class, ModuleImpl.class);
readerMap.put(SisImportReader.class, SisImportImpl.class);
readerMap.put(SelectiveDataReader.class, SelectiveDataImpl.class);
readerMap.put(MigrationIssueReader.class, MigrationIssueImpl.class);
readerMap.put(CommunicationChannelReader.class, CommunicationChannelImpl.class);
readerMap.put(AuthenticationLogReader.class, AuthenticationLogImpl.class);
readerMap.put(FeatureReader.class, FeatureImpl.class);
readerMap.put(FeatureFlagReader.class, FeatureFlagImpl.class);
readerMap.put(RubricReader.class, RubricImpl.class);

writerMap.put(AccountWriter.class, AccountImpl.class);
writerMap.put(AssignmentOverrideWriter.class, AssignmentOverrideImpl.class);
writerMap.put(AdminWriter.class, AdminImpl.class);
writerMap.put(AssignmentWriter.class, AssignmentImpl.class);
writerMap.put(ConversationWriter.class, ConversationImpl.class);
writerMap.put(CourseWriter.class, CourseImpl.class);
writerMap.put(TabWriter.class, TabImpl.class);
writerMap.put(FileWriter.class, FileImpl.class);
writerMap.put(EnrollmentWriter.class, EnrollmentImpl.class);
writerMap.put(QuizQuestionWriter.class, QuizQuestionImpl.class);
writerMap.put(QuizWriter.class, QuizImpl.class);
writerMap.put(QuizSubmissionQuestionWriter.class, QuizSubmissionQuestionImpl.class);
writerMap.put(QuizSubmissionWriter.class, QuizSubmissionImpl.class);
writerMap.put(UserWriter.class, UserImpl.class);
writerMap.put(PageWriter.class, PageImpl.class);
writerMap.put(SectionWriter.class, SectionsImpl.class);
writerMap.put(SubmissionWriter.class, SubmissionImpl.class);
writerMap.put(AssignmentGroupWriter.class, AssignmentGroupImpl.class);
writerMap.put(RoleWriter.class, RoleImpl.class);
writerMap.put(ExternalToolWriter.class, ExternalToolImpl.class);
writerMap.put(LoginWriter.class, LoginImpl.class);
writerMap.put(CalendarWriter.class, CalendarEventImpl.class);
writerMap.put(AccountReportSummaryWriter.class, AccountReportSummaryImpl.class);
writerMap.put(AccountReportWriter.class, AccountReportImpl.class);
writerMap.put(ContentMigrationWriter.class, ContentMigrationImpl.class);
writerMap.put(ProgressWriter.class, ProgressImpl.class);
writerMap.put(CourseSettingsWriter.class, CourseSettingsImpl.class);
writerMap.put(GradingStandardWriter.class, GradingStandardImpl.class);
writerMap.put(SisImportWriter.class, SisImportImpl.class);
writerMap.put(CommunicationChannelWriter.class, CommunicationChannelImpl.class);
writerMap.put(FeatureFlagWriter.class, FeatureFlagImpl.class);
writerMap.put(RubricWriter.class, RubricImpl.class);
private void setupClassMap() throws IOException {
Set<Class<?>> implClasses = ClassPath.from(this.getClass().getClassLoader())
.getTopLevelClasses(IMPLEMENTATION_PACKAGE)
.stream()
.map(ClassPath.ClassInfo::load)
.collect(Collectors.toSet());

for (Class<?> implClass : implClasses) {
Class<?>[] interfaces = implClass.getInterfaces();

for (Class<?> interfaze : interfaces) {
if (interfaze.isAnnotationPresent(AbstainRegister.class)) {
LOG.debug("Skipped registering: {}", implClass.getCanonicalName());
continue;
}

if (CanvasReader.class.isAssignableFrom(interfaze) && !interfaze.equals(CanvasReader.class)) {
readerMap.put((Class<? extends CanvasReader>) interfaze, (Class<? extends BaseImpl>) implClass);
} else if (CanvasWriter.class.isAssignableFrom(interfaze) && !interfaze.equals(CanvasWriter.class)) {
writerMap.put((Class<? extends CanvasWriter>) interfaze, (Class<? extends BaseImpl>) implClass);
}
}
}
}

}
38 changes: 21 additions & 17 deletions src/main/java/edu/ksu/canvas/TestLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import edu.ksu.canvas.interfaces.AccountReader;
import edu.ksu.canvas.interfaces.CourseReader;
import edu.ksu.canvas.interfaces.DiscussionTopicReader;
import edu.ksu.canvas.model.Account;
import edu.ksu.canvas.model.Course;
import edu.ksu.canvas.model.DiscussionTopic;
import edu.ksu.canvas.oauth.NonRefreshableOauthToken;
import edu.ksu.canvas.oauth.OauthToken;
import edu.ksu.canvas.requestOptions.GetSingleDiscussionTopicOptions;
import edu.ksu.canvas.requestOptions.ListCurrentUserCoursesOptions;
import edu.ksu.canvas.requestOptions.ListDiscussionTopicsOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -26,25 +30,13 @@ public class TestLauncher {

private static final Logger LOG = LoggerFactory.getLogger(TestLauncher.class);

private String canvasUrl;
private OauthToken oauthToken;
private final String canvasUrl;
private final OauthToken oauthToken;

public static void main(String[] args) {

String canvasUrl = null;
String oauthToken = null;
if(args.length != 4) {
LOG.error("Must supply two arguments: --canvas_url http://instance.instructure.com --token [Manually generated token]");
System.exit(1);
}
for(int i=0; i < args.length; i++) {
if("--canvas_url".equals(args[i])) {
canvasUrl = args[i+1];
}
if("--token".equals(args[i])) {
oauthToken = args[i+1];
}
}
String canvasUrl = System.getenv("CANVAS_URL");
String oauthToken = System.getenv("CANVAS_API_TOKEN");

if(canvasUrl == null || oauthToken == null) {
LOG.error("Canvas URL or OAuth token is blank. Must have to continue!");
Expand All @@ -53,8 +45,9 @@ public static void main(String[] args) {

TestLauncher launcher = new TestLauncher(canvasUrl, oauthToken);
try {
launcher.getRootAccount();
//launcher.getRootAccount();
launcher.getOwnCourses();
launcher.getDiscussionTopics();
} catch(Exception e) {
LOG.error("Problem while executing example methods", e);
}
Expand All @@ -65,6 +58,17 @@ public TestLauncher(String canvasUrl, String tokenString) {
this.oauthToken = new NonRefreshableOauthToken(tokenString);
}

public void getDiscussionTopics() throws IOException {
CanvasApiFactory apiFactory = new CanvasApiFactory(canvasUrl);
DiscussionTopicReader topicReader = apiFactory.getReader(DiscussionTopicReader.class, oauthToken);
List<DiscussionTopic> topics = topicReader.listDiscussionTopics(new ListDiscussionTopicsOptions("141571", ListDiscussionTopicsOptions.IdType.COURSES).onlyAnnouncements());
System.out.println("Got " + topics.size() + " topics back from Canvas: ");
for (DiscussionTopic topic : topics) {
System.out.println(" topic: " + topic.getTitle());
System.out.println(topic.getLockInfo());
}
}

public void getRootAccount() throws IOException {
CanvasApiFactory apiFactory = new CanvasApiFactory(canvasUrl);
AccountReader acctReader = apiFactory.getReader(AccountReader.class, oauthToken);
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/edu/ksu/canvas/annotation/AbstainRegister.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package edu.ksu.canvas.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AbstainRegister {
}
57 changes: 57 additions & 0 deletions src/main/java/edu/ksu/canvas/impl/DiscussionTopicImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package edu.ksu.canvas.impl;

import com.google.gson.reflect.TypeToken;
import edu.ksu.canvas.interfaces.DiscussionTopicReader;
import edu.ksu.canvas.interfaces.DiscussionTopicWriter;
import edu.ksu.canvas.model.DiscussionTopic;
import edu.ksu.canvas.net.Response;
import edu.ksu.canvas.net.RestClient;
import edu.ksu.canvas.oauth.OauthToken;
import edu.ksu.canvas.requestOptions.GetSingleDiscussionTopicOptions;
import edu.ksu.canvas.requestOptions.ListDiscussionTopicsOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public class DiscussionTopicImpl extends BaseImpl<DiscussionTopic, DiscussionTopicReader, DiscussionTopicWriter> implements DiscussionTopicReader, DiscussionTopicWriter {

private static final Logger LOG = LoggerFactory.getLogger(DiscussionTopicImpl.class);


public DiscussionTopicImpl(String canvasBaseUrl, Integer apiVersion, OauthToken oauthToken, RestClient restClient, int connectTimeout, int readTimeout, Integer paginationPageSize, Boolean serializeNulls) {
super(canvasBaseUrl, apiVersion, oauthToken, restClient, connectTimeout, readTimeout, paginationPageSize, serializeNulls);
}


@Override
public List<DiscussionTopic> listDiscussionTopics(ListDiscussionTopicsOptions options) throws IOException {
LOG.debug("Getting discussion topics for course/group: {}", options.getCourseOrGroupId());
String url = buildCanvasUrl(options.getStringIdType() + "/" + options.getCourseOrGroupId() + "/discussion_topics", options.getOptionsMap());
return getListFromCanvas(url);
}

@Override
public Optional<DiscussionTopic> getDiscussionTopic(GetSingleDiscussionTopicOptions options) throws IOException {
LOG.debug("Getting discussion topic with id: {} for course/group: {}", options.getDiscussionId(), options.getCourseOrGroupId());
Response response = canvasMessenger.getSingleResponseFromCanvas(oauthToken, buildCanvasUrl(options.getStringIdType() + "/" + options.getCourseOrGroupId() + "/discussion_topics/" + options.getDiscussionId(), options.getOptionsMap()));
if (response.getErrorHappened() || response.getResponseCode() != 200) {
return Optional.empty();
}
return responseParser.parseToObject(DiscussionTopic.class, response);
}

@Override
protected Type listType() {
return new TypeToken<List<DiscussionTopic>>(){}.getType();
}

@Override
protected Class<DiscussionTopic> objectType() {
return DiscussionTopic.class;
}
}
2 changes: 2 additions & 0 deletions src/main/java/edu/ksu/canvas/interfaces/CanvasReader.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package edu.ksu.canvas.interfaces;


import edu.ksu.canvas.impl.BaseImpl;

import java.util.List;
import java.util.function.Consumer;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/ksu/canvas/interfaces/CourseReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface CourseReader extends CanvasReader<Course, CourseReader> {
List<Course> listCurrentUserCourses(ListCurrentUserCoursesOptions options) throws IOException;

/**
* Returns the list of active courses for the a user
* Returns the list of active courses for the user
* @param options The object holding options for this API call
* @return List of courses for the user matching any optional criteria
* @throws IOException When there is an error communicating with Canvas
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/edu/ksu/canvas/interfaces/DiscussionTopicReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.ksu.canvas.interfaces;

import edu.ksu.canvas.model.DiscussionTopic;
import edu.ksu.canvas.requestOptions.GetSingleDiscussionTopicOptions;
import edu.ksu.canvas.requestOptions.ListDiscussionTopicsOptions;

import java.io.IOException;
import java.util.List;
import java.util.Optional;

public interface DiscussionTopicReader extends CanvasReader<DiscussionTopic, DiscussionTopicReader> {

List<DiscussionTopic> listDiscussionTopics(ListDiscussionTopicsOptions options) throws IOException;

Optional<DiscussionTopic> getDiscussionTopic(GetSingleDiscussionTopicOptions options) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package edu.ksu.canvas.interfaces;

import edu.ksu.canvas.model.DiscussionTopic;

public interface DiscussionTopicWriter extends CanvasWriter<DiscussionTopic, DiscussionTopicWriter> {
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package edu.ksu.canvas.interfaces;


import edu.ksu.canvas.annotation.AbstainRegister;
import edu.ksu.canvas.model.EnrollmentTerm;

@AbstainRegister
public interface EnrollmentTermWriter extends CanvasWriter<EnrollmentTerm, EnrollmentTermWriter> {

}
Loading