From bde0e1b74a299aebc9e845cb5bc26e947099f263 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 14:00:22 +0300 Subject: [PATCH 01/13] Initial API commit --- .../vlad/newsapi4j/access/APIConnection.java | 39 ++++ .../vlad/newsapi4j/client/NewsApiClient.java | 174 ++++++++++++++++ src/com/vlad/newsapi4j/client/Response.java | 67 +++++++ .../client/StandartAsyncService.java | 107 ++++++++++ .../newsapi4j/client/StandartService.java | 152 ++++++++++++++ .../vlad/newsapi4j/examples/Asynchronous.java | 49 +++++ src/com/vlad/newsapi4j/examples/Custom.java | 188 ++++++++++++++++++ src/com/vlad/newsapi4j/examples/Standart.java | 43 ++++ src/com/vlad/newsapi4j/model/Article.java | 173 ++++++++++++++++ src/com/vlad/newsapi4j/model/NewsSource.java | 136 +++++++++++++ .../vlad/newsapi4j/response/APIResponse.java | 70 +++++++ src/com/vlad/newsapi4j/service/Endpoint.java | 38 ++++ .../vlad/newsapi4j/service/IAsyncService.java | 178 +++++++++++++++++ src/com/vlad/newsapi4j/service/IService.java | 173 ++++++++++++++++ src/com/vlad/newsapi4j/service/SortBy.java | 11 + src/com/vlad/newsapi4j/utils/Callback.java | 8 + src/com/vlad/newsapi4j/utils/Category.java | 27 +++ src/com/vlad/newsapi4j/utils/DateRange.java | 39 ++++ src/com/vlad/newsapi4j/utils/LinkBuilder.java | 129 ++++++++++++ .../newsapi4j/utils/NewsAPIException.java | 14 ++ .../utils/NewsAPIRuntimeException.java | 14 ++ .../vlad/newsapi4j/utils/ResponseStatus.java | 9 + 22 files changed, 1838 insertions(+) create mode 100644 src/com/vlad/newsapi4j/access/APIConnection.java create mode 100644 src/com/vlad/newsapi4j/client/NewsApiClient.java create mode 100644 src/com/vlad/newsapi4j/client/Response.java create mode 100644 src/com/vlad/newsapi4j/client/StandartAsyncService.java create mode 100644 src/com/vlad/newsapi4j/client/StandartService.java create mode 100644 src/com/vlad/newsapi4j/examples/Asynchronous.java create mode 100644 src/com/vlad/newsapi4j/examples/Custom.java create mode 100644 src/com/vlad/newsapi4j/examples/Standart.java create mode 100644 src/com/vlad/newsapi4j/model/Article.java create mode 100644 src/com/vlad/newsapi4j/model/NewsSource.java create mode 100644 src/com/vlad/newsapi4j/response/APIResponse.java create mode 100644 src/com/vlad/newsapi4j/service/Endpoint.java create mode 100644 src/com/vlad/newsapi4j/service/IAsyncService.java create mode 100644 src/com/vlad/newsapi4j/service/IService.java create mode 100644 src/com/vlad/newsapi4j/service/SortBy.java create mode 100644 src/com/vlad/newsapi4j/utils/Callback.java create mode 100644 src/com/vlad/newsapi4j/utils/Category.java create mode 100644 src/com/vlad/newsapi4j/utils/DateRange.java create mode 100644 src/com/vlad/newsapi4j/utils/LinkBuilder.java create mode 100644 src/com/vlad/newsapi4j/utils/NewsAPIException.java create mode 100644 src/com/vlad/newsapi4j/utils/NewsAPIRuntimeException.java create mode 100644 src/com/vlad/newsapi4j/utils/ResponseStatus.java diff --git a/src/com/vlad/newsapi4j/access/APIConnection.java b/src/com/vlad/newsapi4j/access/APIConnection.java new file mode 100644 index 0000000..48a709a --- /dev/null +++ b/src/com/vlad/newsapi4j/access/APIConnection.java @@ -0,0 +1,39 @@ +package com.vlad.newsapi4j.access; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +import com.vlad.newsapi4j.utils.LinkBuilder; + +public class APIConnection { + + public APIConnection(LinkBuilder link) { + this.fromWhere = link.toString(); + } + + private String fromWhere; + + public String getContents() { + StringBuilder builder = new StringBuilder(); + try { + HttpURLConnection connection = (HttpURLConnection) new URL(fromWhere).openConnection(); + connection.setDoInput(true); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Content-Type", "application/json; charset=utf-8"); + connection.setRequestProperty("Data-Type", "json"); + InputStreamReader streamReader = new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(streamReader); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line); + } + } catch (Exception ex) { + + } + return builder.toString(); + } + +} diff --git a/src/com/vlad/newsapi4j/client/NewsApiClient.java b/src/com/vlad/newsapi4j/client/NewsApiClient.java new file mode 100644 index 0000000..7e1c292 --- /dev/null +++ b/src/com/vlad/newsapi4j/client/NewsApiClient.java @@ -0,0 +1,174 @@ +package com.vlad.newsapi4j.client; + +import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.service.IAsyncService; +import com.vlad.newsapi4j.service.IService; + +public class NewsApiClient { + + private String apiKey; + + public NewsApiClient(String apiKey) { + this.apiKey = apiKey; + } + + /** + * creates an 'everything' request
+ * + * To query everything, you must include at least a keyword,
+ * source or domain + * + * via the appropriate method from IService + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @return + */ + public IService newEverythingService() { + return new StandartService().prepare(apiKey, Endpoint.EVERYTHING); + } + + /** + * Creates a 'top-headlines' request
+ * + * All options passed are optional, however at least one must be included, in + * order to
+ * query top-headlines + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @return + */ + public IService newTopHeadlinesService() { + return new StandartService().prepare(apiKey, Endpoint.TOP_HEADLINES); + } + + /** + * Creates a 'sources' request
+ * + * No options are mandatory + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @return + */ + public IService newSourcesService() { + return new StandartService().prepare(apiKey, Endpoint.SOURCES); + } + + /** + * Creates a custom service
+ * In order to create a custom service, implement IService without overriding + * the default constructor!
+ * then, simply pass it to the method : + * NewsApiClient.newCustomService(new MyCustomService(), Endpoint.[Some endpoint]); + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param service + * @param endpoint + * @return + */ + public IService newCustomService(IService service, Endpoint endpoint) { + return service.prepare(apiKey, endpoint); + } + + /** + * creates an 'everything' request that will run asynchronously
+ * + * To query everything, you must include at least a keyword,
+ * source or domain + * + * via the appropriate method from IService + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @return + */ + public IAsyncService newEverythingServiceAsync() { + return new StandartAsyncService().prepare(apiKey, Endpoint.EVERYTHING); + } + + /** + * Creates a 'top-headlines' request that will run asynchronously
+ * + * All options passed are optional, however at least one must be included, in + * order to
+ * query top-headlines + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @return + */ + public IAsyncService newTopHeadlinesServiceAsync() { + return new StandartAsyncService().prepare(apiKey, Endpoint.TOP_HEADLINES); + } + + /** + * Creates a 'sources' request that will run asynchronously
+ * + * No options are mandatory
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @return + */ + public IAsyncService newSourcesServiceAsync() { + return new StandartAsyncService().prepare(apiKey, Endpoint.SOURCES); + } + + /** + * Creates a custom asynchronous service
+ * In order to create a custom service, implement IAsyncService without + * overriding the default constructor!
+ * then, simply pass it to the method : + * NewsApiClient.newCustomAsyncService(new MyCustomService(), Endpoint.[Some endpoint]); + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param service + * @param endpoint + * @return + */ + public IAsyncService newCustomAsyncService(IAsyncService service, Endpoint endpoint) { + return service.prepare(apiKey, endpoint); + } + + /** + * @return The API key used by this object + */ + public String getApiKey() { + return new String(apiKey); + } + +} diff --git a/src/com/vlad/newsapi4j/client/Response.java b/src/com/vlad/newsapi4j/client/Response.java new file mode 100644 index 0000000..945c4ba --- /dev/null +++ b/src/com/vlad/newsapi4j/client/Response.java @@ -0,0 +1,67 @@ +package com.vlad.newsapi4j.client; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.utils.ResponseStatus; + +public class Response implements APIResponse { + + private ResponseStatus status; + private int totalRes; + private JSONObject content; + private List list; + private Endpoint endpoint; + + public Response(Endpoint reqType, String content, ResponseStatus status, int totalRes) { + this.totalRes = totalRes; + this.status = status; + List dataActual = new ArrayList<>(); + try { + this.content = new JSONObject(content); + JSONArray jsonData = this.content.getJSONArray(reqType != Endpoint.SOURCES ? "articles" : "sources"); + for (int i = 0; i < jsonData.length(); i++) { + dataActual.add(jsonData.getJSONObject(i)); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + this.list = dataActual; + this.endpoint = reqType; + } + + @Override + public ResponseStatus getStatus() { + return status; + } + + @Override + public int totalResults() { + return totalRes; + } + + @Override + public JSONObject getJSON() { + return content; + } + + @Override + public List getData() { + return list; + } + + @Override + public Type getResponseType() { + return endpoint == Endpoint.SOURCES ? + Type.SOURCES + : Type.ARTICLES; + } + +} \ No newline at end of file diff --git a/src/com/vlad/newsapi4j/client/StandartAsyncService.java b/src/com/vlad/newsapi4j/client/StandartAsyncService.java new file mode 100644 index 0000000..b47ff92 --- /dev/null +++ b/src/com/vlad/newsapi4j/client/StandartAsyncService.java @@ -0,0 +1,107 @@ +package com.vlad.newsapi4j.client; + +import java.util.Date; +import java.util.function.Supplier; + +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.service.IAsyncService; +import com.vlad.newsapi4j.utils.Callback; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.DateRange; +import com.vlad.newsapi4j.utils.NewsAPIException; + +class StandartAsyncService implements IAsyncService { + + private StandartService stdService; + + public StandartAsyncService() { + stdService = new StandartService(); + } + + @Override + public IAsyncService withSources(String... sources) { + stdService.withSources(sources); + return this; + } + + @Override + public IAsyncService withDomains(String... domains) { + stdService.withDomains(domains); + return this; + } + + @Override + public IAsyncService withKeyword(String keyword) { + stdService.withKeyword(keyword); + return this; + } + + @Override + public IAsyncService language(String lang) { + stdService.language(lang); + return this; + } + + @Override + public IAsyncService sortBy(String sortBy) { + stdService.sortBy(sortBy); + return this; + } + + @Override + public IAsyncService country(String country) { + stdService.country(country); + return this; + } + + @Override + public IAsyncService page(int page) { + stdService.page(page); + return this; + } + + @Override + public IAsyncService to(Date to) { + stdService.to(to); + return this; + } + + @Override + public IAsyncService from(Date date) { + stdService.from(date); + return this; + } + + @Override + public void send(Callback result, Callback onError) { + new Thread(() -> { + try { + result.invoke(stdService.send()); + } catch (NewsAPIException exception) { + onError.invoke(exception); + } + }).start(); + } + + @Override + public IAsyncService prepare(String apiKey, Endpoint endpoint) { + stdService.prepare(apiKey, endpoint); + return this; + } + + @Override + public IAsyncService withCategory(Category category) { + stdService.withCategory(category); + return this; + } + + @Override + public IAsyncService dateRange(Supplier range) { + // TODO Auto-generated method stub + return null; + } + + + +} diff --git a/src/com/vlad/newsapi4j/client/StandartService.java b/src/com/vlad/newsapi4j/client/StandartService.java new file mode 100644 index 0000000..deb93e8 --- /dev/null +++ b/src/com/vlad/newsapi4j/client/StandartService.java @@ -0,0 +1,152 @@ +package com.vlad.newsapi4j.client; + +import java.util.Date; +import java.util.function.Supplier; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.vlad.newsapi4j.access.APIConnection; +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.service.IService; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.DateRange; +import com.vlad.newsapi4j.utils.LinkBuilder; +import com.vlad.newsapi4j.utils.NewsAPIException; +import com.vlad.newsapi4j.utils.ResponseStatus; + +class StandartService implements IService { + + private String apiKey; + + private Endpoint endpoint; + + private LinkBuilder link; + + StandartService() { + + } + + @Override + public IService withSources(String... sources) { + link.sources(sources); + return this; + } + + @Override + public IService withDomains(String... domains) { + link.domains(domains); + return this; + } + + @Override + public IService withKeyword(String keyword) { + link.keyword(keyword); + return this; + } + + @Override + public IService language(String lang) { + link.language(lang); + return this; + } + + @Override + public IService sortBy(String sortBy) { + link.sortBy(sortBy); + return this; + } + + @Override + public IService page(int page) { + link.page(page); + return this; + } + + @Override + public IService to(Date to) { + link.to(to); + return this; + } + + @Override + public IService from(Date date) { + link.from(date); + return this; + } + + @Override + public APIResponse send() throws NewsAPIException { + /** + * Insert the API Key + */ + link.finish(apiKey); + /** + * Connect to NewsAPI + */ + System.out.println(link); + String content = new APIConnection(link).getContents(); + int totalResults = APIResponse.INFORMATION_UNAVAILABLE; + JSONObject obj = null; + try { + obj = new JSONObject(content); + // System.out.println(obj); + } catch (JSONException e1) { + // throw new NewsAPIException("Something went wrong while parsing json"); + e1.printStackTrace(); + } + + System.out.println(link); + ResponseStatus status = ResponseStatus.OK; + /** + * Returns at least an empty string, not null + */ + if (content.contains("error") || content.equals("")) { + status = ResponseStatus.ERROR; + String message = ""; + try { + message = obj.getString("message"); + } catch (JSONException e) { + throw new NewsAPIException("Something went wrong while parsing json"); + } + throw new NewsAPIException(message); + } + + if (endpoint != Endpoint.SOURCES) + try { + totalResults = obj.getInt("totalResults"); + } catch (JSONException e) { + throw new NewsAPIException("Something went wrong while parsing json"); + } + return new Response(endpoint, content, status, totalResults); + } + + @Override + public IService country(String country) { + link.country(country); + return this; + } + + @Override + public IService prepare(String apiKey, Endpoint endpoint) { + this.apiKey = apiKey; + this.endpoint = endpoint; + this.link = new LinkBuilder(endpoint); + return this; + } + + @Override + public IService withCategory(Category category) { + link.category(category.toLink()); + return this; + } + + @Override + public IService range(Supplier range) { + link.from(range.get().getFrom()); + link.to(range.get().getTo()); + return this; + } + +} diff --git a/src/com/vlad/newsapi4j/examples/Asynchronous.java b/src/com/vlad/newsapi4j/examples/Asynchronous.java new file mode 100644 index 0000000..c04b325 --- /dev/null +++ b/src/com/vlad/newsapi4j/examples/Asynchronous.java @@ -0,0 +1,49 @@ +package com.vlad.newsapi4j.examples; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import com.vlad.newsapi4j.client.NewsApiClient; +import com.vlad.newsapi4j.model.Article; +import com.vlad.newsapi4j.service.SortBy; + +public class Asynchronous { + + public static void main(String[] args) { + NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); + /** + * Create the asynchronous request and supply with information + * Get the top headlines in the us today, sort them by date, show the first page(optional it's 1 by default) + */ + client.newTopHeadlinesServiceAsync() + .country("us") + .from(new Date()) + .sortBy(SortBy.DATE) + .page(1) + /** + * send method gets called either with the result callback or with the error one + */ + .send(result -> { + /** + * We are here, everything is fine + */ + List
articles = result.viewAsArticles().orElseGet(Collections::emptyList); + /** + * Get all articles whose author starts with the letter 'a', coz why not :D + */ + articles.stream() + .filter(article -> article.getAuthor().startsWith("A")) + .forEach(System.out::println); + + }, /** + * We are here, something went wrong, just print the cause + */ + Throwable::printStackTrace); + /** + * Program flow continues freely + */ + System.out.println("Yay, running concurrently"); + } + +} diff --git a/src/com/vlad/newsapi4j/examples/Custom.java b/src/com/vlad/newsapi4j/examples/Custom.java new file mode 100644 index 0000000..eae3e7b --- /dev/null +++ b/src/com/vlad/newsapi4j/examples/Custom.java @@ -0,0 +1,188 @@ +package com.vlad.newsapi4j.examples; + +import java.util.Date; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.vlad.newsapi4j.access.APIConnection; +import com.vlad.newsapi4j.client.NewsApiClient; +import com.vlad.newsapi4j.client.Response; +import com.vlad.newsapi4j.model.Article; +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.service.IAsyncService; +import com.vlad.newsapi4j.utils.Callback; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.DateRange; +import com.vlad.newsapi4j.utils.LinkBuilder; +import com.vlad.newsapi4j.utils.NewsAPIException; +import com.vlad.newsapi4j.utils.ResponseStatus; + +public class Custom { + + public static void main(String[] args) { + NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); + client.newCustomAsyncService(new MyCustomAsyncService(), Endpoint.EVERYTHING) + .withKeyword("Youtube") + .language("en") + /** + * I HAD to break convention (All caps methods and all that), just look at how beautiful this looks + */ + .dateRange(DateRange::LAST_7_DAYS) + .send(result -> { + System.out.println("Result matches : " + result.totalResults()); + /** + * Find the first article that has an author ? + */ + Article a = result.viewAsArticles() + .get() + .stream() + .filter(article -> article.getAuthor() != null) + .findFirst() + .orElse(null); + System.out.println(a); + }, Throwable::printStackTrace); + + } + + private static class MyCustomAsyncService implements IAsyncService { + + private String apiKey; + + private Endpoint endpoint; + + private LinkBuilder link; + + public MyCustomAsyncService() { + + } + + @Override + public IAsyncService withSources(String... sources) { + link.sources(sources); + return this; + } + + @Override + public IAsyncService withDomains(String... domains) { + link.domains(domains); + return this; + } + + @Override + public IAsyncService withKeyword(String keyword) { + link.keyword(keyword); + return this; + } + + @Override + public IAsyncService withCategory(Category category) { + link.category(category.toLink()); + return this; + } + + @Override + public IAsyncService language(String lang) { + link.language(lang); + return this; + } + + @Override + public IAsyncService sortBy(String sortBy) { + link.sortBy(sortBy); + return this; + } + + @Override + public IAsyncService country(String country) { + link.country(country); + return this; + } + + @Override + public IAsyncService page(int page) { + link.page(page); + return this; + } + + @Override + public IAsyncService to(Date to) { + link.to(to); + return this; + } + + @Override + public IAsyncService from(Date date) { + link.from(date); + return this; + } + + @Override + public IAsyncService prepare(String apiKey, Endpoint endpoint) { + this.apiKey = apiKey; + this.endpoint = endpoint; + this.link = new LinkBuilder(endpoint); + return this; + } + + + + @Override + public void send(Callback result, Callback onError) { + new Thread(() -> { + link.finish(apiKey); + String content = new APIConnection(link).getContents(); + int totalRes = APIResponse.INFORMATION_UNAVAILABLE; + JSONObject obj = null; + try { + obj = new JSONObject(content); + // System.out.println(obj); + } catch (JSONException e1) { + // throw new NewsAPIException("Something went wrong while parsing json"); + e1.printStackTrace(); + } + + System.out.println(link); + ResponseStatus status = ResponseStatus.OK; + /** + * Returns at least an empty string, not null + */ + try { + if (obj.getString("status").equals("error") || content.equals("")) { + status = ResponseStatus.ERROR; + String message = ""; + try { + message = obj.getString("message"); + } catch (JSONException e) { + onError.invoke(new NewsAPIException("Something went wrong while parsing json")); + } + onError.invoke(new NewsAPIException(message)); + } + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (endpoint != Endpoint.SOURCES) + try { + totalRes = obj.getInt("totalResults"); + } catch (JSONException e) { + onError.invoke(new NewsAPIException("Something went wrong while parsing json")); + } + result.invoke(new Response(endpoint, content, status, totalRes)); + }).start(); + } + + @Override + public IAsyncService dateRange(Supplier range) { + this.link.from(range.get().getFrom()); + this.link.to(range.get().getTo()); + return this; + } + + } + +} diff --git a/src/com/vlad/newsapi4j/examples/Standart.java b/src/com/vlad/newsapi4j/examples/Standart.java new file mode 100644 index 0000000..1c28283 --- /dev/null +++ b/src/com/vlad/newsapi4j/examples/Standart.java @@ -0,0 +1,43 @@ +package com.vlad.newsapi4j.examples; + +import java.util.Collections; +import java.util.List; + +import com.vlad.newsapi4j.client.NewsApiClient; +import com.vlad.newsapi4j.model.NewsSource; +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.SortBy; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.NewsAPIException; + +public class Standart { + + public static void main(String[] args) throws NewsAPIException { + NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); + /** + * Wait and receive response from server + */ + APIResponse response = client.newSourcesService() + .withKeyword("bulgaria") + .sortBy(SortBy.POPULARITY) + .send(); + + System.out.println("Response type : "+response.getResponseType()); + System.out.println("Response total results : "+response.totalResults()); + + /** + * viewAs methods return an optional, since it's uncertain what the data type inside APIResponse.getData is + */ + List newsSources = response.viewAsNewsSources().orElseGet(Collections::emptyList); + + /** + * Let's say we wanted to be extra cool and printed only the news sources that specialize in sports + */ + newsSources.stream() + .filter(nSource -> nSource.getCategory() == Category.Sports) + .forEach(System.out::println); + + + } + +} diff --git a/src/com/vlad/newsapi4j/model/Article.java b/src/com/vlad/newsapi4j/model/Article.java new file mode 100644 index 0000000..80a69e0 --- /dev/null +++ b/src/com/vlad/newsapi4j/model/Article.java @@ -0,0 +1,173 @@ +package com.vlad.newsapi4j.model; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.json.JSONException; +import org.json.JSONObject; + +public class Article implements java.io.Serializable { + + /** + * + */ + private static final long serialVersionUID = 4316843304782307619L; + + private Source source; + + private String author; + + private String title; + + private String description; + + private String url, urlToImage; + + private Date publishedAt; + + public Article(JSONObject from) { + this.deserialize(from); + } + + private void deserialize(JSONObject from) { + try { + JSONObject source = from.getJSONObject("source"); + this.source = new Source(source.getString("id"), source.getString("name")); + this.author = from.getString("author"); + this.title = from.getString("title"); + this.description = from.getString("description"); + this.url = from.getString("url"); + this.urlToImage = from.getString("urlToImage"); + String publishedAt = from.getString("publishedAt"); + if (publishedAt != null) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + this.publishedAt = sdf.parse(publishedAt); + } + } catch (JSONException | ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public String getAuthor() { + return author; + } + + public String getDescription() { + return description; + } + + public Date getPublishedAt() { + return publishedAt; + } + + public Source getSource() { + return source; + } + + public String getTitle() { + return title; + } + + public String getUrl() { + return url; + } + + public String getUrlToImage() { + return urlToImage; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((author == null) ? 0 : author.hashCode()); + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((publishedAt == null) ? 0 : publishedAt.hashCode()); + result = prime * result + ((source == null) ? 0 : source.hashCode()); + result = prime * result + ((title == null) ? 0 : title.hashCode()); + result = prime * result + ((url == null) ? 0 : url.hashCode()); + result = prime * result + ((urlToImage == null) ? 0 : urlToImage.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Article other = (Article) obj; + if (author == null) { + if (other.author != null) + return false; + } else if (!author.equals(other.author)) + return false; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (publishedAt == null) { + if (other.publishedAt != null) + return false; + } else if (!publishedAt.equals(other.publishedAt)) + return false; + if (source == null) { + if (other.source != null) + return false; + } else if (!source.equals(other.source)) + return false; + if (title == null) { + if (other.title != null) + return false; + } else if (!title.equals(other.title)) + return false; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + if (urlToImage == null) { + if (other.urlToImage != null) + return false; + } else if (!urlToImage.equals(other.urlToImage)) + return false; + return true; + } + + @Override + public String toString() { + return "Article [source=" + source + ", author=" + author + ", title=" + title + ", description=" + description + + ", url=" + url + ", urlToImage=" + urlToImage + ", publishedAt=" + publishedAt + "]"; + } + + public class Source { + + private String id; + private String name; + + public Source(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Source [id=" + id + ", name=" + name + "]"; + } + + } + +} diff --git a/src/com/vlad/newsapi4j/model/NewsSource.java b/src/com/vlad/newsapi4j/model/NewsSource.java new file mode 100644 index 0000000..9410e8e --- /dev/null +++ b/src/com/vlad/newsapi4j/model/NewsSource.java @@ -0,0 +1,136 @@ +package com.vlad.newsapi4j.model; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.vlad.newsapi4j.utils.Category; + +public class NewsSource implements java.io.Serializable { + + /** + * + */ + private static final long serialVersionUID = -5784025163604945320L; + + private String id; + private String name; + private String description; + private String url; + private Category category; + private String language, country; + + public NewsSource(JSONObject from) { + this.deserialize(from); + } + + private void deserialize(JSONObject from) { + try { + this.id = from.getString("id"); + this.name = from.getString("name"); + this.description = from.getString("description"); + this.url = from.getString("url"); + this.category = Category.parse(from.getString("category")); + this.language = from.getString("language"); + this.country = from.getString("country"); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public Category getCategory() { + return category; + } + + public String getCountry() { + return country; + } + + public String getDescription() { + return description; + } + + public String getId() { + return id; + } + + public String getLanguage() { + return language; + } + + public String getName() { + return name; + } + + public String getUrl() { + return url; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((category == null) ? 0 : category.hashCode()); + result = prime * result + ((country == null) ? 0 : country.hashCode()); + result = prime * result + ((description == null) ? 0 : description.hashCode()); + result = prime * result + ((id == null) ? 0 : id.hashCode()); + result = prime * result + ((language == null) ? 0 : language.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((url == null) ? 0 : url.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + NewsSource other = (NewsSource) obj; + if (category != other.category) + return false; + if (country == null) { + if (other.country != null) + return false; + } else if (!country.equals(other.country)) + return false; + if (description == null) { + if (other.description != null) + return false; + } else if (!description.equals(other.description)) + return false; + if (id == null) { + if (other.id != null) + return false; + } else if (!id.equals(other.id)) + return false; + if (language == null) { + if (other.language != null) + return false; + } else if (!language.equals(other.language)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (url == null) { + if (other.url != null) + return false; + } else if (!url.equals(other.url)) + return false; + return true; + } + + @Override + public String toString() { + return "NewsSource [id=" + id + ", name=" + name + ", description=" + description + ", url=" + url + + ", category=" + category + ", language=" + language + ", country=" + country + "]"; + } + + + + +} diff --git a/src/com/vlad/newsapi4j/response/APIResponse.java b/src/com/vlad/newsapi4j/response/APIResponse.java new file mode 100644 index 0000000..4aaba41 --- /dev/null +++ b/src/com/vlad/newsapi4j/response/APIResponse.java @@ -0,0 +1,70 @@ +package com.vlad.newsapi4j.response; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.json.JSONObject; + +import com.vlad.newsapi4j.model.Article; +import com.vlad.newsapi4j.model.NewsSource; +import com.vlad.newsapi4j.utils.ResponseStatus; + +/** + * Returned by querying newsapi + */ +public interface APIResponse { + + public enum Type { + SOURCES, + + ARTICLES + } + + /** + * Returned whenever the 'totalResults' info is unavailable + */ + int INFORMATION_UNAVAILABLE = -0xff; + + /** + * @return the json object obtained; + */ + JSONObject getJSON(); + + /** + * Returns the status of the request + */ + ResponseStatus getStatus(); + + /** + * Returns the type of information the object is holding + * + * @return + */ + APIResponse.Type getResponseType(); + + /** + * @return either the total amount of elements collected by the query or + * IAPIRespnse.INFORMATION_UNAVAILABLE + */ + int totalResults(); + + /** + * @return a list view of the jsonArray containing all the items queried
+ * + */ + java.util.List getData(); + + default Optional> viewAsArticles() { + if (getResponseType() != Type.ARTICLES) + return Optional.empty(); + return Optional.of(getData().stream().map(Article::new).collect(Collectors.toList())); + } + + default Optional> viewAsNewsSources() { + if (getResponseType() != Type.SOURCES) + return Optional.empty(); + return Optional.of(getData().stream().map(NewsSource::new).collect(Collectors.toList())); + } + +} diff --git a/src/com/vlad/newsapi4j/service/Endpoint.java b/src/com/vlad/newsapi4j/service/Endpoint.java new file mode 100644 index 0000000..4abf8ec --- /dev/null +++ b/src/com/vlad/newsapi4j/service/Endpoint.java @@ -0,0 +1,38 @@ +package com.vlad.newsapi4j.service; + +/** + * + * Enum representing the different news query types + * + */ +public enum Endpoint { + + /** + * Info from here
+ *
+ * + * All options passed are optional, however at least one must be included, in + * order to
+ * query top-headlines + */ + TOP_HEADLINES, + /** + * Info from here
+ *
+ * + * No options are mandatory for a sources request + * + */ + SOURCES, + + /** + * Info from here
+ *
+ * + * To query everything, you must include at least a keyword,
+ * source or domain + * + */ + EVERYTHING + +} diff --git a/src/com/vlad/newsapi4j/service/IAsyncService.java b/src/com/vlad/newsapi4j/service/IAsyncService.java new file mode 100644 index 0000000..cb3b26e --- /dev/null +++ b/src/com/vlad/newsapi4j/service/IAsyncService.java @@ -0,0 +1,178 @@ +package com.vlad.newsapi4j.service; + +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.utils.Callback; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.DateRange; + +public interface IAsyncService { + /** + * Set the lookup sources
+ * such as abc-news, bbc, cnn, etc + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param sources + * @return + */ + IAsyncService withSources(String... sources); + + /** + * Set the lookup domains
+ * example : (techcrunch.com, bbc.co.uk) + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param domains + * @return + */ + IAsyncService withDomains(String... domains); + + /** + * Set the searched keyword + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param keyword + * @return + */ + IAsyncService withKeyword(String keyword); + + /** + * Filters the news given a category + * + *
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param category + * @return + */ + IAsyncService withCategory(Category category); + + /** + * Sets the language
+ * eg : find all articles written in English.
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param lang + * @return + */ + IAsyncService language(String lang); + + /** + * Sort the results by
+ * Date
+ * Relevancy to search keyword
+ * Popularity of source
+ *
+ * + * For more information, visit NewsAPI's official website + * here
+ * + * @see {@link SortBy} + * @param sortBy + * @return + */ + IAsyncService sortBy(String sortBy); + + /** + * Sets the country of origin
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param country + * @return + */ + IAsyncService country(String country); + + /** + * Sets the lookup page
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param page + * @return + */ + IAsyncService page(int page); + + /** + * Sets the 'to' date
+ * i.e every request after to will be ignored
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param to + * @return + */ + IAsyncService to(java.util.Date to); + + /** + * Sets the 'from' date
+ * i.e every request before from will be ignored
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param from + * @return + */ + IAsyncService from(java.util.Date date); + + /** + * Sets the range of the news (both from and to) + * + *
+ * For more information, visit NewsAPI's official website + * here + * @param range + * @return + */ + IAsyncService dateRange(java.util.function.Supplier range); + + + /** + * Supplies the AsyncService object with the given api key and + * endpoint
+ * Not meant to be used by the user of the API + * + * @param apiKey + * @param endpoint + * @return + */ + IAsyncService prepare(String apiKey, Endpoint endpoint); + + /** + * Sends the request to the newsapi server on a new thread
+ * returns either the result in a callback or the error that occured + * + * @param result + * @param onError + */ + void send(Callback result, Callback onError); + +} diff --git a/src/com/vlad/newsapi4j/service/IService.java b/src/com/vlad/newsapi4j/service/IService.java new file mode 100644 index 0000000..5420fc6 --- /dev/null +++ b/src/com/vlad/newsapi4j/service/IService.java @@ -0,0 +1,173 @@ +package com.vlad.newsapi4j.service; + +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.DateRange; +import com.vlad.newsapi4j.utils.NewsAPIException; + +public interface IService { + + /** + * Set the lookup sources
+ * such as abc-news, bbc, cnn, etc
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param sources + * @return + */ + IService withSources(String... sources); + + /** + * Set the lookup domains
+ * example : (techcrunch.com, bbc.co.uk)
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param domains + * @return + */ + IService withDomains(String... domains); + + /** + * Set the searched keyword
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param keyword + * @return + */ + IService withKeyword(String keyword); + + /** + * Filters the news given a category
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param category + * @return + */ + IService withCategory(Category category); + + /** + * Sets the language
+ * eg : find all articles written in English.
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param lang + * @return + */ + IService language(String lang); + + /** + * Sort the results by
+ * Date
+ * Relevancy to search keyword
+ * Popularity of source
+ *
+ * + * For more information, visit NewsAPI's official website + * here
+ * + * @see {@link SortBy} + * @param sortBy + * @return + */ + IService sortBy(String sortBy); + + /** + * Sets the country of origin
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param country + * @return + */ + IService country(String country); + + /** + * Sets the lookup page
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param page + * @return + */ + IService page(int page); + + /** + * Sets the 'to' date
+ * i.e every request after to will be ignored
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param to + * @return + */ + IService to(java.util.Date to); + + /** + * Sets the 'from' date
+ * i.e every request before from will be ignored
+ *
+ * + * For more information, visit NewsAPI's official website + * here + * + * @param from + * @return + */ + IService from(java.util.Date date); + + /** + * Sets the range of the news (both from and to) + * + *
+ * For more information, visit NewsAPI's official website + * here + * @param range + * @return + */ + IService range(java.util.function.Supplier range); + + /** + * Sends the request to the newsapi server and returns the result
+ *
+ * + * + * @return + * @throws NewsAPIException + * if anything went wrong
+ * i.e wrong request, etc. + */ + APIResponse send() throws NewsAPIException; + + /** + * Supplies the Service object with the given api key and + * endpoint
+ * Not meant to be used by the user of the API + * + * @param apiKey + * @param endpoint + * @return + */ + IService prepare(String apiKey, Endpoint endpoint); + +} diff --git a/src/com/vlad/newsapi4j/service/SortBy.java b/src/com/vlad/newsapi4j/service/SortBy.java new file mode 100644 index 0000000..698068e --- /dev/null +++ b/src/com/vlad/newsapi4j/service/SortBy.java @@ -0,0 +1,11 @@ +package com.vlad.newsapi4j.service; + +public interface SortBy { + + String RELEVANCE = "relevance"; + + String POPULARITY = "popularity"; + + String DATE = "date"; + +} diff --git a/src/com/vlad/newsapi4j/utils/Callback.java b/src/com/vlad/newsapi4j/utils/Callback.java new file mode 100644 index 0000000..3684728 --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/Callback.java @@ -0,0 +1,8 @@ +package com.vlad.newsapi4j.utils; + +@FunctionalInterface +public interface Callback { + + void invoke(T t); + +} diff --git a/src/com/vlad/newsapi4j/utils/Category.java b/src/com/vlad/newsapi4j/utils/Category.java new file mode 100644 index 0000000..f22c2a5 --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/Category.java @@ -0,0 +1,27 @@ +package com.vlad.newsapi4j.utils; + +public enum Category { + + Business, Entertainment, Health, Science, Sports, Technology, General; + + public String toLink() { + return this.name().toLowerCase(); + } + + public static Category parse(String category) { + if (category.equalsIgnoreCase(Category.Business.name())) + return Category.Business; + if (category.equalsIgnoreCase(Category.Entertainment.name())) + return Category.Entertainment; + if (category.equalsIgnoreCase(Category.Health.name())) + return Category.Health; + if (category.equalsIgnoreCase(Category.Science.name())) + return Category.Science; + if (category.equalsIgnoreCase(Category.Sports.name())) + return Category.Sports; + if (category.equalsIgnoreCase(Category.Technology.name())) + return Category.Technology; + return Category.General; + } + +} diff --git a/src/com/vlad/newsapi4j/utils/DateRange.java b/src/com/vlad/newsapi4j/utils/DateRange.java new file mode 100644 index 0000000..8a47604 --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/DateRange.java @@ -0,0 +1,39 @@ +package com.vlad.newsapi4j.utils; + +import java.util.Date; + +public class DateRange { + + private Date from, to; + + public DateRange(Date from, Date to) { + this.from = from; + System.out.println("from :: "+from); + this.to = to; + } + + public static final DateRange SINCE_YESTERDAY() { + return new DateRange(new Date(System.currentTimeMillis() - 3600 * 1000 * 24), new Date()); + } + + public static final DateRange LAST_7_DAYS() { + return new DateRange(new Date(System.currentTimeMillis() - 3600 * 1000 * 24 * 7), new Date()); + } + + public static final DateRange LAST_30_DAYS() { + return new DateRange(new Date(System.currentTimeMillis() - 3600 * 1000 * 24 * 30), new Date()); + } + + public static final DateRange LAST_100_DAYS() { + return new DateRange(new Date(System.currentTimeMillis() - 3600 * 1000 * 24 * 100), new Date()); + } + + public Date getFrom() { + return from; + } + + public Date getTo() { + return to; + } + +} diff --git a/src/com/vlad/newsapi4j/utils/LinkBuilder.java b/src/com/vlad/newsapi4j/utils/LinkBuilder.java new file mode 100644 index 0000000..4b0f247 --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/LinkBuilder.java @@ -0,0 +1,129 @@ +package com.vlad.newsapi4j.utils; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.stream.Collectors; + +import com.vlad.newsapi4j.service.Endpoint; + +public class LinkBuilder { + + public static final String NEWSAPI_LINK = "https://newsapi.org/v2/"; + + private StringBuilder current = new StringBuilder(NEWSAPI_LINK); + private boolean firstAddition = true; + + private Endpoint endPoint; + + public LinkBuilder(Endpoint ePoint) { + current.append( + ePoint == Endpoint.EVERYTHING ? "everything" + : + ePoint == Endpoint.TOP_HEADLINES ? "top-headlines" : "sources"); + current.append('?'); + this.endPoint = ePoint; + } + + public LinkBuilder sources(String... sources) { + addTag("sources"); + current.append(join(sources)); + return this; + } + + public LinkBuilder domains(String... domains) { + addTag("domains"); + current.append(join(domains)); + return this; + } + + public LinkBuilder category(String category) { + addTag("category"); + current.append(category); + return this; + } + + private void addTag(String tag) { + if (firstAddition) { + current.append(tag).append('='); + firstAddition = false; + } else + current.append('&').append(tag).append('='); + } + + public LinkBuilder language(String lang) { + addTag("language"); + current.append(lang); + return this; + } + + private CharSequence join(String... strings) { + return Arrays.stream(strings) + .collect(Collectors.joining(",")); + } + + @Override + public String toString() { + return current.toString(); + } + + public LinkBuilder keyword(String string) { + addTag("q"); + current.append(string); + return this; + } + + public LinkBuilder finish(String apiKey) { + addTag("apiKey"); + current.append(apiKey); + return this; + } + + public LinkBuilder country(String country) { + if (endPoint == Endpoint.EVERYTHING) + throw new NewsAPIRuntimeException("Cannot use an everything request with a country"); + addTag("country"); + current.append(country); + return this; + } + + public LinkBuilder sortBy(String sortBy) { + addTag("sortBy"); + current.append(sortBy); + return this; + } + + public LinkBuilder page(int page) { + addTag("page"); + current.append(page); + return this; + } + + /* + * YY-MM-DD + */ + public LinkBuilder from(Date from) { + Calendar c = Calendar.getInstance(); + c.setTime(from); + int dd = c.get(Calendar.DAY_OF_MONTH); + int yy = c.get(Calendar.YEAR); + int mm = c.get(Calendar.MONTH) + 1; + addTag("from"); + current.append(yy).append('-').append((String.valueOf(mm).length() != 2 ? "0" : "") + mm).append('-').append( + String.valueOf(dd).length() != 2 ? "0" : "" + dd); + return this; + } + + public LinkBuilder to(Date to) { + Calendar c = Calendar.getInstance(); + c.setTime(to); + int dd = c.get(Calendar.DAY_OF_MONTH); + int yy = c.get(Calendar.YEAR); + int mm = c.get(Calendar.MONTH) + 1; + addTag("to"); + current.append(yy).append('-').append((String.valueOf(mm).length() != 2 ? "0" : "") + mm).append('-').append( + String.valueOf(dd).length() != 2 ? "0" : "" + dd); + return this; + } + +} diff --git a/src/com/vlad/newsapi4j/utils/NewsAPIException.java b/src/com/vlad/newsapi4j/utils/NewsAPIException.java new file mode 100644 index 0000000..571901f --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/NewsAPIException.java @@ -0,0 +1,14 @@ +package com.vlad.newsapi4j.utils; + +public class NewsAPIException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -7569894523616376122L; + + public NewsAPIException(String message) { + super(message); + } + +} diff --git a/src/com/vlad/newsapi4j/utils/NewsAPIRuntimeException.java b/src/com/vlad/newsapi4j/utils/NewsAPIRuntimeException.java new file mode 100644 index 0000000..08770e6 --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/NewsAPIRuntimeException.java @@ -0,0 +1,14 @@ +package com.vlad.newsapi4j.utils; + +public class NewsAPIRuntimeException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = 6895946820744739720L; + + public NewsAPIRuntimeException(String message) { + super(message); + } + +} diff --git a/src/com/vlad/newsapi4j/utils/ResponseStatus.java b/src/com/vlad/newsapi4j/utils/ResponseStatus.java new file mode 100644 index 0000000..f059489 --- /dev/null +++ b/src/com/vlad/newsapi4j/utils/ResponseStatus.java @@ -0,0 +1,9 @@ +package com.vlad.newsapi4j.utils; + +public enum ResponseStatus { + + OK, + + ERROR + +} From 1c1619deaaff499f713bf43bed0881eb98c1c04f Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 14:11:06 +0300 Subject: [PATCH 02/13] Removed examples from package --- .../vlad/newsapi4j/examples/Asynchronous.java | 49 ----- src/com/vlad/newsapi4j/examples/Custom.java | 188 ------------------ src/com/vlad/newsapi4j/examples/Standart.java | 43 ---- 3 files changed, 280 deletions(-) delete mode 100644 src/com/vlad/newsapi4j/examples/Asynchronous.java delete mode 100644 src/com/vlad/newsapi4j/examples/Custom.java delete mode 100644 src/com/vlad/newsapi4j/examples/Standart.java diff --git a/src/com/vlad/newsapi4j/examples/Asynchronous.java b/src/com/vlad/newsapi4j/examples/Asynchronous.java deleted file mode 100644 index c04b325..0000000 --- a/src/com/vlad/newsapi4j/examples/Asynchronous.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.vlad.newsapi4j.examples; - -import java.util.Collections; -import java.util.Date; -import java.util.List; - -import com.vlad.newsapi4j.client.NewsApiClient; -import com.vlad.newsapi4j.model.Article; -import com.vlad.newsapi4j.service.SortBy; - -public class Asynchronous { - - public static void main(String[] args) { - NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); - /** - * Create the asynchronous request and supply with information - * Get the top headlines in the us today, sort them by date, show the first page(optional it's 1 by default) - */ - client.newTopHeadlinesServiceAsync() - .country("us") - .from(new Date()) - .sortBy(SortBy.DATE) - .page(1) - /** - * send method gets called either with the result callback or with the error one - */ - .send(result -> { - /** - * We are here, everything is fine - */ - List
articles = result.viewAsArticles().orElseGet(Collections::emptyList); - /** - * Get all articles whose author starts with the letter 'a', coz why not :D - */ - articles.stream() - .filter(article -> article.getAuthor().startsWith("A")) - .forEach(System.out::println); - - }, /** - * We are here, something went wrong, just print the cause - */ - Throwable::printStackTrace); - /** - * Program flow continues freely - */ - System.out.println("Yay, running concurrently"); - } - -} diff --git a/src/com/vlad/newsapi4j/examples/Custom.java b/src/com/vlad/newsapi4j/examples/Custom.java deleted file mode 100644 index eae3e7b..0000000 --- a/src/com/vlad/newsapi4j/examples/Custom.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.vlad.newsapi4j.examples; - -import java.util.Date; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import org.json.JSONException; -import org.json.JSONObject; - -import com.vlad.newsapi4j.access.APIConnection; -import com.vlad.newsapi4j.client.NewsApiClient; -import com.vlad.newsapi4j.client.Response; -import com.vlad.newsapi4j.model.Article; -import com.vlad.newsapi4j.response.APIResponse; -import com.vlad.newsapi4j.service.Endpoint; -import com.vlad.newsapi4j.service.IAsyncService; -import com.vlad.newsapi4j.utils.Callback; -import com.vlad.newsapi4j.utils.Category; -import com.vlad.newsapi4j.utils.DateRange; -import com.vlad.newsapi4j.utils.LinkBuilder; -import com.vlad.newsapi4j.utils.NewsAPIException; -import com.vlad.newsapi4j.utils.ResponseStatus; - -public class Custom { - - public static void main(String[] args) { - NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); - client.newCustomAsyncService(new MyCustomAsyncService(), Endpoint.EVERYTHING) - .withKeyword("Youtube") - .language("en") - /** - * I HAD to break convention (All caps methods and all that), just look at how beautiful this looks - */ - .dateRange(DateRange::LAST_7_DAYS) - .send(result -> { - System.out.println("Result matches : " + result.totalResults()); - /** - * Find the first article that has an author ? - */ - Article a = result.viewAsArticles() - .get() - .stream() - .filter(article -> article.getAuthor() != null) - .findFirst() - .orElse(null); - System.out.println(a); - }, Throwable::printStackTrace); - - } - - private static class MyCustomAsyncService implements IAsyncService { - - private String apiKey; - - private Endpoint endpoint; - - private LinkBuilder link; - - public MyCustomAsyncService() { - - } - - @Override - public IAsyncService withSources(String... sources) { - link.sources(sources); - return this; - } - - @Override - public IAsyncService withDomains(String... domains) { - link.domains(domains); - return this; - } - - @Override - public IAsyncService withKeyword(String keyword) { - link.keyword(keyword); - return this; - } - - @Override - public IAsyncService withCategory(Category category) { - link.category(category.toLink()); - return this; - } - - @Override - public IAsyncService language(String lang) { - link.language(lang); - return this; - } - - @Override - public IAsyncService sortBy(String sortBy) { - link.sortBy(sortBy); - return this; - } - - @Override - public IAsyncService country(String country) { - link.country(country); - return this; - } - - @Override - public IAsyncService page(int page) { - link.page(page); - return this; - } - - @Override - public IAsyncService to(Date to) { - link.to(to); - return this; - } - - @Override - public IAsyncService from(Date date) { - link.from(date); - return this; - } - - @Override - public IAsyncService prepare(String apiKey, Endpoint endpoint) { - this.apiKey = apiKey; - this.endpoint = endpoint; - this.link = new LinkBuilder(endpoint); - return this; - } - - - - @Override - public void send(Callback result, Callback onError) { - new Thread(() -> { - link.finish(apiKey); - String content = new APIConnection(link).getContents(); - int totalRes = APIResponse.INFORMATION_UNAVAILABLE; - JSONObject obj = null; - try { - obj = new JSONObject(content); - // System.out.println(obj); - } catch (JSONException e1) { - // throw new NewsAPIException("Something went wrong while parsing json"); - e1.printStackTrace(); - } - - System.out.println(link); - ResponseStatus status = ResponseStatus.OK; - /** - * Returns at least an empty string, not null - */ - try { - if (obj.getString("status").equals("error") || content.equals("")) { - status = ResponseStatus.ERROR; - String message = ""; - try { - message = obj.getString("message"); - } catch (JSONException e) { - onError.invoke(new NewsAPIException("Something went wrong while parsing json")); - } - onError.invoke(new NewsAPIException(message)); - } - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - if (endpoint != Endpoint.SOURCES) - try { - totalRes = obj.getInt("totalResults"); - } catch (JSONException e) { - onError.invoke(new NewsAPIException("Something went wrong while parsing json")); - } - result.invoke(new Response(endpoint, content, status, totalRes)); - }).start(); - } - - @Override - public IAsyncService dateRange(Supplier range) { - this.link.from(range.get().getFrom()); - this.link.to(range.get().getTo()); - return this; - } - - } - -} diff --git a/src/com/vlad/newsapi4j/examples/Standart.java b/src/com/vlad/newsapi4j/examples/Standart.java deleted file mode 100644 index 1c28283..0000000 --- a/src/com/vlad/newsapi4j/examples/Standart.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.vlad.newsapi4j.examples; - -import java.util.Collections; -import java.util.List; - -import com.vlad.newsapi4j.client.NewsApiClient; -import com.vlad.newsapi4j.model.NewsSource; -import com.vlad.newsapi4j.response.APIResponse; -import com.vlad.newsapi4j.service.SortBy; -import com.vlad.newsapi4j.utils.Category; -import com.vlad.newsapi4j.utils.NewsAPIException; - -public class Standart { - - public static void main(String[] args) throws NewsAPIException { - NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); - /** - * Wait and receive response from server - */ - APIResponse response = client.newSourcesService() - .withKeyword("bulgaria") - .sortBy(SortBy.POPULARITY) - .send(); - - System.out.println("Response type : "+response.getResponseType()); - System.out.println("Response total results : "+response.totalResults()); - - /** - * viewAs methods return an optional, since it's uncertain what the data type inside APIResponse.getData is - */ - List newsSources = response.viewAsNewsSources().orElseGet(Collections::emptyList); - - /** - * Let's say we wanted to be extra cool and printed only the news sources that specialize in sports - */ - newsSources.stream() - .filter(nSource -> nSource.getCategory() == Category.Sports) - .forEach(System.out::println); - - - } - -} From 3118cf1e97e940e8685ecdeaeddc3881d2a647ce Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 14:12:09 +0300 Subject: [PATCH 03/13] Added examples folder --- examples/Asynchronous.java | 49 ++++++++++ examples/Custom.java | 188 +++++++++++++++++++++++++++++++++++++ examples/Standart.java | 43 +++++++++ 3 files changed, 280 insertions(+) create mode 100644 examples/Asynchronous.java create mode 100644 examples/Custom.java create mode 100644 examples/Standart.java diff --git a/examples/Asynchronous.java b/examples/Asynchronous.java new file mode 100644 index 0000000..b4e5fae --- /dev/null +++ b/examples/Asynchronous.java @@ -0,0 +1,49 @@ +package com.vlad.newsapi4j.examples; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import com.vlad.newsapi4j.client.NewsApiClient; +import com.vlad.newsapi4j.model.Article; +import com.vlad.newsapi4j.service.SortBy; + +public class Asynchronous { + + public static void main(String[] args) { + NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); + /** + * Create the asynchronous request and supply with information + * Get the top headlines in the us today, sort them by date, show the first page(optional it's 1 by default) + */ + client.newTopHeadlinesServiceAsync() + .country("bg") + .from(new Date()) + .sortBy(SortBy.DATE) + .page(1) + /** + * send method gets called either with the result callback or with the error one + */ + .send(result -> { + /** + * We are here, everything is fine + */ + List
articles = result.viewAsArticles().orElseGet(Collections::emptyList); + /** + * Get all articles whose author starts with the letter 'a', coz why not :D + */ + articles.stream() +// .filter(article -> article.getAuthor().startsWith("A")) + .forEach(article -> System.out.println(article.getDescription())); + + }, /** + * We are here, something went wrong, just print the cause + */ + Throwable::printStackTrace); + /** + * Program flow continues freely + */ + System.out.println("Yay, running concurrently"); + } + +} diff --git a/examples/Custom.java b/examples/Custom.java new file mode 100644 index 0000000..eae3e7b --- /dev/null +++ b/examples/Custom.java @@ -0,0 +1,188 @@ +package com.vlad.newsapi4j.examples; + +import java.util.Date; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.vlad.newsapi4j.access.APIConnection; +import com.vlad.newsapi4j.client.NewsApiClient; +import com.vlad.newsapi4j.client.Response; +import com.vlad.newsapi4j.model.Article; +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.service.IAsyncService; +import com.vlad.newsapi4j.utils.Callback; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.DateRange; +import com.vlad.newsapi4j.utils.LinkBuilder; +import com.vlad.newsapi4j.utils.NewsAPIException; +import com.vlad.newsapi4j.utils.ResponseStatus; + +public class Custom { + + public static void main(String[] args) { + NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); + client.newCustomAsyncService(new MyCustomAsyncService(), Endpoint.EVERYTHING) + .withKeyword("Youtube") + .language("en") + /** + * I HAD to break convention (All caps methods and all that), just look at how beautiful this looks + */ + .dateRange(DateRange::LAST_7_DAYS) + .send(result -> { + System.out.println("Result matches : " + result.totalResults()); + /** + * Find the first article that has an author ? + */ + Article a = result.viewAsArticles() + .get() + .stream() + .filter(article -> article.getAuthor() != null) + .findFirst() + .orElse(null); + System.out.println(a); + }, Throwable::printStackTrace); + + } + + private static class MyCustomAsyncService implements IAsyncService { + + private String apiKey; + + private Endpoint endpoint; + + private LinkBuilder link; + + public MyCustomAsyncService() { + + } + + @Override + public IAsyncService withSources(String... sources) { + link.sources(sources); + return this; + } + + @Override + public IAsyncService withDomains(String... domains) { + link.domains(domains); + return this; + } + + @Override + public IAsyncService withKeyword(String keyword) { + link.keyword(keyword); + return this; + } + + @Override + public IAsyncService withCategory(Category category) { + link.category(category.toLink()); + return this; + } + + @Override + public IAsyncService language(String lang) { + link.language(lang); + return this; + } + + @Override + public IAsyncService sortBy(String sortBy) { + link.sortBy(sortBy); + return this; + } + + @Override + public IAsyncService country(String country) { + link.country(country); + return this; + } + + @Override + public IAsyncService page(int page) { + link.page(page); + return this; + } + + @Override + public IAsyncService to(Date to) { + link.to(to); + return this; + } + + @Override + public IAsyncService from(Date date) { + link.from(date); + return this; + } + + @Override + public IAsyncService prepare(String apiKey, Endpoint endpoint) { + this.apiKey = apiKey; + this.endpoint = endpoint; + this.link = new LinkBuilder(endpoint); + return this; + } + + + + @Override + public void send(Callback result, Callback onError) { + new Thread(() -> { + link.finish(apiKey); + String content = new APIConnection(link).getContents(); + int totalRes = APIResponse.INFORMATION_UNAVAILABLE; + JSONObject obj = null; + try { + obj = new JSONObject(content); + // System.out.println(obj); + } catch (JSONException e1) { + // throw new NewsAPIException("Something went wrong while parsing json"); + e1.printStackTrace(); + } + + System.out.println(link); + ResponseStatus status = ResponseStatus.OK; + /** + * Returns at least an empty string, not null + */ + try { + if (obj.getString("status").equals("error") || content.equals("")) { + status = ResponseStatus.ERROR; + String message = ""; + try { + message = obj.getString("message"); + } catch (JSONException e) { + onError.invoke(new NewsAPIException("Something went wrong while parsing json")); + } + onError.invoke(new NewsAPIException(message)); + } + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + if (endpoint != Endpoint.SOURCES) + try { + totalRes = obj.getInt("totalResults"); + } catch (JSONException e) { + onError.invoke(new NewsAPIException("Something went wrong while parsing json")); + } + result.invoke(new Response(endpoint, content, status, totalRes)); + }).start(); + } + + @Override + public IAsyncService dateRange(Supplier range) { + this.link.from(range.get().getFrom()); + this.link.to(range.get().getTo()); + return this; + } + + } + +} diff --git a/examples/Standart.java b/examples/Standart.java new file mode 100644 index 0000000..1c28283 --- /dev/null +++ b/examples/Standart.java @@ -0,0 +1,43 @@ +package com.vlad.newsapi4j.examples; + +import java.util.Collections; +import java.util.List; + +import com.vlad.newsapi4j.client.NewsApiClient; +import com.vlad.newsapi4j.model.NewsSource; +import com.vlad.newsapi4j.response.APIResponse; +import com.vlad.newsapi4j.service.SortBy; +import com.vlad.newsapi4j.utils.Category; +import com.vlad.newsapi4j.utils.NewsAPIException; + +public class Standart { + + public static void main(String[] args) throws NewsAPIException { + NewsApiClient client = new NewsApiClient("99827975269246bc91c1780b77e7e008"); + /** + * Wait and receive response from server + */ + APIResponse response = client.newSourcesService() + .withKeyword("bulgaria") + .sortBy(SortBy.POPULARITY) + .send(); + + System.out.println("Response type : "+response.getResponseType()); + System.out.println("Response total results : "+response.totalResults()); + + /** + * viewAs methods return an optional, since it's uncertain what the data type inside APIResponse.getData is + */ + List newsSources = response.viewAsNewsSources().orElseGet(Collections::emptyList); + + /** + * Let's say we wanted to be extra cool and printed only the news sources that specialize in sports + */ + newsSources.stream() + .filter(nSource -> nSource.getCategory() == Category.Sports) + .forEach(System.out::println); + + + } + +} From ad6bd87901d72a767b24e29bfc7dfa965026ac0f Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 14:32:41 +0300 Subject: [PATCH 04/13] Renamed Response --- .../client/{Response.java => ResponseImpl.java} | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) rename src/com/vlad/newsapi4j/client/{Response.java => ResponseImpl.java} (82%) diff --git a/src/com/vlad/newsapi4j/client/Response.java b/src/com/vlad/newsapi4j/client/ResponseImpl.java similarity index 82% rename from src/com/vlad/newsapi4j/client/Response.java rename to src/com/vlad/newsapi4j/client/ResponseImpl.java index 945c4ba..3e3e3df 100644 --- a/src/com/vlad/newsapi4j/client/Response.java +++ b/src/com/vlad/newsapi4j/client/ResponseImpl.java @@ -11,7 +11,7 @@ import com.vlad.newsapi4j.service.Endpoint; import com.vlad.newsapi4j.utils.ResponseStatus; -public class Response implements APIResponse { +public class ResponseImpl implements APIResponse { private ResponseStatus status; private int totalRes; @@ -19,7 +19,7 @@ public class Response implements APIResponse { private List list; private Endpoint endpoint; - public Response(Endpoint reqType, String content, ResponseStatus status, int totalRes) { + public ResponseImpl(Endpoint reqType, String content, ResponseStatus status, int totalRes) { this.totalRes = totalRes; this.status = status; List dataActual = new ArrayList<>(); @@ -29,9 +29,7 @@ public Response(Endpoint reqType, String content, ResponseStatus status, int tot for (int i = 0; i < jsonData.length(); i++) { dataActual.add(jsonData.getJSONObject(i)); } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + } catch (JSONException ignored) { } this.list = dataActual; this.endpoint = reqType; @@ -48,7 +46,7 @@ public int totalResults() { } @Override - public JSONObject getJSON() { + public JSONObject getResponseRaw() { return content; } From 91f74d6d3e3f37b27882fbf32297d57361f95783 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 14:34:51 +0300 Subject: [PATCH 05/13] SortBy now is an enum, minor changes to services --- .../vlad/newsapi4j/service/IAsyncService.java | 2 +- src/com/vlad/newsapi4j/service/IService.java | 2 +- src/com/vlad/newsapi4j/service/SortBy.java | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/com/vlad/newsapi4j/service/IAsyncService.java b/src/com/vlad/newsapi4j/service/IAsyncService.java index cb3b26e..3312127 100644 --- a/src/com/vlad/newsapi4j/service/IAsyncService.java +++ b/src/com/vlad/newsapi4j/service/IAsyncService.java @@ -91,7 +91,7 @@ public interface IAsyncService { * @param sortBy * @return */ - IAsyncService sortBy(String sortBy); + IAsyncService sortBy(SortBy sortBy); /** * Sets the country of origin
diff --git a/src/com/vlad/newsapi4j/service/IService.java b/src/com/vlad/newsapi4j/service/IService.java index 5420fc6..9d8393c 100644 --- a/src/com/vlad/newsapi4j/service/IService.java +++ b/src/com/vlad/newsapi4j/service/IService.java @@ -84,7 +84,7 @@ public interface IService { * @param sortBy * @return */ - IService sortBy(String sortBy); + IService sortBy(SortBy sortBy); /** * Sets the country of origin
diff --git a/src/com/vlad/newsapi4j/service/SortBy.java b/src/com/vlad/newsapi4j/service/SortBy.java index 698068e..7084553 100644 --- a/src/com/vlad/newsapi4j/service/SortBy.java +++ b/src/com/vlad/newsapi4j/service/SortBy.java @@ -1,11 +1,19 @@ package com.vlad.newsapi4j.service; -public interface SortBy { +/** + * Indicates the response sort order + */ +public enum SortBy { - String RELEVANCE = "relevance"; + RELEVANCE, - String POPULARITY = "popularity"; + POPULARITY, - String DATE = "date"; + DATE; + + public String toLink() { + return this.name().toLowerCase(); + } + } From 1334f666972b13bd4b9908276602286ca2d66c55 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 14:36:40 +0300 Subject: [PATCH 06/13] Added the option to connect to the api with string as a link --- src/com/vlad/newsapi4j/access/APIConnection.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/vlad/newsapi4j/access/APIConnection.java b/src/com/vlad/newsapi4j/access/APIConnection.java index 48a709a..ee86757 100644 --- a/src/com/vlad/newsapi4j/access/APIConnection.java +++ b/src/com/vlad/newsapi4j/access/APIConnection.java @@ -14,6 +14,10 @@ public APIConnection(LinkBuilder link) { this.fromWhere = link.toString(); } + public APIConnection(String linkRaw) { + this.fromWhere = linkRaw; + } + private String fromWhere; public String getContents() { From 2e174555ab5c943309cf608a8b21c3cd9cde52b3 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 15:22:18 +0300 Subject: [PATCH 07/13] Fixed bug where dateRange returns null --- .../vlad/newsapi4j/client/StandartAsyncService.java | 8 +++++--- src/com/vlad/newsapi4j/client/StandartService.java | 11 +++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/com/vlad/newsapi4j/client/StandartAsyncService.java b/src/com/vlad/newsapi4j/client/StandartAsyncService.java index b47ff92..fd6878c 100644 --- a/src/com/vlad/newsapi4j/client/StandartAsyncService.java +++ b/src/com/vlad/newsapi4j/client/StandartAsyncService.java @@ -1,11 +1,13 @@ package com.vlad.newsapi4j.client; import java.util.Date; +import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; import com.vlad.newsapi4j.response.APIResponse; import com.vlad.newsapi4j.service.Endpoint; import com.vlad.newsapi4j.service.IAsyncService; +import com.vlad.newsapi4j.service.SortBy; import com.vlad.newsapi4j.utils.Callback; import com.vlad.newsapi4j.utils.Category; import com.vlad.newsapi4j.utils.DateRange; @@ -44,7 +46,7 @@ public IAsyncService language(String lang) { } @Override - public IAsyncService sortBy(String sortBy) { + public IAsyncService sortBy(SortBy sortBy) { stdService.sortBy(sortBy); return this; } @@ -98,8 +100,8 @@ public IAsyncService withCategory(Category category) { @Override public IAsyncService dateRange(Supplier range) { - // TODO Auto-generated method stub - return null; + stdService.dateRange(range); + return this; } diff --git a/src/com/vlad/newsapi4j/client/StandartService.java b/src/com/vlad/newsapi4j/client/StandartService.java index deb93e8..30bc84e 100644 --- a/src/com/vlad/newsapi4j/client/StandartService.java +++ b/src/com/vlad/newsapi4j/client/StandartService.java @@ -10,6 +10,7 @@ import com.vlad.newsapi4j.response.APIResponse; import com.vlad.newsapi4j.service.Endpoint; import com.vlad.newsapi4j.service.IService; +import com.vlad.newsapi4j.service.SortBy; import com.vlad.newsapi4j.utils.Category; import com.vlad.newsapi4j.utils.DateRange; import com.vlad.newsapi4j.utils.LinkBuilder; @@ -53,7 +54,7 @@ public IService language(String lang) { } @Override - public IService sortBy(String sortBy) { + public IService sortBy(SortBy sortBy) { link.sortBy(sortBy); return this; } @@ -85,7 +86,7 @@ public APIResponse send() throws NewsAPIException { /** * Connect to NewsAPI */ - System.out.println(link); + System.out.println("Sending API request to ["+link+"]..."); String content = new APIConnection(link).getContents(); int totalResults = APIResponse.INFORMATION_UNAVAILABLE; JSONObject obj = null; @@ -94,10 +95,8 @@ public APIResponse send() throws NewsAPIException { // System.out.println(obj); } catch (JSONException e1) { // throw new NewsAPIException("Something went wrong while parsing json"); - e1.printStackTrace(); } - System.out.println(link); ResponseStatus status = ResponseStatus.OK; /** * Returns at least an empty string, not null @@ -119,7 +118,7 @@ public APIResponse send() throws NewsAPIException { } catch (JSONException e) { throw new NewsAPIException("Something went wrong while parsing json"); } - return new Response(endpoint, content, status, totalResults); + return new ResponseImpl(endpoint, content, status, totalResults); } @Override @@ -143,7 +142,7 @@ public IService withCategory(Category category) { } @Override - public IService range(Supplier range) { + public IService dateRange(Supplier range) { link.from(range.get().getFrom()); link.to(range.get().getTo()); return this; From 5859396b22fc96026d21bda363b23d8ecb74a307 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 15:24:32 +0300 Subject: [PATCH 08/13] Fixed major bug concerning date requests --- src/com/vlad/newsapi4j/service/IService.java | 2 +- src/com/vlad/newsapi4j/utils/LinkBuilder.java | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/com/vlad/newsapi4j/service/IService.java b/src/com/vlad/newsapi4j/service/IService.java index 9d8393c..4dfddc4 100644 --- a/src/com/vlad/newsapi4j/service/IService.java +++ b/src/com/vlad/newsapi4j/service/IService.java @@ -145,7 +145,7 @@ public interface IService { * @param range * @return */ - IService range(java.util.function.Supplier range); + IService dateRange(java.util.function.Supplier range); /** * Sends the request to the newsapi server and returns the result
diff --git a/src/com/vlad/newsapi4j/utils/LinkBuilder.java b/src/com/vlad/newsapi4j/utils/LinkBuilder.java index 4b0f247..362fdf7 100644 --- a/src/com/vlad/newsapi4j/utils/LinkBuilder.java +++ b/src/com/vlad/newsapi4j/utils/LinkBuilder.java @@ -6,12 +6,17 @@ import java.util.stream.Collectors; import com.vlad.newsapi4j.service.Endpoint; +import com.vlad.newsapi4j.service.SortBy; +/** + * Utility class used for building the request link for NewsAPI + * + */ public class LinkBuilder { - public static final String NEWSAPI_LINK = "https://newsapi.org/v2/"; + public static final String NEWSAPI_LINK_V2 = "https://newsapi.org/v2/"; - private StringBuilder current = new StringBuilder(NEWSAPI_LINK); + private StringBuilder current = new StringBuilder(NEWSAPI_LINK_V2); private boolean firstAddition = true; private Endpoint endPoint; @@ -38,6 +43,8 @@ public LinkBuilder domains(String... domains) { } public LinkBuilder category(String category) { + if(endPoint == Endpoint.EVERYTHING) + throw new NewsAPIRuntimeException("The category param is not currently supported on the /everything endpoint"); addTag("category"); current.append(category); return this; @@ -87,9 +94,9 @@ public LinkBuilder country(String country) { return this; } - public LinkBuilder sortBy(String sortBy) { + public LinkBuilder sortBy(SortBy sortBy) { addTag("sortBy"); - current.append(sortBy); + current.append(sortBy.toLink()); return this; } @@ -110,7 +117,7 @@ public LinkBuilder from(Date from) { int mm = c.get(Calendar.MONTH) + 1; addTag("from"); current.append(yy).append('-').append((String.valueOf(mm).length() != 2 ? "0" : "") + mm).append('-').append( - String.valueOf(dd).length() != 2 ? "0" : "" + dd); + (String.valueOf(dd).length() != 2 ? "0" : "") + dd); return this; } @@ -122,7 +129,7 @@ public LinkBuilder to(Date to) { int mm = c.get(Calendar.MONTH) + 1; addTag("to"); current.append(yy).append('-').append((String.valueOf(mm).length() != 2 ? "0" : "") + mm).append('-').append( - String.valueOf(dd).length() != 2 ? "0" : "" + dd); + (String.valueOf(dd).length() != 2 ? "0" : "") + dd); return this; } From 7cc385da2afef7cef46bdd5501ff9af42fcc5385 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 15:48:05 +0300 Subject: [PATCH 09/13] Added pageSize option --- .../vlad/newsapi4j/client/StandartAsyncService.java | 7 ++++++- src/com/vlad/newsapi4j/client/StandartService.java | 6 ++++++ src/com/vlad/newsapi4j/service/IAsyncService.java | 11 +++++++++++ src/com/vlad/newsapi4j/service/IService.java | 11 +++++++++++ src/com/vlad/newsapi4j/utils/LinkBuilder.java | 6 ++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/com/vlad/newsapi4j/client/StandartAsyncService.java b/src/com/vlad/newsapi4j/client/StandartAsyncService.java index fd6878c..4ca7010 100644 --- a/src/com/vlad/newsapi4j/client/StandartAsyncService.java +++ b/src/com/vlad/newsapi4j/client/StandartAsyncService.java @@ -1,7 +1,6 @@ package com.vlad.newsapi4j.client; import java.util.Date; -import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; import com.vlad.newsapi4j.response.APIResponse; @@ -104,6 +103,12 @@ public IAsyncService dateRange(Supplier range) { return this; } + @Override + public IAsyncService pageSize(int pageSize) { + stdService.pageSize(pageSize); + return this; + } + } diff --git a/src/com/vlad/newsapi4j/client/StandartService.java b/src/com/vlad/newsapi4j/client/StandartService.java index 30bc84e..bc9d266 100644 --- a/src/com/vlad/newsapi4j/client/StandartService.java +++ b/src/com/vlad/newsapi4j/client/StandartService.java @@ -148,4 +148,10 @@ public IService dateRange(Supplier range) { return this; } + @Override + public IService pageSize(int pageSize) { + link.pageSize(pageSize); + return this; + } + } diff --git a/src/com/vlad/newsapi4j/service/IAsyncService.java b/src/com/vlad/newsapi4j/service/IAsyncService.java index 3312127..82b8bb9 100644 --- a/src/com/vlad/newsapi4j/service/IAsyncService.java +++ b/src/com/vlad/newsapi4j/service/IAsyncService.java @@ -116,6 +116,17 @@ public interface IAsyncService { * @return */ IAsyncService page(int page); + + /** + * Sets the lookup page size
+ * I.E the amount of articles requested
+ * + * For more information, visit NewsAPI's official website + * here + * @param pageSize + * @return this + */ + IAsyncService pageSize(int pageSize); /** * Sets the 'to' date
diff --git a/src/com/vlad/newsapi4j/service/IService.java b/src/com/vlad/newsapi4j/service/IService.java index 4dfddc4..6a89fb0 100644 --- a/src/com/vlad/newsapi4j/service/IService.java +++ b/src/com/vlad/newsapi4j/service/IService.java @@ -109,6 +109,17 @@ public interface IService { * @return */ IService page(int page); + + /** + * Sets the lookup page size
+ * I.E the amount of articles requested
+ * + * For more information, visit NewsAPI's official website + * here + * @param pageSize + * @return this + */ + IService pageSize(int pageSize); /** * Sets the 'to' date
diff --git a/src/com/vlad/newsapi4j/utils/LinkBuilder.java b/src/com/vlad/newsapi4j/utils/LinkBuilder.java index 362fdf7..38e5547 100644 --- a/src/com/vlad/newsapi4j/utils/LinkBuilder.java +++ b/src/com/vlad/newsapi4j/utils/LinkBuilder.java @@ -49,6 +49,12 @@ public LinkBuilder category(String category) { current.append(category); return this; } + + public LinkBuilder pageSize(int pageSize) { + addTag("pageSize"); + current.append(pageSize); + return this; + } private void addTag(String tag) { if (firstAddition) { From 5f2e8bdcfd126c7aadfdb9eea571ae435ba715c7 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 15:50:53 +0300 Subject: [PATCH 10/13] Made examples better --- examples/Asynchronous.java | 4 ++-- examples/Custom.java | 32 ++++++++++++++++++-------------- examples/Standart.java | 1 + 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/examples/Asynchronous.java b/examples/Asynchronous.java index b4e5fae..4f469e9 100644 --- a/examples/Asynchronous.java +++ b/examples/Asynchronous.java @@ -17,7 +17,7 @@ public static void main(String[] args) { * Get the top headlines in the us today, sort them by date, show the first page(optional it's 1 by default) */ client.newTopHeadlinesServiceAsync() - .country("bg") + .country("us") .from(new Date()) .sortBy(SortBy.DATE) .page(1) @@ -34,7 +34,7 @@ public static void main(String[] args) { */ articles.stream() // .filter(article -> article.getAuthor().startsWith("A")) - .forEach(article -> System.out.println(article.getDescription())); + .forEach(System.out::println); }, /** * We are here, something went wrong, just print the cause diff --git a/examples/Custom.java b/examples/Custom.java index eae3e7b..3d8b803 100644 --- a/examples/Custom.java +++ b/examples/Custom.java @@ -1,19 +1,21 @@ package com.vlad.newsapi4j.examples; +import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.function.Supplier; -import java.util.stream.Collectors; import org.json.JSONException; import org.json.JSONObject; import com.vlad.newsapi4j.access.APIConnection; import com.vlad.newsapi4j.client.NewsApiClient; -import com.vlad.newsapi4j.client.Response; +import com.vlad.newsapi4j.client.ResponseImpl; import com.vlad.newsapi4j.model.Article; import com.vlad.newsapi4j.response.APIResponse; import com.vlad.newsapi4j.service.Endpoint; import com.vlad.newsapi4j.service.IAsyncService; +import com.vlad.newsapi4j.service.SortBy; import com.vlad.newsapi4j.utils.Callback; import com.vlad.newsapi4j.utils.Category; import com.vlad.newsapi4j.utils.DateRange; @@ -28,22 +30,18 @@ public static void main(String[] args) { client.newCustomAsyncService(new MyCustomAsyncService(), Endpoint.EVERYTHING) .withKeyword("Youtube") .language("en") + .pageSize(100) /** * I HAD to break convention (All caps methods and all that), just look at how beautiful this looks */ .dateRange(DateRange::LAST_7_DAYS) .send(result -> { System.out.println("Result matches : " + result.totalResults()); - /** - * Find the first article that has an author ? - */ - Article a = result.viewAsArticles() - .get() - .stream() - .filter(article -> article.getAuthor() != null) - .findFirst() - .orElse(null); - System.out.println(a); + + List
articles = result.viewAsArticles().orElseGet(Collections::emptyList); + + //Print the articles + articles.forEach(System.out::println); }, Throwable::printStackTrace); } @@ -91,7 +89,7 @@ public IAsyncService language(String lang) { } @Override - public IAsyncService sortBy(String sortBy) { + public IAsyncService sortBy(SortBy sortBy) { link.sortBy(sortBy); return this; } @@ -172,7 +170,7 @@ public void send(Callback result, Callback onError) { } catch (JSONException e) { onError.invoke(new NewsAPIException("Something went wrong while parsing json")); } - result.invoke(new Response(endpoint, content, status, totalRes)); + result.invoke(new ResponseImpl(endpoint, content, status, totalRes)); }).start(); } @@ -183,6 +181,12 @@ public IAsyncService dateRange(Supplier range) { return this; } + @Override + public IAsyncService pageSize(int pageSize) { + this.link.pageSize(pageSize); + return this; + } + } } diff --git a/examples/Standart.java b/examples/Standart.java index 1c28283..e3a3fe6 100644 --- a/examples/Standart.java +++ b/examples/Standart.java @@ -39,5 +39,6 @@ public static void main(String[] args) throws NewsAPIException { } + } From 9594cc05019c5d6f61ae10cb60dbc4fcff1bb83b Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 16:57:16 +0300 Subject: [PATCH 11/13] Update README.md --- README.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3be6d2f..952c3a3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,84 @@ # News API SDK for Java -Coming soon... this is where our officially supported SDK for Java is going to live. -*** -## Developers... we need you! -We need some help fleshing out this repo. If you're a Java dev with experience building Maven-compatible libraries and web API wrappers, we're offering a reward of $250 to help us get started. For more info please email support@newsapi.org, or dive right in and send us a pull request. +How to use + +0.Download the latest release here : https://github.com/VIad/News-API-java/releases and add the jar to your build path + + + +1.Create the client object +```java +NewsApiClient client = new NewsApiClient("YOUR_API_KEY_HERE"); +``` +2.Create the service you require (sources / everything / top headlines) + +Example: get the top headlines from the united states using an asynchronous service + +```java +client.newTopHeadlinesServiceAsync() + .country("us") + .send(result -> { + List
articles = result.viewAsArticles().orElseGet(Collections::emptyList); + //Do some processing on the articles + }, + //Error occured, print it + error -> System.err.println(error.getMessage())); +``` + +You can also use a non-async flow and store the response in an ```APIResponse``` object + +Example: get the news sources using a keyword and sort them by popularity +```java +APIResponse response = client.newSourcesService() + .withKeyword("bulgaria") + .sortBy(SortBy.POPULARITY) + .send(); + +/* + * viewAs methods return an optional, since it's uncertain what the data type inside APIResponse.getData is + */ +List newsSources = response.viewAsNewsSources().orElseGet(Collections::emptyList); +//Do some processing on the news sources +``` + +Creating your own service + +1.Create a class and implement either ```IService``` or ```IAsyncService``` if you want either synchronous or asynchronous execution + +Example: +```java +public class MyCustomAsyncService implements IAsyncService{ +Remainder omitted... +} +``` + +2.Create the service using the ```NewsApiClient``` object + +Example: query all the headlines in english with keyword 'Youtube' from the last 7 days + +```java +client.newCustomAsyncService(new MyCustomAsyncService(), /*Specify an endpoint for your service*/ Endpoint.EVERYTHING) + .withKeyword("Youtube") + .language("en") + .dateRange(DateRange::LAST_7_DAYS) + .send(result -> { + List
articles = result.viewAsArticles().orElseGet(Collections::emptyList); + //Do some processing on the articles + }, + //Something went wrong, print the stack trace + Throwable::printStackTrace); +``` + +Some request methods ```IService``` and ```IAsyncService``` provide + +```java +withSources(String... sources) //Sets the lookup sources, such as bbc, abc-news, cnn +withDomains(String... domains) //Sets the lookup domains, such as techcrunch.com, bbc.co.uk +from(Date date) //Filters news from the specified date +to(Date date) //Filters news to the specified date +withKeyword(String keyword) //sets the searched keyword +withCategory(Category category) //Filters the news given a category +``` + +If you are unsure as to what a function does, you can always refer to the javadoc provided with the binary From bcbddb83adb446ef384f49df205fa1a43772ba6f Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 16:59:48 +0300 Subject: [PATCH 12/13] Update README.md --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 952c3a3..9461ff9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # News API SDK for Java -How to use +**How to use** -0.Download the latest release here : https://github.com/VIad/News-API-java/releases and add the jar to your build path +**0**.Download the latest release here : https://github.com/VIad/News-API-java/releases and add the jar to your build path @@ -13,7 +13,7 @@ NewsApiClient client = new NewsApiClient("YOUR_API_KEY_HERE"); ``` 2.Create the service you require (sources / everything / top headlines) -Example: get the top headlines from the united states using an asynchronous service +*Example: get the top headlines from the united states using an asynchronous service* ```java client.newTopHeadlinesServiceAsync() @@ -26,9 +26,9 @@ client.newTopHeadlinesServiceAsync() error -> System.err.println(error.getMessage())); ``` -You can also use a non-async flow and store the response in an ```APIResponse``` object +**You can also use a non-async flow and store the response in an ```APIResponse``` object** -Example: get the news sources using a keyword and sort them by popularity +*Example: get the news sources using a keyword and sort them by popularity* ```java APIResponse response = client.newSourcesService() .withKeyword("bulgaria") @@ -42,11 +42,11 @@ List newsSources = response.viewAsNewsSources().orElseGet(Collection //Do some processing on the news sources ``` -Creating your own service +**Creating your own service** 1.Create a class and implement either ```IService``` or ```IAsyncService``` if you want either synchronous or asynchronous execution -Example: +*Example:* ```java public class MyCustomAsyncService implements IAsyncService{ Remainder omitted... @@ -55,7 +55,7 @@ Remainder omitted... 2.Create the service using the ```NewsApiClient``` object -Example: query all the headlines in english with keyword 'Youtube' from the last 7 days +*Example: query all the headlines in english with keyword 'Youtube' from the last 7 days* ```java client.newCustomAsyncService(new MyCustomAsyncService(), /*Specify an endpoint for your service*/ Endpoint.EVERYTHING) From 3aa713c392d501f132681fc77ead44c15be90b45 Mon Sep 17 00:00:00 2001 From: VIad Date: Sat, 2 Jun 2018 20:24:31 +0300 Subject: [PATCH 13/13] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9461ff9..4e3ffc3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# News API SDK for Java +# NewsAPI SDK for Java **How to use** @@ -7,11 +7,11 @@ -1.Create the client object +**1**.Create the client object ```java NewsApiClient client = new NewsApiClient("YOUR_API_KEY_HERE"); ``` -2.Create the service you require (sources / everything / top headlines) +**2**.Create the service you require (sources / everything / top headlines) *Example: get the top headlines from the united states using an asynchronous service* @@ -44,7 +44,7 @@ List newsSources = response.viewAsNewsSources().orElseGet(Collection **Creating your own service** -1.Create a class and implement either ```IService``` or ```IAsyncService``` if you want either synchronous or asynchronous execution +**1**.Create a class and implement either ```IService``` or ```IAsyncService``` if you want either synchronous or asynchronous execution *Example:* ```java @@ -53,7 +53,7 @@ Remainder omitted... } ``` -2.Create the service using the ```NewsApiClient``` object +**2**.Create the service using the ```NewsApiClient``` object *Example: query all the headlines in english with keyword 'Youtube' from the last 7 days*