Skip to content
This repository was archived by the owner on Jan 24, 2026. It is now read-only.

Commit 2444278

Browse files
committed
Basic Implementation
This basic implementation follows this complete documentation: https://codebottle.io/api/docs/getting-started
1 parent 58d0b41 commit 2444278

File tree

10 files changed

+758
-0
lines changed

10 files changed

+758
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package io.codebottle.api;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import java.util.Optional;
6+
import java.util.concurrent.CompletableFuture;
7+
import java.util.concurrent.ConcurrentHashMap;
8+
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import io.codebottle.api.model.Category;
11+
import io.codebottle.api.model.Language;
12+
import io.codebottle.api.model.Snippet;
13+
import io.codebottle.api.rest.CodeBottleRequest;
14+
import io.codebottle.api.rest.Endpoint;
15+
import org.jetbrains.annotations.Nullable;
16+
17+
public final class CodeBottle {
18+
private static final ObjectMapper objectMapper;
19+
20+
private final Map<Integer, Language> languageCache = new ConcurrentHashMap<>();
21+
private final Map<Integer, Category> categoryCache = new ConcurrentHashMap<>();
22+
private final Map<Integer, Snippet> snippetCache = new ConcurrentHashMap<>();
23+
24+
private final String token;
25+
26+
static {
27+
objectMapper = new ObjectMapper();
28+
}
29+
30+
public CodeBottle() {
31+
this(null);
32+
}
33+
34+
public CodeBottle(@Nullable String token) {
35+
this.token = token;
36+
}
37+
38+
public Optional<String> getToken() {
39+
return Optional.ofNullable(token);
40+
}
41+
42+
public Optional<Language> getLanguageByID(int id) {
43+
if (id == -1) return Optional.empty();
44+
45+
synchronized (languageCache) {
46+
return Optional.ofNullable(languageCache.get(id));
47+
}
48+
}
49+
50+
public CompletableFuture<Language> requestLanguageByID(int id) {
51+
return new CodeBottleRequest<Language>(this)
52+
.to(Endpoint.LANGUAGE_SPECIFIC, id)
53+
.makeGET()
54+
.then(data -> {
55+
synchronized (languageCache) {
56+
return getLanguageByID(id)
57+
.map(entity -> entity.update(data))
58+
.orElseGet(() -> languageCache.compute(id,
59+
// existing values don't matter here, as the cache access failed before
60+
(k, v) -> new Language(this, data)));
61+
}
62+
});
63+
}
64+
65+
public Optional<Category> getCategoryByID(int id) {
66+
if (id == -1) return Optional.empty();
67+
68+
synchronized (categoryCache) {
69+
return Optional.ofNullable(categoryCache.get(id));
70+
}
71+
}
72+
73+
public CompletableFuture<Category> requestCategoryByID(int id) {
74+
return new CodeBottleRequest<Category>(this)
75+
.to(Endpoint.CATEGORY_SPECIFIC, id)
76+
.makeGET()
77+
.then(data -> {
78+
synchronized (categoryCache) {
79+
return getCategoryByID(id)
80+
.map(entity -> entity.update(data))
81+
.orElseGet(() -> categoryCache.compute(id,
82+
// existing values don't matter here, as the cache access failed before
83+
(k, v) -> new Category(this, data)));
84+
}
85+
});
86+
}
87+
88+
public Optional<Snippet> getSnippetByID(int id) {
89+
if (id == -1) return Optional.empty();
90+
91+
synchronized (snippetCache) {
92+
return Optional.ofNullable(snippetCache.get(id));
93+
}
94+
}
95+
96+
public CompletableFuture<Snippet> requestSnippetByID(int id) {
97+
return new CodeBottleRequest<Snippet>(this)
98+
.to(Endpoint.SNIPPET_SPECIFIC, id)
99+
.makeGET()
100+
.then(data -> {
101+
synchronized (snippetCache) {
102+
return getSnippetByID(id)
103+
.map(entity -> entity.update(data))
104+
.orElseGet(() -> snippetCache.compute(id,
105+
// existing values don't matter here, as the cache access failed before
106+
(k, v) -> new Snippet(this, data)));
107+
}
108+
});
109+
}
110+
111+
public Optional<Snippet.Revision> getSnippetRevisionByID(int snippetId, int id) throws IndexOutOfBoundsException {
112+
if (id == -1) return Optional.empty();
113+
114+
synchronized (snippetCache) {
115+
return Optional.ofNullable(snippetCache.get(id))
116+
.flatMap(snippet -> snippet.getRevisionByID(id));
117+
}
118+
}
119+
120+
public CompletableFuture<Snippet.Revision> requestSnippetRevision(int snippetId, int id) {
121+
return getSnippetByID(snippetId)
122+
.orElseGet(() -> requestSnippetByID(snippetId).join())
123+
.requestRevision(id);
124+
}
125+
126+
public CompletableFuture<List<Snippet.Revision>> requestSnippetRevisions(int snippetId, int id) {
127+
return getSnippetByID(snippetId)
128+
.orElseGet(() -> requestSnippetByID(snippetId).join())
129+
.requestRevisions();
130+
}
131+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.codebottle.api.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.fasterxml.jackson.databind.JsonNode;
5+
import io.codebottle.api.CodeBottle;
6+
7+
public abstract class AbstractEntity {
8+
protected final CodeBottle context;
9+
10+
protected final @JsonProperty(required = true) int id;
11+
12+
protected AbstractEntity(CodeBottle context, JsonNode data) {
13+
this.context = context;
14+
this.id = data.get("id").asInt();
15+
16+
update(data);
17+
}
18+
19+
public AbstractEntity(CodeBottle context, int id) {
20+
this.context = context;
21+
22+
this.id = id;
23+
}
24+
25+
public int getID() {
26+
return id;
27+
}
28+
29+
public CodeBottle getContext() {
30+
return context;
31+
}
32+
33+
public abstract AbstractEntity update(JsonNode data);
34+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.codebottle.api.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.fasterxml.jackson.databind.JsonNode;
5+
import io.codebottle.api.CodeBottle;
6+
7+
public class Category extends AbstractEntity {
8+
private @JsonProperty(required = true) int id;
9+
private @JsonProperty(required = true) String name;
10+
11+
public Category(CodeBottle context, JsonNode data) {
12+
super(context, data);
13+
}
14+
15+
public String getName() {
16+
return name;
17+
}
18+
19+
@Override
20+
public Category update(JsonNode data) {
21+
this.name = data.path("name").asText(name);
22+
23+
return this;
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.codebottle.api.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.fasterxml.jackson.databind.JsonNode;
5+
import io.codebottle.api.CodeBottle;
6+
7+
public class Language extends AbstractEntity {
8+
private @JsonProperty(required = true) int id;
9+
private @JsonProperty(required = true) String name;
10+
11+
public Language(CodeBottle context, JsonNode data) {
12+
super(context, data);
13+
}
14+
15+
public String getName() {
16+
return name;
17+
}
18+
19+
@Override
20+
public Language update(JsonNode data) {
21+
this.name = data.path("name").asText(name);
22+
23+
return this;
24+
}
25+
}

0 commit comments

Comments
 (0)