├── .gitignore
├── LICENSE.md
├── README.md
├── build.gradle
├── docs
├── allclasses-frame.html
├── allclasses-noframe.html
├── com
│ └── viber
│ │ └── bot
│ │ ├── Request.html
│ │ ├── Response.html
│ │ ├── ViberSignatureValidator.html
│ │ ├── api
│ │ ├── ApiException.html
│ │ ├── ApiResponse.html
│ │ ├── ViberBot.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── event
│ │ ├── Event.html
│ │ ├── callback
│ │ │ ├── OnConversationStarted.html
│ │ │ ├── OnMessageDelivered.html
│ │ │ ├── OnMessageReceived.html
│ │ │ ├── OnMessageSeen.html
│ │ │ ├── OnMessageSent.html
│ │ │ ├── OnSubscribe.html
│ │ │ ├── OnUnsubscribe.html
│ │ │ ├── package-frame.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── incoming
│ │ │ ├── IncomingConversationStartedEvent.html
│ │ │ ├── IncomingDeliveredEvent.html
│ │ │ ├── IncomingErrorEvent.html
│ │ │ ├── IncomingEvent.html
│ │ │ ├── IncomingMessageEvent.html
│ │ │ ├── IncomingSeenEvent.html
│ │ │ ├── IncomingSubscribedEvent.html
│ │ │ ├── IncomingUnsubscribeEvent.html
│ │ │ ├── IncomingWebhookEvent.html
│ │ │ ├── package-frame.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── message
│ │ ├── Contact.html
│ │ ├── ContactMessage.html
│ │ ├── FileMessage.html
│ │ ├── Location.html
│ │ ├── LocationMessage.html
│ │ ├── Message.html
│ │ ├── MessageKeyboard.html
│ │ ├── PictureMessage.html
│ │ ├── RichMediaMessage.html
│ │ ├── RichMediaObject.html
│ │ ├── StickerMessage.html
│ │ ├── TextMessage.html
│ │ ├── TrackingData.html
│ │ ├── UrlMessage.html
│ │ ├── VideoMessage.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ ├── package-tree.html
│ │ └── profile
│ │ ├── BotProfile.html
│ │ ├── UserProfile.html
│ │ ├── package-frame.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
├── constant-values.html
├── deprecated-list.html
├── help-doc.html
├── index-files
│ ├── index-1.html
│ ├── index-10.html
│ ├── index-11.html
│ ├── index-12.html
│ ├── index-13.html
│ ├── index-14.html
│ ├── index-15.html
│ ├── index-16.html
│ ├── index-17.html
│ ├── index-2.html
│ ├── index-3.html
│ ├── index-4.html
│ ├── index-5.html
│ ├── index-6.html
│ ├── index-7.html
│ ├── index-8.html
│ └── index-9.html
├── index.html
├── overview-frame.html
├── overview-summary.html
├── overview-tree.html
├── package-list
├── script.js
├── serialized-form.html
└── stylesheet.css
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── nano-httpd-sample
├── README.md
├── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── viber
│ │ └── bot
│ │ └── sample
│ │ └── NanoHttpdSample.java
│ └── resources
│ └── simplelogger.properties
├── settings.gradle
├── spring-boot-sample
├── README.md
├── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── viber
│ │ └── bot
│ │ └── sample
│ │ └── SpringEchoBot.java
│ └── resources
│ └── application.yml
└── src
├── main
└── java
│ └── com
│ └── viber
│ └── bot
│ ├── Preconditions.java
│ ├── Request.java
│ ├── Response.java
│ ├── ViberEnvironmentConfiguration.java
│ ├── ViberSignatureValidator.java
│ ├── api
│ ├── ApiException.java
│ ├── ApiResponse.java
│ ├── MessageSender.java
│ ├── MessageToMapConverter.java
│ ├── RegexMatcherRouter.java
│ ├── RequestReceiverImpl.java
│ ├── ViberBot.java
│ └── ViberClient.java
│ ├── event
│ ├── BotEventListener.java
│ ├── Event.java
│ ├── EventEmitter.java
│ ├── callback
│ │ ├── OnConversationStarted.java
│ │ ├── OnMessageDelivered.java
│ │ ├── OnMessageReceived.java
│ │ ├── OnMessageSeen.java
│ │ ├── OnMessageSent.java
│ │ ├── OnSubscribe.java
│ │ └── OnUnsubscribe.java
│ └── incoming
│ │ ├── IncomingConversationStartedEvent.java
│ │ ├── IncomingDeliveredEvent.java
│ │ ├── IncomingErrorEvent.java
│ │ ├── IncomingEvent.java
│ │ ├── IncomingMessageEvent.java
│ │ ├── IncomingSeenEvent.java
│ │ ├── IncomingSubscribedEvent.java
│ │ ├── IncomingUnsubscribeEvent.java
│ │ └── IncomingWebhookEvent.java
│ ├── message
│ ├── Contact.java
│ ├── ContactMessage.java
│ ├── FileMessage.java
│ ├── Location.java
│ ├── LocationMessage.java
│ ├── Message.java
│ ├── MessageKeyboard.java
│ ├── PictureMessage.java
│ ├── RichMediaMessage.java
│ ├── RichMediaObject.java
│ ├── StickerMessage.java
│ ├── TextMessage.java
│ ├── TrackingData.java
│ ├── UrlMessage.java
│ └── VideoMessage.java
│ ├── middleware
│ ├── DefaultMiddleware.java
│ ├── Middleware.java
│ ├── PubSubMiddleware.java
│ └── RequestReceiver.java
│ └── profile
│ ├── BotProfile.java
│ └── UserProfile.java
└── test
└── java
└── com
└── viber
└── bot
├── RequestTest.java
├── ViberSignatureValidatorTest.java
├── api
├── RegexMatcherRouterTest.java
└── ViberClientTest.java
├── event
└── EventEmitterTest.java
└── middleware
└── PubSubMiddlewareTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .gradle
3 | gradle.properties
4 | build/
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # :warning: Deprecated :warning:
2 |
3 | This library is deprecated. No new development will be taking place. We recommend that you use either [NodeJS](https://github.com/Viber/viber-bot-node), [Python](https://github.com/Viber/viber-bot-python) or [REST API](https://developers.viber.com/docs/api/rest-bot-api/).
4 |
5 | # Viber Java Bot API
6 |
7 | Use this library to develop a bot for Viber platform.
8 | The library is available on **[GitHub](https://github.com/Viber/viber-bot-java)** as well as [maven central](http://central.maven.org/maven2/com/viber/viber-bot/).
9 |
10 | ## License
11 |
12 | This library is released under the terms of the Apache 2.0 license. See [License](https://github.com/Viber/viber-bot-java/blob/master/LICENSE.md) for more information.
13 |
14 | ## Library Prerequisites
15 |
16 | 1. Java >= 8
17 | 1. An Active Viber account on a platform which supports Public Accounts/ bots (iOS/Android). This account will automatically be set as the account administrator during the account creation process.
18 | 1. Active Public Account/ bot.
19 | 1. Account authentication token - unique account identifier used to validate your account in all API requests. Once your account is created your authentication token will appear in the account’s “edit info” screen (for admins only). Each request posted to Viber by the account will need to contain the token.
20 | 1. Webhook - Please use a server endpoint URL that supports HTTPS. If you deploy on your own custom server, you'll need a trusted (ca.pem) certificate, not self-signed. Read our [blog post](https://developers.viber.com/blog/2017/05/24/test-your-bots-locally) on how to test your bot locally.
21 |
22 | ## Installation
23 |
24 | This library is released on [maven central](http://central.maven.org/maven2/com/viber/viber-bot/).
25 |
26 | ### Gradle
27 |
28 | ```
29 | compile group: 'com.viber', name: 'viber-bot', version: '1.0.11'
30 | ```
31 |
32 | ### Maven
33 |
34 | ```
35 |
36 | com.viber
37 | viber-bot
38 | 1.0.11
39 |
40 | ```
41 |
42 | ## Documentation
43 |
44 | ### JavaDocs
45 |
46 | All public APIs are documented with JavaDocs which can be found in the [GitHub repository](http://htmlpreview.github.io/?https://github.com/Viber/viber-bot-java/blob/master/docs/index.html).
47 |
48 | ### Sample projects
49 |
50 | We've created two sample projects to help you get started:
51 |
52 | * [Spring-Boot Sample](https://github.com/Viber/viber-bot-java/tree/master/spring-boot-sample) using [spring-boot-starter-web](https://github.com/spring-projects/spring-boot/tree/master/spring-boot-starters/spring-boot-starter-web) package.
53 | * [NanoHTTPd Sample](https://github.com/Viber/viber-bot-java/tree/master/nano-httpd-sample/) with a tiny embedded HTTP server, called [NanoHTTPd](https://github.com/NanoHttpd/nanohttpd).
54 |
55 | ### A simple overview
56 |
57 | ```java
58 | public void botExample() {
59 | ViberBot bot = new ViberBot(new BotProfile("SampleBot", "http://viber.com/avatar.jpg"), "YOUR_AUTH_TOKEN_HERE");
60 | bot.onMessageReceived((event, message, response) -> response.send(message));
61 |
62 | // somewhere else in your web server of choice:
63 | bot.incoming(Request.fromJsonString("..."));
64 | }
65 | ```
66 |
67 | You can chose to use any web server or framework you like. All you need to do is call the API with:
68 |
69 | ```java
70 | bot.incoming(Request.fromJsonString("...")); // or
71 | bot.incoming(Request.fromInputStream(inputStream));
72 | ```
73 |
74 | ### Should I be concerned with synchronizing my web server threads? Is this library thread-safe?
75 |
76 | The Viber bot library is *thread-safe* and highly concurrent. You do not have to worry about synchronizing anything.
77 |
78 | All calls to `ViberBot#incoming()` go through a `BlockingQueue`, and ordering is retained.
79 | All I/O calls are directly executed on the same thread they were initially called on.
80 |
81 | ### Can I make I/O calls asynchronous and still retain thread-safety for my bot?
82 |
83 | Yes. You can pass a system property to control the I/O thread pool:
84 |
85 | `com.viber.bot.executor.strategy=[DIRECT|THREAD]` (default is DIRECT)
86 |
87 | `com.viber.bot.executor.threads=N` (default is `getRuntime().availableProcessors()`)
88 |
89 | * Note: This will not change the way you use the library. You still don't have to synchronize anything.
90 |
91 | ### Do you supply a basic router for text messages?
92 |
93 | Well funny you ask. Yes we do. But a word of warning - messages sent to your router callback will also be emitted to the `ViberBot#onMessageReceived` event.
94 |
95 | ```java
96 | public void botTextRouterExample() {
97 | bot.onTextMessage("(hi|hello)", (event, message, response) -> response.send("Hi " + event.getSender().getName()));
98 | }
99 | ```
100 |
101 | ## Community
102 |
103 | Join the conversation on **[Gitter](https://gitter.im/viber/bot-java)**.
104 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | group = projectGroup
2 | version = projectVersion
3 |
4 | buildscript {
5 | repositories {
6 | mavenCentral()
7 | }
8 | }
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | apply plugin: 'java'
15 | apply plugin: 'idea'
16 | apply plugin: 'eclipse'
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | sourceCompatibility = projectSourceCompatibility
21 |
22 | project.ext {
23 | slf4jVersion = '1.7.22'
24 | jacksonVersion = '2.8.6'
25 | findbugsVersion = '3.0.1'
26 | guavaVersion = '21.0'
27 | okhttp3Version = '3.5.0'
28 | }
29 |
30 | dependencies {
31 | compile group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
32 | compile group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp3Version
33 | compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: jacksonVersion
34 |
35 | compile group: 'com.google.code.findbugs', name: 'jsr305', version: findbugsVersion
36 | compile group: 'com.google.guava', name: 'guava', version: guavaVersion
37 |
38 | testCompile group: 'junit', name: 'junit', version: '4.12'
39 | testCompile group: 'org.assertj', name: 'assertj-core', version: '3.6.1'
40 | testCompile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
41 | testCompile group: 'com.jayway.awaitility', name: 'awaitility', version: '1.7.0'
42 | }
43 |
44 | sourceSets {
45 | main {
46 | java {
47 | srcDirs 'src/main/java'
48 | }
49 | }
50 | }
51 |
52 | task wrapper(type: Wrapper) {
53 | gradleVersion = '2.13'
54 | }
55 |
56 | task javadocJar(type: Jar) {
57 | classifier = 'javadoc'
58 | from javadoc
59 | }
60 |
61 | task sourcesJar(type: Jar) {
62 | classifier = 'sources'
63 | from sourceSets.main.allSource
64 | }
65 |
66 | artifacts {
67 | archives javadocJar, sourcesJar
68 | }
69 |
70 | signing {
71 | sign configurations.archives
72 | }
73 |
74 | uploadArchives {
75 | repositories {
76 | mavenDeployer {
77 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
78 |
79 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
80 | authentication(userName: ossrhUsername, password: ossrhPassword)
81 | }
82 |
83 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
84 | authentication(userName: ossrhUsername, password: ossrhPassword)
85 | }
86 |
87 | pom.project {
88 | name projectName
89 | packaging 'jar'
90 | artifactId projectName
91 | description 'Use this library to communicate with the Viber API to develop a bot for https://developers.viber.com/.'
92 | url 'https://developers.viber.com/'
93 |
94 | scm {
95 | connection 'scm:git:git://github.com/Viber/viber-bot-java.git'
96 | url 'https://github.com/Viber/viber-bot-java/tree/master'
97 | }
98 |
99 | licenses {
100 | license {
101 | name 'The Apache License, Version 2.0'
102 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
103 | }
104 | }
105 |
106 | developers {
107 | developer {
108 | id 'idan'
109 | name 'Idan Harel'
110 | email 'idanh@viber.com'
111 | organization 'Viber'
112 | organizationUrl 'http://viber.com'
113 | }
114 | }
115 | }
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/docs/allclasses-noframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | All Classes
7 |
8 |
9 |
10 |
11 |
12 | All Classes
13 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/api/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.api
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Classes
15 |
19 |
Exceptions
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/event/callback/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.event.callback
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Interfaces
15 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/event/incoming/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.event.incoming
7 |
8 |
9 |
10 |
11 |
12 |
13 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/event/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.event
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/event/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.event
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
74 |
75 |
76 | -
77 |
78 | Enum Summary
79 |
80 | Enum |
81 | Description |
82 |
83 |
84 |
85 | Event |
86 | |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
111 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/event/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.event Class Hierarchy
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
78 |
79 |
Enum Hierarchy
80 |
81 | - java.lang.Object
82 |
83 | - java.lang.Enum<E> (implements java.lang.Comparable<T>, java.io.Serializable)
84 |
85 | - com.viber.bot.event.Event
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
110 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/message/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.message
7 |
8 |
9 |
10 |
11 |
12 |
13 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
74 |
101 |
102 |
119 |
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot Class Hierarchy
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
78 |
79 |
Class Hierarchy
80 |
81 | - java.lang.Object
82 |
87 |
88 |
89 |
90 |
91 |
108 |
109 |
110 | - Prev
111 | - Next
112 |
113 |
117 |
120 |
121 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/profile/package-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.profile
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/profile/package-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.profile
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
74 |
75 |
76 | -
77 |
78 | Class Summary
79 |
80 | Class |
81 | Description |
82 |
83 |
84 |
85 | BotProfile |
86 | |
87 |
88 |
89 | UserProfile |
90 | |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
115 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/docs/com/viber/bot/profile/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | com.viber.bot.profile Class Hierarchy
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
78 |
79 |
Class Hierarchy
80 |
81 | - java.lang.Object
82 |
86 |
87 |
88 |
89 |
90 |
107 |
108 |
109 | - Prev
110 | - Next
111 |
112 |
116 |
119 |
120 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/docs/constant-values.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Constant Field Values
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
75 |
76 |
93 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/docs/deprecated-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Deprecated List
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
75 |
76 |
93 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Generated Documentation (Untitled)
7 |
59 |
60 |
74 |
75 |
--------------------------------------------------------------------------------
/docs/overview-frame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview List
7 |
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/docs/overview-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Overview
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
110 |
111 |
128 |
129 |
130 | - Prev
131 | - Next
132 |
133 |
137 |
140 |
141 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/docs/package-list:
--------------------------------------------------------------------------------
1 | com.viber.bot
2 | com.viber.bot.api
3 | com.viber.bot.event
4 | com.viber.bot.event.callback
5 | com.viber.bot.event.incoming
6 | com.viber.bot.message
7 | com.viber.bot.profile
8 |
--------------------------------------------------------------------------------
/docs/script.js:
--------------------------------------------------------------------------------
1 | function show(type)
2 | {
3 | count = 0;
4 | for (var key in methods) {
5 | var row = document.getElementById(key);
6 | if ((methods[key] & type) != 0) {
7 | row.style.display = '';
8 | row.className = (count++ % 2) ? rowColor : altColor;
9 | }
10 | else
11 | row.style.display = 'none';
12 | }
13 | updateTabs(type);
14 | }
15 |
16 | function updateTabs(type)
17 | {
18 | for (var value in tabs) {
19 | var sNode = document.getElementById(tabs[value][0]);
20 | var spanNode = sNode.firstChild;
21 | if (value == type) {
22 | sNode.className = activeTableTab;
23 | spanNode.innerHTML = tabs[value][1];
24 | }
25 | else {
26 | sNode.className = tableTab;
27 | spanNode.innerHTML = "" + tabs[value][1] + "";
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/docs/serialized-form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Serialized Form
7 |
8 |
9 |
10 |
11 |
12 |
22 |
25 |
26 |
43 |
70 |
71 |
74 |
88 |
89 |
106 |
107 |
108 | - Prev
109 | - Next
110 |
111 |
115 |
118 |
119 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-java/65be8a3e6210ade86157146c68fe78dfe1bc8d78/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 30 16:58:07 IST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/nano-httpd-sample/README.md:
--------------------------------------------------------------------------------
1 | # Viber Bot API - NanoHTTPd
2 | ## Documentation
3 | For full documentation on this SDK please [click here](https://github.com/Viber/viber-bot-java/blob/master/README.md)
4 |
5 | ## Using this sample
6 | * Building the project:
7 | * For IntelliJ: `./gradlew idea`
8 | * For Eclipse: `./gradlew eclipse`
9 | * Please edit constants in [NanoHttpdSample.java](src/main/java/com/viber/bot/sample/NanoHttpdSample.java) with your SSL certificate and [auth token](https://developers.viber.com/docs/faq/#authentication-tokens).
10 | * Run [NanoHttpdSample.main()](src/main/java/com/viber/bot/sample/NanoHttpdSample.java).
11 |
--------------------------------------------------------------------------------
/nano-httpd-sample/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.viber'
2 | version '1.0-SNAPSHOT'
3 |
4 | apply plugin: 'java'
5 | apply plugin: 'idea'
6 | apply plugin: 'eclipse'
7 |
8 | sourceCompatibility = 1.8
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | compile group: 'com.viber', name: 'viber-bot', version: '1.0.9'
16 | compile group: 'org.nanohttpd', name: 'nanohttpd', version: '2.3.1'
17 | compile group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.21'
18 | }
19 |
--------------------------------------------------------------------------------
/nano-httpd-sample/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-java/65be8a3e6210ade86157146c68fe78dfe1bc8d78/nano-httpd-sample/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/nano-httpd-sample/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 05 08:42:29 IST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
7 |
--------------------------------------------------------------------------------
/nano-httpd-sample/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/nano-httpd-sample/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/nano-httpd-sample/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'nano-httpd-sample'
2 |
3 |
--------------------------------------------------------------------------------
/nano-httpd-sample/src/main/java/com/viber/bot/sample/NanoHttpdSample.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.sample;
2 |
3 | import com.google.common.base.Preconditions;
4 | import com.google.common.net.MediaType;
5 | import com.google.common.util.concurrent.Futures;
6 | import com.google.common.util.concurrent.Uninterruptibles;
7 | import com.viber.bot.Request;
8 | import com.viber.bot.ViberSignatureValidator;
9 | import com.viber.bot.api.ViberBot;
10 | import com.viber.bot.message.TextMessage;
11 | import com.viber.bot.profile.BotProfile;
12 | import fi.iki.elonen.NanoHTTPD;
13 |
14 | import javax.annotation.Nullable;
15 | import java.io.IOException;
16 | import java.io.InputStream;
17 | import java.util.HashMap;
18 | import java.util.Map;
19 | import java.util.Optional;
20 | import java.util.concurrent.ExecutionException;
21 |
22 | public class NanoHttpdSample extends NanoHTTPD {
23 |
24 | private static final int PORT = 8080;
25 |
26 | private static final String AUTH_TOKEN = "YOUR_VIBER_AUTH_TOKEN";
27 | private static final String WEBHOOK_URL = "https://YOUR_WEBHOOK_URL:8080";
28 |
29 | private static final String SSL_JKS = "/path/to/cert.jks";
30 | private static final String SSL_JKS_PASSWORD = "password";
31 |
32 | private final ViberBot bot;
33 | private final ViberSignatureValidator signatureValidator;
34 |
35 | NanoHttpdSample() throws IOException, ExecutionException, InterruptedException {
36 | super(PORT);
37 | makeSecure(NanoHTTPD.makeSSLSocketFactory(SSL_JKS, SSL_JKS_PASSWORD.toCharArray()), null);
38 | start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);
39 |
40 | bot = new ViberBot(new BotProfile("Echo Bot"), AUTH_TOKEN);
41 | signatureValidator = new ViberSignatureValidator(AUTH_TOKEN);
42 |
43 | bot.setWebhook(WEBHOOK_URL).get();
44 | bot.onMessageReceived((event, message, response) -> response.send(message)); // echos everything back
45 | bot.onConversationStarted(event -> Futures.immediateFuture(Optional.of( // send 'Hi UserName' when conversation is started
46 | new TextMessage("Hi " + event.getUser().getName()))));
47 | }
48 |
49 | public static void main(final String[] args) throws InterruptedException, ExecutionException, IOException {
50 | new NanoHttpdSample();
51 | }
52 |
53 | @Override
54 | public Response serve(final IHTTPSession session) {
55 | try {
56 | final String json = parsePostData(session);
57 | final String serverSideSignature = session.getHeaders().get("x-viber-content-signature");
58 | Preconditions.checkState(signatureValidator.isSignatureValid(serverSideSignature, json), "invalid signature");
59 |
60 | final Request request = Request.fromJsonString(json);
61 | final InputStream inputStream = Uninterruptibles.getUninterruptibly(bot.incoming(request));
62 |
63 | return newChunkedResponse(Response.Status.OK, MediaType.JSON_UTF_8.toString(), inputStream);
64 | } catch (final ExecutionException e) {
65 | e.printStackTrace();
66 | return newFixedLengthResponse("Error, sorry");
67 | }
68 | }
69 |
70 | @Nullable
71 | private String parsePostData(final IHTTPSession session) {
72 | final Map body = new HashMap<>();
73 | try {
74 | session.parseBody(body);
75 | } catch (IOException | ResponseException e) {
76 | e.printStackTrace();
77 | }
78 | return body.get("postData");
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/nano-httpd-sample/src/main/resources/simplelogger.properties:
--------------------------------------------------------------------------------
1 | org.slf4j.simpleLogger.defaultLogLevel=debug
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = projectName
--------------------------------------------------------------------------------
/spring-boot-sample/README.md:
--------------------------------------------------------------------------------
1 | # Viber Bot API - Spring Boot
2 | ## Documentation
3 | For full documentation on this SDK please [click here](https://github.com/Viber/viber-bot-java/blob/master/README.md)
4 |
5 | ## Using this sample
6 | * Building the project:
7 | * For IntelliJ: `./gradlew idea`
8 | * For Eclipse: `./gradlew eclipse`
9 | * Please edit [`application.yml`](src/main/resources/application.yml) with your SSL certificate and [auth token](https://developers.viber.com/docs/faq/#authentication-tokens).
10 | * Run [SpringEchoBot.main()](src/main/java/com/viber/bot/sample/SpringEchoBot.java).
11 |
12 |
--------------------------------------------------------------------------------
/spring-boot-sample/build.gradle:
--------------------------------------------------------------------------------
1 | group 'com.viber'
2 | version '1.0-SNAPSHOT'
3 |
4 | apply plugin: 'java'
5 | apply plugin: 'idea'
6 | apply plugin: 'eclipse'
7 |
8 | sourceCompatibility = 1.8
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | compile group: 'com.viber', name: 'viber-bot', version: '1.0.9'
16 | compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.4.2.RELEASE'
17 | compile group: 'javax.inject', name: 'javax.inject', version: '1'
18 | }
19 |
--------------------------------------------------------------------------------
/spring-boot-sample/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Viber/viber-bot-java/65be8a3e6210ade86157146c68fe78dfe1bc8d78/spring-boot-sample/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/spring-boot-sample/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 05 08:00:49 IST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
7 |
--------------------------------------------------------------------------------
/spring-boot-sample/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/spring-boot-sample/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'spring-boot-sample'
2 |
3 |
--------------------------------------------------------------------------------
/spring-boot-sample/src/main/java/com/viber/bot/sample/SpringEchoBot.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.sample;
2 |
3 | import com.google.common.base.Charsets;
4 | import com.google.common.base.Preconditions;
5 | import com.google.common.io.CharStreams;
6 | import com.google.common.util.concurrent.Futures;
7 | import com.viber.bot.Request;
8 | import com.viber.bot.ViberSignatureValidator;
9 | import com.viber.bot.api.ViberBot;
10 | import com.viber.bot.message.TextMessage;
11 | import com.viber.bot.profile.BotProfile;
12 | import org.springframework.beans.factory.annotation.Value;
13 | import org.springframework.boot.SpringApplication;
14 | import org.springframework.boot.autoconfigure.SpringBootApplication;
15 | import org.springframework.boot.context.event.ApplicationReadyEvent;
16 | import org.springframework.context.ApplicationListener;
17 | import org.springframework.context.annotation.Bean;
18 | import org.springframework.context.annotation.Configuration;
19 | import org.springframework.web.bind.annotation.PostMapping;
20 | import org.springframework.web.bind.annotation.RequestBody;
21 | import org.springframework.web.bind.annotation.RequestHeader;
22 | import org.springframework.web.bind.annotation.RestController;
23 |
24 | import javax.annotation.Nullable;
25 | import javax.inject.Inject;
26 | import java.io.IOException;
27 | import java.io.InputStream;
28 | import java.io.InputStreamReader;
29 | import java.util.Optional;
30 | import java.util.concurrent.ExecutionException;
31 |
32 | @RestController
33 | @SpringBootApplication
34 | public class SpringEchoBot implements ApplicationListener {
35 |
36 | @Inject
37 | private ViberBot bot;
38 |
39 | @Inject
40 | private ViberSignatureValidator signatureValidator;
41 |
42 | @Value("${application.viber-bot.webhook-url}")
43 | private String webhookUrl;
44 |
45 | public static void main(String[] args) {
46 | SpringApplication.run(SpringEchoBot.class, args);
47 | }
48 |
49 | @Override
50 | public void onApplicationEvent(ApplicationReadyEvent appReadyEvent) {
51 | try {
52 | bot.setWebhook(webhookUrl).get();
53 | } catch (Exception e) {
54 | e.printStackTrace();
55 | }
56 |
57 | bot.onMessageReceived((event, message, response) -> response.send(message)); // echos everything back
58 | bot.onConversationStarted(event -> Futures.immediateFuture(Optional.of( // send 'Hi UserName' when conversation is started
59 | new TextMessage("Hi " + event.getUser().getName()))));
60 | }
61 |
62 | @PostMapping(value = "/", produces = "application/json")
63 | public String incoming(@RequestBody String json,
64 | @RequestHeader("X-Viber-Content-Signature") String serverSideSignature)
65 | throws ExecutionException, InterruptedException, IOException {
66 | Preconditions.checkState(signatureValidator.isSignatureValid(serverSideSignature, json), "invalid signature");
67 | @Nullable InputStream response = bot.incoming(Request.fromJsonString(json)).get();
68 | return response != null ? CharStreams.toString(new InputStreamReader(response, Charsets.UTF_16)) : null;
69 | }
70 |
71 | @Configuration
72 | public class BotConfiguration {
73 |
74 | @Value("${application.viber-bot.auth-token}")
75 | private String authToken;
76 |
77 | @Value("${application.viber-bot.name}")
78 | private String name;
79 |
80 | @Nullable
81 | @Value("${application.viber-bot.avatar:@null}")
82 | private String avatar;
83 |
84 | @Bean
85 | ViberBot viberBot() {
86 | return new ViberBot(new BotProfile(name, avatar), authToken);
87 | }
88 |
89 | @Bean
90 | ViberSignatureValidator signatureValidator() {
91 | return new ViberSignatureValidator(authToken);
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/spring-boot-sample/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 | ssl:
4 | enabled: true
5 | key-alias: test
6 | key-store: "path/to/cert.jks"
7 | key-store-password: "password"
8 |
9 | application.viber-bot:
10 | auth-token: "YOUR_VIBER_AUTH_TOKEN"
11 | webhook-url: "https://YOUR_WEBHOOK_URL:8080"
12 | name: "EchoBot"
13 | avatar: "http://example.com/avatar.jpg"
14 |
15 | logging.level.com.viber: DEBUG
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/Preconditions.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import com.google.common.base.Strings;
4 |
5 | import javax.annotation.Nonnull;
6 | import javax.annotation.Nullable;
7 |
8 | import static com.google.common.base.Preconditions.checkNotNull;
9 |
10 | public class Preconditions {
11 | public static String checkNotEmpty(final @Nonnull String str) {
12 | return checkNotEmpty(str, null);
13 | }
14 |
15 | public static String checkNotEmpty(final @Nonnull String str, final @Nullable String errorMessage) {
16 | return checkNotNull(Strings.emptyToNull(str), errorMessage);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/Request.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.base.Charsets;
5 | import com.google.common.base.MoreObjects;
6 | import com.google.common.base.Strings;
7 | import com.google.common.io.ByteStreams;
8 | import com.google.common.io.Closeables;
9 | import com.viber.bot.event.incoming.IncomingEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import javax.annotation.Nonnull;
14 | import javax.annotation.Nullable;
15 | import javax.annotation.WillClose;
16 | import javax.annotation.WillNotClose;
17 | import javax.annotation.concurrent.ThreadSafe;
18 | import java.io.ByteArrayInputStream;
19 | import java.io.Closeable;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.util.concurrent.atomic.AtomicBoolean;
23 | import java.util.concurrent.atomic.AtomicReference;
24 |
25 | import static com.google.common.base.Preconditions.checkNotNull;
26 |
27 | @ThreadSafe
28 | public class Request implements Closeable {
29 |
30 | private static final Logger logger = LoggerFactory.getLogger(Request.class);
31 | private static final ObjectMapper objectMapper = new ObjectMapper();
32 |
33 | private static final String EMPTY_JSON_OBJECT = "{}";
34 |
35 | private final AtomicBoolean isClosed = new AtomicBoolean(false);
36 | private final AtomicReference responseInputStream = new AtomicReference<>();
37 | private final IncomingEvent event;
38 |
39 | private Request(final String json) {
40 | logger.debug("Reading json request: {}", json);
41 | event = readJson(json, IncomingEvent.class);
42 | }
43 |
44 | /**
45 | * Creates a Request object from an InputStream.
46 | * Be noted that the InputStream will be closed by this method.
47 | *
48 | * @param inputStream the InputStream
49 | * @return Request
50 | */
51 | public static Request fromInputStream(final @WillClose @Nonnull InputStream inputStream) {
52 | final String json = new String(readInputStream(inputStream), Charsets.UTF_8);
53 | Closeables.closeQuietly(inputStream);
54 | return Request.fromJsonString(json);
55 | }
56 |
57 | /**
58 | * Creates a Request object from a json string literal.
59 | *
60 | * @param json string
61 | * @return Request
62 | */
63 | public static Request fromJsonString(final @Nullable String json) {
64 | return new Request(MoreObjects.firstNonNull(Strings.nullToEmpty(json), EMPTY_JSON_OBJECT));
65 | }
66 |
67 | private static byte[] readInputStream(final @Nonnull InputStream inputStream) {
68 | final byte[] data;
69 | try {
70 | data = ByteStreams.toByteArray(inputStream);
71 | } catch (final IOException e) {
72 | logger.error("Could not read input stream", e);
73 | throw new RuntimeException(e);
74 | }
75 | return data;
76 | }
77 |
78 | private static T readJson(final String json, final Class clazz) {
79 | final T event;
80 | try {
81 | event = objectMapper.readValue(json, clazz);
82 | } catch (final Exception e) {
83 | logger.error("Could not read incoming event", e);
84 | throw new RuntimeException(e);
85 | }
86 | return event;
87 | }
88 |
89 | public IncomingEvent getEvent() {
90 | return event;
91 | }
92 |
93 | public boolean isClosed() {
94 | return isClosed.get();
95 | }
96 |
97 | public void setResponse(final String response) {
98 | setResponse(new ByteArrayInputStream(response.getBytes(Charsets.UTF_16)));
99 | }
100 |
101 | public void setResponse(final @Nonnull @WillNotClose InputStream inputStream) {
102 | responseInputStream.set(checkNotNull(inputStream));
103 | }
104 |
105 | @Nullable
106 | public InputStream getResponseInputStream() {
107 | return responseInputStream.get();
108 | }
109 |
110 | @Override
111 | public void close() throws IOException {
112 | synchronized (this) {
113 | if (!isClosed.compareAndSet(false, true)) return;
114 | try {
115 | notify();
116 | } catch (final IllegalMonitorStateException e) {
117 | logger.error("Could not notify object", e);
118 | }
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/Response.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import com.google.common.util.concurrent.ListenableFuture;
4 | import com.viber.bot.api.ApiException;
5 | import com.viber.bot.api.ViberBot;
6 | import com.viber.bot.message.Message;
7 | import com.viber.bot.message.TextMessage;
8 | import com.viber.bot.profile.UserProfile;
9 |
10 | import javax.annotation.Nonnull;
11 | import javax.annotation.concurrent.Immutable;
12 | import java.util.Collection;
13 |
14 | @Immutable
15 | public class Response {
16 |
17 | private final UserProfile to;
18 | private final ViberBot bot;
19 |
20 | public Response(final UserProfile to, final ViberBot bot) {
21 | this.to = to;
22 | this.bot = bot;
23 | }
24 |
25 | /**
26 | * Shorthand for {@link ViberBot#sendMessage(UserProfile, Collection)}
27 | * Where the {@link UserProfile} is already set.
28 | *
29 | * @param messages collection of messages to be sent
30 | * @return future which contains a collection of message tokens as strings, that may throw {@link ApiException}.
31 | * @see ViberBot#sendMessage(UserProfile, Collection)
32 | */
33 | public ListenableFuture> send(final @Nonnull Collection messages) {
34 | return bot.sendMessage(to, messages);
35 | }
36 |
37 | /**
38 | * Shorthand for {@link ViberBot#sendMessage(UserProfile, Message...)}
39 | * Where the {@link UserProfile} is already set.
40 | *
41 | * @param messages collection of messages to be sent
42 | * @return future which contains a collection of message tokens as strings, that may throw {@link ApiException}.
43 | * @see ViberBot#sendMessage(UserProfile, Message...)
44 | */
45 | public ListenableFuture> send(final @Nonnull Message... messages) {
46 | return bot.sendMessage(to, messages);
47 | }
48 |
49 | /**
50 | * Shorthand for {@link ViberBot#sendMessage(UserProfile, Message...)}
51 | * The method will create a {@link TextMessage} for you with the String provided to it.
52 | *
53 | * @param textMessage string to be as text for the message
54 | * @return future which contains a collection of message tokens as strings, that may throw {@link ApiException}.
55 | * @see ViberBot#sendMessage(UserProfile, Message...)
56 | */
57 | public ListenableFuture> send(final @Nonnull String textMessage) {
58 | return bot.sendMessage(to, new TextMessage(textMessage));
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/ViberEnvironmentConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import com.google.common.base.Strings;
4 | import com.google.common.util.concurrent.ListeningExecutorService;
5 | import com.google.common.util.concurrent.MoreExecutors;
6 |
7 | import javax.annotation.Nullable;
8 | import java.util.concurrent.Executors;
9 | import java.util.concurrent.atomic.AtomicReference;
10 | import java.util.function.Function;
11 |
12 | public class ViberEnvironmentConfiguration {
13 |
14 | private static final String CONFIG_PREFIX = "com.viber.bot";
15 | private static final String CONFIG_EXECUTOR_SERVICE_STRATEGY = "executor.strategy";
16 | private static final String CONFIG_NUMBER_OF_THREADS = "executor.threads";
17 |
18 | private static final AtomicReference executorService = new AtomicReference<>(null);
19 |
20 | public static ListeningExecutorService getExecutorService() {
21 | if (getExecutorServiceStrategy() == ExecutorServiceStrategy.DIRECT) {
22 | return MoreExecutors.newDirectExecutorService();
23 | } else {
24 | executorService.compareAndSet(null, MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(getNumberOfThreads())));
25 | return executorService.get();
26 | }
27 | }
28 |
29 | private static int getNumberOfThreads() {
30 | return getPropertyOrDefault(CONFIG_NUMBER_OF_THREADS, Integer::valueOf, Runtime.getRuntime().availableProcessors());
31 | }
32 |
33 | private static ExecutorServiceStrategy getExecutorServiceStrategy() {
34 | return getPropertyOrDefault(CONFIG_EXECUTOR_SERVICE_STRATEGY, ExecutorServiceStrategy::valueOf, ExecutorServiceStrategy.DIRECT);
35 | }
36 |
37 | private static T getPropertyOrDefault(final String suffix, final Function compose, final @Nullable T def) {
38 | final String configProperty = String.format("%s.%s", CONFIG_PREFIX, suffix);
39 | final String configValue = System.getProperty(configProperty);
40 | return Strings.isNullOrEmpty(configValue) ? def : compose.apply(configValue.toUpperCase());
41 | }
42 |
43 | private enum ExecutorServiceStrategy {
44 | DIRECT, THREAD
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/ViberSignatureValidator.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import com.google.common.base.Charsets;
4 | import com.google.common.hash.Hashing;
5 | import com.google.common.io.BaseEncoding;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import javax.annotation.Nonnull;
10 |
11 | import static com.viber.bot.Preconditions.checkNotEmpty;
12 |
13 | public class ViberSignatureValidator {
14 |
15 | private static final Logger logger = LoggerFactory.getLogger(ViberSignatureValidator.class);
16 | private final String secret;
17 |
18 | public ViberSignatureValidator(final @Nonnull String secret) {
19 | this.secret = checkNotEmpty(secret);
20 | }
21 |
22 | public boolean isSignatureValid(final @Nonnull String signature, final @Nonnull String data) {
23 | final String calculatedHash = encode(secret, data);
24 | logger.debug("Validating signature '{}' == '{}'", signature, calculatedHash);
25 | return calculatedHash.equals(signature);
26 | }
27 |
28 | private String encode(final @Nonnull String key, final @Nonnull String data) {
29 | final byte[] bytes = Hashing.hmacSha256(key.getBytes()).hashString(data, Charsets.UTF_8).asBytes();
30 | return BaseEncoding.base16().lowerCase().encode(bytes);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/api/ApiException.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import java.util.Map;
4 | import java.util.concurrent.ExecutionException;
5 |
6 | public class ApiException extends ExecutionException {
7 | private static final String STATUS_MESSAGE = "status_message";
8 |
9 | public ApiException(final Map responseMap) {
10 | super(responseMap.get(STATUS_MESSAGE).toString());
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/api/ApiResponse.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import com.google.common.base.MoreObjects;
4 | import com.google.common.collect.ForwardingMap;
5 |
6 | import javax.annotation.Nullable;
7 | import java.util.Collections;
8 | import java.util.Map;
9 |
10 | /**
11 | * Simple Map(String, Object) wrapper class.
12 | */
13 | public class ApiResponse extends ForwardingMap {
14 | private final Map map;
15 |
16 | ApiResponse(final @Nullable Map delegate) {
17 | this.map = Collections.unmodifiableMap(MoreObjects.firstNonNull(delegate, Collections.emptyMap()));
18 | }
19 |
20 | @Override
21 | protected Map delegate() {
22 | return map;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/api/MessageSender.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import com.google.common.base.Function;
4 | import com.google.common.collect.Lists;
5 | import com.google.common.util.concurrent.Futures;
6 | import com.google.common.util.concurrent.ListenableFuture;
7 | import com.viber.bot.message.Message;
8 | import com.viber.bot.profile.BotProfile;
9 | import com.viber.bot.profile.UserProfile;
10 |
11 | import javax.annotation.Nonnull;
12 | import java.util.Collection;
13 | import java.util.Iterator;
14 | import java.util.Optional;
15 |
16 | import static com.google.common.base.Preconditions.checkNotNull;
17 |
18 | class MessageSender {
19 | private static final String MESSAGE_TOKEN = "message_token";
20 |
21 | private final BotProfile botProfile;
22 | private final ViberClient client;
23 |
24 | MessageSender(final @Nonnull BotProfile botProfile, final @Nonnull ViberClient client) {
25 | this.botProfile = checkNotNull(botProfile);
26 | this.client = checkNotNull(client);
27 | }
28 |
29 | ListenableFuture> sendMessage(final @Nonnull UserProfile to, final @Nonnull Collection messages) {
30 | final Collection messageTokens = Lists.newArrayList();
31 | final Iterator iterator = messages.iterator();
32 |
33 | while (iterator.hasNext()) {
34 | final Message message = iterator.next();
35 |
36 | if (!iterator.hasNext()) {
37 | messageTokens.add(Futures.getUnchecked(Futures.transform(sendMessageWithKeyboard(to, message), getMessageToken())));
38 | } else {
39 | messageTokens.add(Futures.getUnchecked(Futures.transform(sendMessageWithoutKeyboard(to, message), getMessageToken())));
40 | }
41 | }
42 | return Futures.immediateFuture(messageTokens);
43 | }
44 |
45 | private ListenableFuture sendMessageWithoutKeyboard(final UserProfile to, final Message message) {
46 | return client.sendMessage(botProfile, to, message, Optional.empty(), Optional.of(message.getTrackingData()));
47 | }
48 |
49 | private ListenableFuture sendMessageWithKeyboard(final UserProfile to, final Message message) {
50 | return client.sendMessage(botProfile, to, message, Optional.of(message.getKeyboard()), Optional.of(message.getTrackingData()));
51 | }
52 |
53 | private Function getMessageToken() {
54 | return response -> response.get(MESSAGE_TOKEN).toString();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/api/MessageToMapConverter.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.base.MoreObjects;
5 | import com.viber.bot.message.Message;
6 | import com.viber.bot.message.MessageKeyboard;
7 | import com.viber.bot.message.TrackingData;
8 | import com.viber.bot.profile.BotProfile;
9 | import com.viber.bot.profile.UserProfile;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import javax.annotation.Nonnull;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 | import java.util.Optional;
17 |
18 | class MessageToMapConverter {
19 |
20 | private static final Logger logger = LoggerFactory.getLogger(MessageToMapConverter.class);
21 | private static final ObjectMapper objectMapper = new ObjectMapper();
22 | private static final String EMPTY_STRING = "";
23 |
24 | static Map mapMessage(final @Nonnull BotProfile from, final @Nonnull UserProfile to,
25 | final @Nonnull Message message, final @Nonnull Optional optionalKeyboard,
26 | final @Nonnull Optional optionalTrackingData) {
27 |
28 | final Map messageMap = message.getMapRepresentation();
29 |
30 | messageMap.put("tracking_data", isPresentAndNotEmpty(optionalTrackingData) ? serializeTrackingData(optionalTrackingData.get()) : null);
31 | messageMap.put("keyboard", isPresentAndNotEmpty(optionalKeyboard) ? optionalKeyboard.get() : null);
32 |
33 | return new HashMap() {{
34 | put("receiver", to.getId());
35 | put("sender", new HashMap() {{
36 | put("name", from.getName());
37 | put("avatar", MoreObjects.firstNonNull(from.getAvatar(), ""));
38 | }});
39 | putAll(messageMap);
40 | }};
41 | }
42 |
43 | private static String serializeTrackingData(final TrackingData trackingData) {
44 | try {
45 | return objectMapper.writeValueAsString(trackingData);
46 | } catch (final Exception e) {
47 | logger.warn("Could not serialize tracking data", trackingData);
48 | return EMPTY_STRING;
49 | }
50 | }
51 |
52 | private static boolean isPresentAndNotEmpty(final Optional optional) {
53 | return optional.isPresent() && !optional.get().isEmpty();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/api/RegexMatcherRouter.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import com.google.common.collect.ArrayListMultimap;
4 | import com.google.common.collect.Multimap;
5 | import com.viber.bot.event.callback.OnMessageReceived;
6 |
7 | import javax.annotation.Nonnull;
8 | import java.util.List;
9 | import java.util.regex.Pattern;
10 | import java.util.stream.Collectors;
11 |
12 | import static com.google.common.base.Preconditions.checkNotNull;
13 |
14 | class RegexMatcherRouter {
15 | private final Multimap patterns = ArrayListMultimap.create();
16 |
17 | void newMatcher(final @Nonnull Pattern pattern, final @Nonnull OnMessageReceived onMessageReceived) {
18 | patterns.put(checkNotNull(pattern), checkNotNull(onMessageReceived));
19 | }
20 |
21 | List tryGetCallback(final String text) {
22 | return patterns.asMap().entrySet().stream()
23 | .filter(entry -> entry.getKey().matcher(text).find())
24 | .flatMap(entry -> entry.getValue().stream())
25 | .collect(Collectors.toList());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/api/RequestReceiverImpl.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.google.common.util.concurrent.Futures;
5 | import com.viber.bot.Request;
6 | import com.viber.bot.Response;
7 | import com.viber.bot.event.EventEmitter;
8 | import com.viber.bot.event.incoming.*;
9 | import com.viber.bot.message.Message;
10 | import com.viber.bot.middleware.RequestReceiver;
11 | import com.viber.bot.profile.UserProfile;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import javax.annotation.Nonnull;
16 | import java.util.Map;
17 | import java.util.Optional;
18 | import java.util.concurrent.Future;
19 | import java.util.function.Consumer;
20 |
21 | import static com.google.common.base.Preconditions.checkNotNull;
22 |
23 | class RequestReceiverImpl implements RequestReceiver {
24 |
25 | private static final Logger logger = LoggerFactory.getLogger(RequestReceiverImpl.class);
26 | private static final ObjectMapper objectMapper = new ObjectMapper();
27 |
28 | private final EventEmitter eventEmitter;
29 | private final ViberBot bot;
30 |
31 | RequestReceiverImpl(final @Nonnull ViberBot bot, final @Nonnull EventEmitter eventEmitter) {
32 | this.bot = checkNotNull(bot);
33 | this.eventEmitter = checkNotNull(eventEmitter);
34 | }
35 |
36 | @Override
37 | public void acceptRequest(final @Nonnull Request request) {
38 | final IncomingEvent incomingEvent = request.getEvent();
39 | switch (incomingEvent.getEvent()) {
40 | case ERROR: {
41 | logger.error("Error from Viber servers: {}", ((IncomingErrorEvent) request.getEvent()).getDescription());
42 | break;
43 | }
44 |
45 | case CONVERSATION_STARTED: {
46 | final IncomingConversationStartedEvent incomingConversationStartedEvent = (IncomingConversationStartedEvent) request.getEvent();
47 | eventEmitter.>emit(incomingEvent.getEvent(), incomingEvent)
48 | .forEach(setReturnedResponse(request, incomingConversationStartedEvent.getUser()));
49 | break;
50 | }
51 |
52 | case MESSAGE_RECEIVED: {
53 | final IncomingMessageEvent incomingMessageEvent = (IncomingMessageEvent) request.getEvent();
54 | final Response response = new Response(incomingMessageEvent.getSender(), bot);
55 | eventEmitter.emit(incomingEvent.getEvent(), incomingEvent, incomingMessageEvent.getMessage(), response);
56 | break;
57 | }
58 |
59 | case SUBSCRIBED: {
60 | final IncomingSubscribedEvent incomingSubscribedEvent = (IncomingSubscribedEvent) request.getEvent();
61 | final Response response = new Response(incomingSubscribedEvent.getUser(), bot);
62 | eventEmitter.emit(incomingEvent.getEvent(), incomingEvent, response);
63 | break;
64 | }
65 |
66 | default: {
67 | eventEmitter.emit(incomingEvent.getEvent(), incomingEvent);
68 | break;
69 | }
70 | }
71 | }
72 |
73 | private Consumer>> setReturnedResponse(final Request request, final UserProfile userProfile) {
74 | return messageFuture -> {
75 |
76 | final Optional message = Futures.getUnchecked(messageFuture);
77 | if (!message.isPresent()) return;
78 |
79 | try {
80 | final String json = objectMapper.writeValueAsString(getMessageMapping(userProfile, message.get()));
81 | request.setResponse(json);
82 | } catch (final Exception e) {
83 | logger.error("Could not send back response to conversation started event", e);
84 | }
85 | };
86 | }
87 |
88 | private Map getMessageMapping(final UserProfile userProfile, final Message message) {
89 | return MessageToMapConverter.mapMessage(
90 | bot.getBotProfile(), userProfile, message,
91 | Optional.ofNullable(message.getKeyboard()),
92 | Optional.ofNullable(message.getTrackingData()));
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/BotEventListener.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event;
2 |
3 | import com.google.common.util.concurrent.Futures;
4 |
5 | import java.util.EventListener;
6 | import java.util.concurrent.Future;
7 |
8 | public interface BotEventListener extends EventListener, EventEmitter.EmittableEvent {
9 | Future nothing = Futures.immediateFuture(null);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/Event.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event;
2 |
3 | import javax.annotation.Nullable;
4 |
5 | public enum Event {
6 |
7 | MESSAGE_SENT,
8 | MESSAGE_RECEIVED("message"),
9 | MESSAGE_DELIVERED("delivered"),
10 | MESSAGE_SEEN("seen"),
11 |
12 | SUBSCRIBED("subscribed"),
13 | UNSUBSCRIBED("unsubscribed"),
14 |
15 | CONVERSATION_STARTED("conversation_started"),
16 | WEBHOOK("webhook"),
17 |
18 | ERROR("failed");
19 |
20 | private final String serverEventName;
21 |
22 | Event(final @Nullable String serverEventName) {
23 | this.serverEventName = serverEventName;
24 | }
25 |
26 | Event() {
27 | this(null);
28 | }
29 |
30 | @Nullable
31 | public String getServerEventName() {
32 | return serverEventName;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/EventEmitter.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event;
2 |
3 | import com.google.common.collect.ArrayListMultimap;
4 | import com.google.common.collect.Lists;
5 | import com.google.common.collect.Multimap;
6 |
7 | import javax.annotation.Nonnull;
8 | import java.util.Collection;
9 | import java.util.concurrent.Future;
10 |
11 | import static com.google.common.base.Preconditions.checkNotNull;
12 |
13 | public class EventEmitter {
14 |
15 | private final Multimap listeners = ArrayListMultimap.create();
16 |
17 | public void on(final @Nonnull Event event, final @Nonnull EmittableEvent listener) {
18 | listeners.put(checkNotNull(event), checkNotNull(listener));
19 | }
20 |
21 | public Collection> emit(final @Nonnull Event event, final Object... args) {
22 | final Collection> futures = Lists.newArrayList();
23 | listeners.get(event).forEach(listener -> futures.add(listener.emit(args)));
24 | return futures;
25 | }
26 |
27 | public interface EmittableEvent {
28 | Future emit(Object... args);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnConversationStarted.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.event.BotEventListener;
4 | import com.viber.bot.event.incoming.IncomingConversationStartedEvent;
5 | import com.viber.bot.message.Message;
6 |
7 | import java.util.Optional;
8 | import java.util.concurrent.Future;
9 |
10 | import static com.google.common.base.Preconditions.checkArgument;
11 |
12 | public interface OnConversationStarted extends BotEventListener> {
13 | Future> conversationStarted(IncomingConversationStartedEvent event);
14 |
15 | @Override
16 | default Future> emit(final Object... args) {
17 | checkArgument(args.length == 1);
18 | return conversationStarted((IncomingConversationStartedEvent) args[0]);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnMessageDelivered.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.event.BotEventListener;
4 | import com.viber.bot.event.incoming.IncomingDeliveredEvent;
5 | import com.viber.bot.message.Message;
6 |
7 | import java.util.concurrent.Future;
8 |
9 | import static com.google.common.base.Preconditions.checkArgument;
10 |
11 | public interface OnMessageDelivered extends BotEventListener {
12 | void messageDelivered(IncomingDeliveredEvent event, Message message);
13 |
14 | @Override
15 | default Future emit(final Object... args) {
16 | checkArgument(args.length == 2);
17 | messageDelivered((IncomingDeliveredEvent) args[0], (Message) args[1]);
18 | return nothing;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnMessageReceived.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.Response;
4 | import com.viber.bot.event.BotEventListener;
5 | import com.viber.bot.event.incoming.IncomingMessageEvent;
6 | import com.viber.bot.message.Message;
7 |
8 | import java.util.concurrent.Future;
9 |
10 | import static com.google.common.base.Preconditions.checkArgument;
11 |
12 | public interface OnMessageReceived extends BotEventListener {
13 | void messageReceived(IncomingMessageEvent event, Message message, Response response);
14 |
15 | @Override
16 | default Future emit(final Object... args) {
17 | checkArgument(args.length == 3);
18 | messageReceived((IncomingMessageEvent) args[0], (Message) args[1], (Response) args[2]);
19 | return nothing;
20 | }
21 | }
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnMessageSeen.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.event.BotEventListener;
4 | import com.viber.bot.event.incoming.IncomingSeenEvent;
5 |
6 | import java.util.concurrent.Future;
7 |
8 | import static com.google.common.base.Preconditions.checkArgument;
9 |
10 | public interface OnMessageSeen extends BotEventListener {
11 | void messageSeen(IncomingSeenEvent event);
12 |
13 | @Override
14 | default Future emit(final Object... args) {
15 | checkArgument(args.length == 1);
16 | messageSeen((IncomingSeenEvent) args[0]);
17 | return nothing;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnMessageSent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.event.BotEventListener;
4 | import com.viber.bot.message.Message;
5 | import com.viber.bot.profile.UserProfile;
6 |
7 | import java.util.concurrent.Future;
8 |
9 | import static com.google.common.base.Preconditions.checkArgument;
10 |
11 | public interface OnMessageSent extends BotEventListener {
12 | void messageSent(UserProfile to, Message message);
13 |
14 | @Override
15 | default Future emit(final Object... args) {
16 | checkArgument(args.length == 2);
17 | messageSent((UserProfile) args[0], (Message) args[1]);
18 | return nothing;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnSubscribe.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.Response;
4 | import com.viber.bot.event.BotEventListener;
5 | import com.viber.bot.event.incoming.IncomingSubscribedEvent;
6 |
7 | import java.util.concurrent.Future;
8 |
9 | import static com.google.common.base.Preconditions.checkArgument;
10 |
11 | public interface OnSubscribe extends BotEventListener {
12 | void subscribe(IncomingSubscribedEvent event, Response response);
13 |
14 | @Override
15 | default Future emit(final Object... args) {
16 | checkArgument(args.length == 2);
17 | subscribe((IncomingSubscribedEvent) args[0], (Response) args[1]);
18 | return nothing;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/callback/OnUnsubscribe.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.callback;
2 |
3 | import com.viber.bot.event.BotEventListener;
4 | import com.viber.bot.event.incoming.IncomingUnsubscribeEvent;
5 |
6 | import java.util.concurrent.Future;
7 |
8 | import static com.google.common.base.Preconditions.checkArgument;
9 |
10 | public interface OnUnsubscribe extends BotEventListener {
11 | void unsubscribe(IncomingUnsubscribeEvent event);
12 |
13 | @Override
14 | default Future emit(final Object... args) {
15 | checkArgument(args.length == 1);
16 | unsubscribe((IncomingUnsubscribeEvent) args[0]);
17 | return nothing;
18 | }
19 | }
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingConversationStartedEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.google.common.base.Strings;
6 | import com.viber.bot.event.Event;
7 | import com.viber.bot.profile.UserProfile;
8 |
9 | import javax.annotation.Nonnull;
10 | import javax.annotation.Nullable;
11 | import javax.annotation.concurrent.Immutable;
12 |
13 | import static com.google.common.base.Preconditions.checkNotNull;
14 | import static com.viber.bot.Preconditions.checkNotEmpty;
15 |
16 | @Immutable
17 | public class IncomingConversationStartedEvent extends IncomingEvent {
18 |
19 | private final UserProfile user;
20 | private final String type;
21 | private final long token;
22 | private final boolean subscribed;
23 |
24 | @Nullable
25 | private final String context;
26 |
27 | @JsonCreator
28 | IncomingConversationStartedEvent(final @JsonProperty("type") @Nonnull String type,
29 | final @JsonProperty("user") @Nonnull UserProfile user,
30 | final @JsonProperty("context") String context,
31 | final @JsonProperty("message_token") long token,
32 | final @JsonProperty("timestamp") long timestamp,
33 | final @JsonProperty("subscribed") boolean subscribed) {
34 | super(Event.CONVERSATION_STARTED, timestamp);
35 | this.user = checkNotNull(user);
36 | this.type = checkNotEmpty(type);
37 | this.context = Strings.emptyToNull(context);
38 | this.token = token;
39 | this.subscribed = subscribed;
40 | }
41 |
42 | public String getType() {
43 | return type;
44 | }
45 |
46 | public long getToken() {
47 | return token;
48 | }
49 |
50 | public UserProfile getUser() {
51 | return user;
52 | }
53 |
54 | public boolean isSubscribed() {
55 | return subscribed;
56 | }
57 |
58 | @Nullable
59 | public String getContext() {
60 | return context;
61 | }
62 |
63 | @Override
64 | public boolean equals(Object o) {
65 | if (this == o) return true;
66 | if (o == null || getClass() != o.getClass()) return false;
67 | if (!super.equals(o)) return false;
68 |
69 | IncomingConversationStartedEvent that = (IncomingConversationStartedEvent) o;
70 |
71 | if (token != that.token) return false;
72 | if (subscribed != that.subscribed) return false;
73 | if (user != null ? !user.equals(that.user) : that.user != null) return false;
74 | if (type != null ? !type.equals(that.type) : that.type != null) return false;
75 | return context != null ? context.equals(that.context) : that.context == null;
76 |
77 | }
78 |
79 | @Override
80 | public int hashCode() {
81 | int result = super.hashCode();
82 | result = 31 * result + (user != null ? user.hashCode() : 0);
83 | result = 31 * result + (type != null ? type.hashCode() : 0);
84 | result = 31 * result + (int) (token ^ (token >>> 32));
85 | result = 31 * result + (subscribed ? 1 : 0);
86 | result = 31 * result + (context != null ? context.hashCode() : 0);
87 | return result;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingDeliveredEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.concurrent.Immutable;
9 |
10 | import static com.viber.bot.Preconditions.checkNotEmpty;
11 |
12 | @Immutable
13 | public class IncomingDeliveredEvent extends IncomingEvent {
14 |
15 | private final String userId;
16 | private final Long token;
17 |
18 | @JsonCreator
19 | IncomingDeliveredEvent(final @JsonProperty("user_id") @Nonnull String userId,
20 | final @JsonProperty("message_token") long token,
21 | final @JsonProperty("timestamp") long timestamp) {
22 | super(Event.MESSAGE_DELIVERED, timestamp);
23 | this.userId = checkNotEmpty(userId);
24 | this.token = token;
25 | }
26 |
27 | public Long getToken() {
28 | return token;
29 | }
30 |
31 | public String getUserId() {
32 | return userId;
33 | }
34 |
35 | @Override
36 | public boolean equals(final Object o) {
37 | if (this == o) return true;
38 | if (o == null || getClass() != o.getClass()) return false;
39 | if (!super.equals(o)) return false;
40 |
41 | final IncomingDeliveredEvent that = (IncomingDeliveredEvent) o;
42 |
43 | if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
44 | return token != null ? token.equals(that.token) : that.token == null;
45 | }
46 |
47 | @Override
48 | public int hashCode() {
49 | int result = super.hashCode();
50 | result = 31 * result + (userId != null ? userId.hashCode() : 0);
51 | result = 31 * result + (token != null ? token.hashCode() : 0);
52 | return result;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingErrorEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.concurrent.Immutable;
9 |
10 | import static com.viber.bot.Preconditions.checkNotEmpty;
11 |
12 | @Immutable
13 | public class IncomingErrorEvent extends IncomingEvent {
14 |
15 | private final String userId;
16 | private final String description;
17 | private final Long token;
18 |
19 | @JsonCreator
20 | IncomingErrorEvent(final @JsonProperty("user_id") @Nonnull String userId,
21 | final @JsonProperty("desc") @Nonnull String description,
22 | final @JsonProperty("message_token") long token,
23 | final @JsonProperty("timestamp") long timestamp) {
24 | super(Event.ERROR, timestamp);
25 | this.userId = checkNotEmpty(userId);
26 | this.description = checkNotEmpty(description);
27 | this.token = token;
28 | }
29 |
30 | public String getDescription() {
31 | return description;
32 | }
33 |
34 | public Long getToken() {
35 | return token;
36 | }
37 |
38 | public String getUserId() {
39 | return userId;
40 | }
41 |
42 | @Override
43 | public boolean equals(final Object o) {
44 | if (this == o) return true;
45 | if (o == null || getClass() != o.getClass()) return false;
46 | if (!super.equals(o)) return false;
47 |
48 | final IncomingErrorEvent that = (IncomingErrorEvent) o;
49 |
50 | if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
51 | if (description != null ? !description.equals(that.description) : that.description != null) return false;
52 | return token != null ? token.equals(that.token) : that.token == null;
53 | }
54 |
55 | @Override
56 | public int hashCode() {
57 | int result = super.hashCode();
58 | result = 31 * result + (userId != null ? userId.hashCode() : 0);
59 | result = 31 * result + (description != null ? description.hashCode() : 0);
60 | result = 31 * result + (token != null ? token.hashCode() : 0);
61 | return result;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import com.fasterxml.jackson.annotation.JsonSubTypes;
5 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 | import com.viber.bot.event.Event;
7 |
8 | import javax.annotation.Nonnull;
9 | import javax.annotation.concurrent.Immutable;
10 |
11 | import static com.google.common.base.Preconditions.checkNotNull;
12 |
13 | @Immutable
14 | @JsonIgnoreProperties(ignoreUnknown = true)
15 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "event")
16 | @JsonSubTypes({
17 | @JsonSubTypes.Type(value = IncomingMessageEvent.class, name = "message"),
18 | @JsonSubTypes.Type(value = IncomingWebhookEvent.class, name = "webhook"),
19 | @JsonSubTypes.Type(value = IncomingSeenEvent.class, name = "seen"),
20 | @JsonSubTypes.Type(value = IncomingDeliveredEvent.class, name = "delivered"),
21 | @JsonSubTypes.Type(value = IncomingSubscribedEvent.class, name = "subscribed"),
22 | @JsonSubTypes.Type(value = IncomingUnsubscribeEvent.class, name = "unsubscribed"),
23 | @JsonSubTypes.Type(value = IncomingConversationStartedEvent.class, name = "conversation_started"),
24 | @JsonSubTypes.Type(value = IncomingErrorEvent.class, name = "failed")
25 | })
26 | public class IncomingEvent {
27 |
28 | private final Event event;
29 | private final long timestamp;
30 |
31 | IncomingEvent(final @Nonnull Event event, final long timestamp) {
32 | this.event = checkNotNull(event);
33 | this.timestamp = timestamp;
34 | }
35 |
36 | public Event getEvent() {
37 | return event;
38 | }
39 |
40 | public long getTimestamp() {
41 | return timestamp;
42 | }
43 |
44 | @Override
45 | public boolean equals(final Object o) {
46 | if (this == o) return true;
47 | if (o == null || getClass() != o.getClass()) return false;
48 |
49 | final IncomingEvent that = (IncomingEvent) o;
50 |
51 | if (timestamp != that.timestamp) return false;
52 |
53 | return true;
54 | }
55 |
56 | @Override
57 | public int hashCode() {
58 | return (int) (timestamp ^ (timestamp >>> 32));
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingMessageEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 | import com.viber.bot.message.Message;
7 | import com.viber.bot.profile.UserProfile;
8 |
9 | import javax.annotation.Nonnull;
10 | import javax.annotation.concurrent.Immutable;
11 |
12 | import static com.google.common.base.Preconditions.checkNotNull;
13 |
14 | @Immutable
15 | public class IncomingMessageEvent extends IncomingEvent {
16 |
17 | private final Long token;
18 | private final Message message;
19 | private final UserProfile sender;
20 |
21 | @JsonCreator
22 | IncomingMessageEvent(final @JsonProperty("message") @Nonnull Message message,
23 | final @JsonProperty("sender") @Nonnull UserProfile sender,
24 | final @JsonProperty("message_token") long token,
25 | final @JsonProperty("timestamp") long timestamp) {
26 | super(Event.MESSAGE_RECEIVED, timestamp);
27 | this.message = checkNotNull(message);
28 | this.sender = checkNotNull(sender);
29 | this.token = token;
30 | }
31 |
32 | public Long getToken() {
33 | return token;
34 | }
35 |
36 | public Message getMessage() {
37 | return message;
38 | }
39 |
40 | public UserProfile getSender() {
41 | return sender;
42 | }
43 |
44 | @Override
45 | public boolean equals(final Object o) {
46 | if (this == o) return true;
47 | if (o == null || getClass() != o.getClass()) return false;
48 | if (!super.equals(o)) return false;
49 |
50 | final IncomingMessageEvent that = (IncomingMessageEvent) o;
51 |
52 | if (token != null ? !token.equals(that.token) : that.token != null) return false;
53 | if (message != null ? !message.equals(that.message) : that.message != null) return false;
54 | if (sender != null ? !sender.equals(that.sender) : that.sender != null) return false;
55 |
56 | return true;
57 | }
58 |
59 | @Override
60 | public int hashCode() {
61 | int result = super.hashCode();
62 | result = 31 * result + (token != null ? token.hashCode() : 0);
63 | result = 31 * result + (message != null ? message.hashCode() : 0);
64 | result = 31 * result + (sender != null ? sender.hashCode() : 0);
65 | return result;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingSeenEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.concurrent.Immutable;
9 |
10 | import static com.viber.bot.Preconditions.checkNotEmpty;
11 |
12 | @Immutable
13 | public class IncomingSeenEvent extends IncomingEvent {
14 |
15 | private final String userId;
16 | private final Long token;
17 |
18 | @JsonCreator
19 | IncomingSeenEvent(final @JsonProperty("user_id") @Nonnull String userId,
20 | final @JsonProperty("message_token") long token,
21 | final @JsonProperty("timestamp") long timestamp) {
22 | super(Event.MESSAGE_SEEN, timestamp);
23 | this.userId = checkNotEmpty(userId);
24 | this.token = token;
25 | }
26 |
27 | public Long getToken() {
28 | return token;
29 | }
30 |
31 | public String getUserId() {
32 | return userId;
33 | }
34 |
35 | @Override
36 | public boolean equals(final Object o) {
37 | if (this == o) return true;
38 | if (o == null || getClass() != o.getClass()) return false;
39 | if (!super.equals(o)) return false;
40 |
41 | final IncomingSeenEvent that = (IncomingSeenEvent) o;
42 |
43 | if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
44 | return token != null ? token.equals(that.token) : that.token == null;
45 | }
46 |
47 | @Override
48 | public int hashCode() {
49 | int result = super.hashCode();
50 | result = 31 * result + (userId != null ? userId.hashCode() : 0);
51 | result = 31 * result + (token != null ? token.hashCode() : 0);
52 | return result;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingSubscribedEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 | import com.viber.bot.profile.UserProfile;
7 |
8 | import javax.annotation.Nonnull;
9 | import javax.annotation.concurrent.Immutable;
10 |
11 | @Immutable
12 | public class IncomingSubscribedEvent extends IncomingEvent {
13 |
14 | private final UserProfile user;
15 |
16 | @JsonCreator
17 | IncomingSubscribedEvent(final @JsonProperty("user") @Nonnull UserProfile user,
18 | final @JsonProperty("timestamp") long timestamp) {
19 | super(Event.SUBSCRIBED, timestamp);
20 | this.user = user;
21 | }
22 |
23 | public UserProfile getUser() {
24 | return user;
25 | }
26 |
27 | @Override
28 | public boolean equals(final Object o) {
29 | if (this == o) return true;
30 | if (o == null || getClass() != o.getClass()) return false;
31 | if (!super.equals(o)) return false;
32 |
33 | final IncomingSubscribedEvent that = (IncomingSubscribedEvent) o;
34 |
35 | return user != null ? user.equals(that.user) : that.user == null;
36 |
37 | }
38 |
39 | @Override
40 | public int hashCode() {
41 | int result = super.hashCode();
42 | result = 31 * result + (user != null ? user.hashCode() : 0);
43 | return result;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingUnsubscribeEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.concurrent.Immutable;
9 |
10 | import static com.viber.bot.Preconditions.checkNotEmpty;
11 |
12 | @Immutable
13 | public class IncomingUnsubscribeEvent extends IncomingEvent {
14 |
15 | private final String userId;
16 |
17 | @JsonCreator
18 | IncomingUnsubscribeEvent(final @JsonProperty("user_id") @Nonnull String userId,
19 | final @JsonProperty("timestamp") long timestamp) {
20 | super(Event.UNSUBSCRIBED, timestamp);
21 | this.userId = checkNotEmpty(userId);
22 | }
23 |
24 | public String getUserId() {
25 | return userId;
26 | }
27 |
28 | @Override
29 | public boolean equals(final Object o) {
30 | if (this == o) return true;
31 | if (o == null || getClass() != o.getClass()) return false;
32 | if (!super.equals(o)) return false;
33 |
34 | final IncomingUnsubscribeEvent that = (IncomingUnsubscribeEvent) o;
35 |
36 | return userId != null ? userId.equals(that.userId) : that.userId == null;
37 | }
38 |
39 | @Override
40 | public int hashCode() {
41 | int result = super.hashCode();
42 | result = 31 * result + (userId != null ? userId.hashCode() : 0);
43 | return result;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/event/incoming/IncomingWebhookEvent.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event.incoming;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.viber.bot.event.Event;
6 |
7 | import javax.annotation.concurrent.Immutable;
8 |
9 | @Immutable
10 | public class IncomingWebhookEvent extends IncomingEvent {
11 |
12 | private final Long token;
13 |
14 | @JsonCreator
15 | IncomingWebhookEvent(final @JsonProperty("message_token") long token,
16 | final @JsonProperty("timestamp") long timestamp) {
17 | super(Event.WEBHOOK, timestamp);
18 | this.token = token;
19 | }
20 |
21 | public Long getToken() {
22 | return token;
23 | }
24 |
25 | @Override
26 | public boolean equals(final Object o) {
27 | if (this == o) return true;
28 | if (o == null || getClass() != o.getClass()) return false;
29 | if (!super.equals(o)) return false;
30 |
31 | final IncomingWebhookEvent that = (IncomingWebhookEvent) o;
32 |
33 | return token != null ? token.equals(that.token) : that.token == null;
34 | }
35 |
36 | @Override
37 | public int hashCode() {
38 | int result = super.hashCode();
39 | result = 31 * result + (token != null ? token.hashCode() : 0);
40 | return result;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/Contact.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.google.common.base.Strings;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import javax.annotation.concurrent.Immutable;
10 |
11 | import static com.viber.bot.Preconditions.checkNotEmpty;
12 |
13 | @Immutable
14 | public class Contact {
15 |
16 | private final String name;
17 | private final String phoneNumber;
18 |
19 | @Nullable
20 | private final String avatar;
21 |
22 | @JsonCreator
23 | public Contact(final @JsonProperty("name") @Nonnull String contactName,
24 | final @JsonProperty("phone_number") @Nonnull String contactPhoneNumber,
25 | final @JsonProperty("avatar") @Nullable String avatar) {
26 | this.name = checkNotEmpty(contactName);
27 | this.phoneNumber = checkNotEmpty(contactPhoneNumber);
28 | this.avatar = Strings.emptyToNull(avatar);
29 | }
30 |
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public String getPhoneNumber() {
36 | return phoneNumber;
37 | }
38 |
39 | @Nullable
40 | public String getAvatar() {
41 | return avatar;
42 | }
43 |
44 | @Override
45 | public boolean equals(Object o) {
46 | if (this == o) return true;
47 | if (o == null || getClass() != o.getClass()) return false;
48 |
49 | Contact contact = (Contact) o;
50 |
51 | if (name != null ? !name.equals(contact.name) : contact.name != null) return false;
52 | if (phoneNumber != null ? !phoneNumber.equals(contact.phoneNumber) : contact.phoneNumber != null) return false;
53 | return avatar != null ? avatar.equals(contact.avatar) : contact.avatar == null;
54 | }
55 |
56 | @Override
57 | public int hashCode() {
58 | int result = name != null ? name.hashCode() : 0;
59 | result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0);
60 | result = 31 * result + (avatar != null ? avatar.hashCode() : 0);
61 | return result;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/ContactMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import javax.annotation.concurrent.Immutable;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import static com.google.common.base.Preconditions.checkNotNull;
14 |
15 | @Immutable
16 | public class ContactMessage extends Message {
17 |
18 | private final Contact contact;
19 |
20 | @JsonCreator
21 | public ContactMessage(final @JsonProperty("contact") @Nonnull Contact contact,
22 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
23 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
24 | super("contact", keyboard, trackingData);
25 | this.contact = checkNotNull(contact);
26 | }
27 |
28 | @JsonIgnore
29 | public ContactMessage(final @Nonnull Contact contact) {
30 | this(contact, null, null);
31 | }
32 |
33 | @Override
34 | protected Map getPartialMapRepresentation() {
35 | return new HashMap() {{
36 | put("contact", new HashMap() {{
37 | put("name", getContact().getName());
38 | put("phone_number", getContact().getPhoneNumber());
39 | put("avatar", getContact().getAvatar());
40 | }});
41 | }};
42 | }
43 |
44 | public Contact getContact() {
45 | return contact;
46 | }
47 |
48 | @Override
49 | public boolean equals(final Object o) {
50 | if (this == o) return true;
51 | if (o == null || getClass() != o.getClass()) return false;
52 | if (!super.equals(o)) return false;
53 |
54 | final ContactMessage that = (ContactMessage) o;
55 |
56 | return contact != null ? contact.equals(that.contact) : that.contact == null;
57 | }
58 |
59 | @Override
60 | public int hashCode() {
61 | int result = super.hashCode();
62 | result = 31 * result + (contact != null ? contact.hashCode() : 0);
63 | return result;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/FileMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import javax.annotation.concurrent.Immutable;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import static com.viber.bot.Preconditions.checkNotEmpty;
14 |
15 | @Immutable
16 | public class FileMessage extends Message {
17 |
18 | private final String url;
19 | private final int sizeInBytes;
20 | private final String filename;
21 |
22 | @JsonCreator
23 | public FileMessage(final @JsonProperty("media") @Nonnull String url,
24 | final @JsonProperty("size") int sizeInBytes,
25 | final @JsonProperty("file_name") @Nonnull String filename,
26 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
27 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
28 | super("file", keyboard, trackingData);
29 | this.url = checkNotEmpty(url);
30 | this.sizeInBytes = sizeInBytes;
31 | this.filename = checkNotEmpty(filename);
32 | }
33 |
34 | @JsonIgnore
35 | public FileMessage(final @Nonnull String url, final int sizeInBytes, final @Nonnull String filename) {
36 | this(url, sizeInBytes, filename, null, null);
37 | }
38 |
39 | @Override
40 | protected Map getPartialMapRepresentation() {
41 | return new HashMap() {{
42 | put("media", getUrl());
43 | put("size", getSizeInBytes());
44 | put("file_name", getFilename());
45 | }};
46 | }
47 |
48 | public String getUrl() {
49 | return url;
50 | }
51 |
52 | public int getSizeInBytes() {
53 | return sizeInBytes;
54 | }
55 |
56 | public String getFilename() {
57 | return filename;
58 | }
59 |
60 | @Override
61 | public boolean equals(final Object o) {
62 | if (this == o) return true;
63 | if (o == null || getClass() != o.getClass()) return false;
64 | if (!super.equals(o)) return false;
65 |
66 | final FileMessage that = (FileMessage) o;
67 |
68 | if (sizeInBytes != that.sizeInBytes) return false;
69 | if (url != null ? !url.equals(that.url) : that.url != null) return false;
70 | return filename != null ? filename.equals(that.filename) : that.filename == null;
71 | }
72 |
73 | @Override
74 | public int hashCode() {
75 | int result = super.hashCode();
76 | result = 31 * result + (url != null ? url.hashCode() : 0);
77 | result = 31 * result + sizeInBytes;
78 | result = 31 * result + (filename != null ? filename.hashCode() : 0);
79 | return result;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/Location.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import javax.annotation.concurrent.Immutable;
7 |
8 | @Immutable
9 | public class Location {
10 |
11 | private final float latitude;
12 | private final float longitude;
13 |
14 | @JsonCreator
15 | public Location(final @JsonProperty("lat") float latitude,
16 | final @JsonProperty("lon") float longitude) {
17 | this.latitude = latitude;
18 | this.longitude = longitude;
19 | }
20 |
21 | public float getLatitude() {
22 | return latitude;
23 | }
24 |
25 | public float getLongitude() {
26 | return longitude;
27 | }
28 |
29 | @Override
30 | public boolean equals(final Object o) {
31 | if (this == o) return true;
32 | if (o == null || getClass() != o.getClass()) return false;
33 |
34 | final Location location = (Location) o;
35 |
36 | if (Float.compare(location.latitude, latitude) != 0) return false;
37 | return Float.compare(location.longitude, longitude) == 0;
38 | }
39 |
40 | @Override
41 | public int hashCode() {
42 | int result = (latitude != +0.0f ? Float.floatToIntBits(latitude) : 0);
43 | result = 31 * result + (longitude != +0.0f ? Float.floatToIntBits(longitude) : 0);
44 | return result;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/LocationMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import javax.annotation.concurrent.Immutable;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import static com.google.common.base.Preconditions.checkNotNull;
14 |
15 | @Immutable
16 | public class LocationMessage extends Message {
17 |
18 | private final Location location;
19 |
20 | @JsonCreator
21 | public LocationMessage(final @JsonProperty("location") @Nonnull Location location,
22 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
23 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
24 | super("location", keyboard, trackingData);
25 | this.location = checkNotNull(location);
26 | }
27 |
28 | @JsonIgnore
29 | public LocationMessage(final @Nonnull Location location) {
30 | this(location, null, null);
31 | }
32 |
33 | @Override
34 | protected Map getPartialMapRepresentation() {
35 | return new HashMap() {{
36 | put("location", new HashMap() {{
37 | put("lat", getLocation().getLatitude());
38 | put("lon", getLocation().getLongitude());
39 | }});
40 | }};
41 | }
42 |
43 | public Location getLocation() {
44 | return location;
45 | }
46 |
47 | @Override
48 | public boolean equals(final Object o) {
49 | if (this == o) return true;
50 | if (o == null || getClass() != o.getClass()) return false;
51 | if (!super.equals(o)) return false;
52 |
53 | final LocationMessage that = (LocationMessage) o;
54 |
55 | return location != null ? location.equals(that.location) : that.location == null;
56 | }
57 |
58 | @Override
59 | public int hashCode() {
60 | int result = super.hashCode();
61 | result = 31 * result + (location != null ? location.hashCode() : 0);
62 | return result;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/Message.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAnyGetter;
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5 | import com.fasterxml.jackson.annotation.JsonSubTypes;
6 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
7 | import com.google.common.base.MoreObjects;
8 | import com.google.common.base.Strings;
9 |
10 | import javax.annotation.Nonnull;
11 | import javax.annotation.Nullable;
12 | import javax.annotation.concurrent.Immutable;
13 | import java.util.HashMap;
14 | import java.util.Map;
15 |
16 | import static com.viber.bot.Preconditions.checkNotEmpty;
17 |
18 | @Immutable
19 | @JsonIgnoreProperties(ignoreUnknown = true)
20 | @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
21 | @JsonSubTypes({
22 | @JsonSubTypes.Type(value = RichMediaMessage.class, name = "rich_media"),
23 | @JsonSubTypes.Type(value = TextMessage.class, name = "text"),
24 | @JsonSubTypes.Type(value = ContactMessage.class, name = "contact"),
25 | @JsonSubTypes.Type(value = FileMessage.class, name = "file"),
26 | @JsonSubTypes.Type(value = LocationMessage.class, name = "location"),
27 | @JsonSubTypes.Type(value = PictureMessage.class, name = "picture"),
28 | @JsonSubTypes.Type(value = StickerMessage.class, name = "sticker"),
29 | @JsonSubTypes.Type(value = UrlMessage.class, name = "url"),
30 | @JsonSubTypes.Type(value = VideoMessage.class, name = "video")
31 | })
32 | public abstract class Message { // todo: should be case classes when moving to scala
33 |
34 | private final String type;
35 | private final MessageKeyboard keyboard;
36 | private final TrackingData trackingData;
37 |
38 | Message(final @Nonnull String type,
39 | final @Nullable MessageKeyboard keyboard,
40 | final @Nullable TrackingData trackingData) {
41 |
42 | this.type = checkNotEmpty(type);
43 | this.keyboard = MoreObjects.firstNonNull(keyboard, new MessageKeyboard());
44 | this.trackingData = MoreObjects.firstNonNull(trackingData, new TrackingData());
45 | }
46 |
47 | public String getType() {
48 | return type;
49 | }
50 |
51 | public MessageKeyboard getKeyboard() {
52 | return keyboard;
53 | }
54 |
55 | public TrackingData getTrackingData() {
56 | return trackingData;
57 | }
58 |
59 | @JsonAnyGetter
60 | public Map getMapRepresentation() {
61 | return new HashMap() {{
62 | put("type", getType());
63 | putAll(getPartialMapRepresentation());
64 | }};
65 | }
66 |
67 | protected abstract Map getPartialMapRepresentation();
68 |
69 | @Override
70 | public boolean equals(final Object o) {
71 | if (this == o) return true;
72 | if (o == null || getClass() != o.getClass()) return false;
73 |
74 | final Message message = (Message) o;
75 |
76 | if (type != null ? !type.equals(message.type) : message.type != null) return false;
77 | if (keyboard != null ? !keyboard.equals(message.keyboard) : message.keyboard != null) return false;
78 | return trackingData != null ? trackingData.equals(message.trackingData) : message.trackingData == null;
79 | }
80 |
81 | @Override
82 | public int hashCode() {
83 | int result = type != null ? type.hashCode() : 0;
84 | result = 31 * result + (keyboard != null ? keyboard.hashCode() : 0);
85 | result = 31 * result + (trackingData != null ? trackingData.hashCode() : 0);
86 | return result;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/MessageKeyboard.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.core.JsonParseException;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.JsonDeserializer;
8 | import com.fasterxml.jackson.databind.JsonMappingException;
9 | import com.fasterxml.jackson.databind.ObjectMapper;
10 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
11 | import com.google.common.base.MoreObjects;
12 | import com.google.common.base.Strings;
13 | import com.google.common.collect.ForwardingMap;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import javax.annotation.Nullable;
18 | import javax.annotation.concurrent.Immutable;
19 | import java.io.IOException;
20 | import java.util.Collections;
21 | import java.util.Map;
22 |
23 | /**
24 | * Simple Map(String, Object) wrapper class.
25 | */
26 | @Immutable
27 | @JsonDeserialize(using = MessageKeyboard.KeyboardDeserializer.class)
28 | public class MessageKeyboard extends ForwardingMap {
29 | private final Map map;
30 |
31 | public MessageKeyboard(final @Nullable Map delegate) {
32 | this.map = Collections.unmodifiableMap(MoreObjects.firstNonNull(delegate, Collections.emptyMap()));
33 | }
34 |
35 | public MessageKeyboard() {
36 | this(null);
37 | }
38 |
39 | @Override
40 | protected Map delegate() {
41 | return map;
42 | }
43 |
44 | static class KeyboardDeserializer extends JsonDeserializer {
45 | private static final Logger logger = LoggerFactory.getLogger(KeyboardDeserializer.class);
46 | private static final ObjectMapper objectMapper = new ObjectMapper();
47 | private static final String EMPTY_JSON_OBJECT = "{}";
48 |
49 | @Override
50 | public MessageKeyboard deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
51 | Map messageKeyboard = null;
52 | try {
53 | messageKeyboard = objectMapper.readValue(MoreObjects.firstNonNull(
54 | Strings.emptyToNull(p.getValueAsString().trim()), EMPTY_JSON_OBJECT), Map.class);
55 | } catch (JsonMappingException | JsonParseException exception) {
56 | logger.warn("Could not deserialize message keyboard '{}'", p.getValueAsString().trim());
57 | }
58 | return new MessageKeyboard(messageKeyboard);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/PictureMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.google.common.base.Strings;
7 |
8 | import javax.annotation.Nonnull;
9 | import javax.annotation.Nullable;
10 | import javax.annotation.concurrent.Immutable;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | import static com.viber.bot.Preconditions.checkNotEmpty;
15 |
16 | @Immutable
17 | public class PictureMessage extends Message {
18 |
19 | private final String url;
20 |
21 | @Nullable
22 | private final String text;
23 |
24 | @Nullable
25 | private final String thumbnail;
26 |
27 | @JsonCreator
28 | public PictureMessage(final @JsonProperty("media") @Nonnull String url,
29 | final @JsonProperty("text") @Nullable String text,
30 | final @JsonProperty("thumbnail") @Nullable String thumbnail,
31 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
32 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
33 | super("picture", keyboard, trackingData);
34 | this.url = checkNotEmpty(url);
35 | this.text = Strings.emptyToNull(text);
36 | this.thumbnail = Strings.emptyToNull(thumbnail);
37 | }
38 |
39 | @JsonIgnore
40 | public PictureMessage(final @Nonnull String url, final @Nullable String text, final @Nullable String thumbnail) {
41 | this(url, text, thumbnail, null, null);
42 | }
43 |
44 | @Override
45 | protected Map getPartialMapRepresentation() {
46 | return new HashMap() {{
47 | put("media", getUrl());
48 | put("text", getText());
49 | put("thumbnail", getThumbnail());
50 | }};
51 | }
52 |
53 | public String getUrl() {
54 | return url;
55 | }
56 |
57 | @Nullable
58 | public String getText() {
59 | return text;
60 | }
61 |
62 | @Nullable
63 | public String getThumbnail() {
64 | return thumbnail;
65 | }
66 |
67 | @Override
68 | public boolean equals(final Object o) {
69 | if (this == o) return true;
70 | if (o == null || getClass() != o.getClass()) return false;
71 | if (!super.equals(o)) return false;
72 |
73 | final PictureMessage that = (PictureMessage) o;
74 |
75 | if (text != null ? !text.equals(that.text) : that.text != null) return false;
76 | if (url != null ? !url.equals(that.url) : that.url != null) return false;
77 | return thumbnail != null ? thumbnail.equals(that.thumbnail) : that.thumbnail == null;
78 | }
79 |
80 | @Override
81 | public int hashCode() {
82 | int result = super.hashCode();
83 | result = 31 * result + (text != null ? text.hashCode() : 0);
84 | result = 31 * result + (url != null ? url.hashCode() : 0);
85 | result = 31 * result + (thumbnail != null ? thumbnail.hashCode() : 0);
86 | return result;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/RichMediaMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import javax.annotation.concurrent.Immutable;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 | import java.util.Optional;
13 |
14 | import static com.google.common.base.Preconditions.checkNotNull;
15 |
16 | @Immutable
17 | public class RichMediaMessage extends Message {
18 |
19 | private final static int RICH_MEDIA_MINIMUM_API_VERSION = 2;
20 |
21 | @Nonnull
22 | private final RichMediaObject richMediaObject;
23 |
24 | @Nullable
25 | private final String alternativeText;
26 |
27 | @Nullable
28 | private final Integer minimalApiVersion;
29 |
30 | @JsonCreator
31 | public RichMediaMessage(final @JsonProperty("rich_media") @Nonnull RichMediaObject richMediaObject,
32 | final @JsonProperty("alt_text") @Nullable String alternativeText,
33 | final @JsonProperty("min_api_version") @Nullable Integer minimalApiVersion,
34 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
35 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
36 | super("rich_media", keyboard, trackingData);
37 | this.richMediaObject = checkNotNull(richMediaObject);
38 | this.alternativeText = alternativeText;
39 | this.minimalApiVersion = minimalApiVersion;
40 | }
41 |
42 | @JsonIgnore
43 | public RichMediaMessage(final RichMediaObject richMedia, final String alternativeText, final Integer minimalApiVersion) {
44 | this(richMedia, alternativeText, minimalApiVersion, null, null);
45 | }
46 |
47 | @Override
48 | protected Map getPartialMapRepresentation() {
49 | return new HashMap() {{
50 | put("rich_media", getRichMediaObject());
51 | put("alt_text", getAlternativeText());
52 | put("min_api_version", getMinimalApiVersion().orElse(RICH_MEDIA_MINIMUM_API_VERSION));
53 | }};
54 | }
55 |
56 | @Nonnull
57 | public RichMediaObject getRichMediaObject() {
58 | return richMediaObject;
59 | }
60 |
61 | @Nullable
62 | public String getAlternativeText() {
63 | return alternativeText;
64 | }
65 |
66 | @Nullable
67 | public Optional getMinimalApiVersion() {
68 | return Optional.ofNullable(minimalApiVersion);
69 | }
70 |
71 | @Override
72 | public boolean equals(final Object o) {
73 | if (this == o) return true;
74 | if (o == null || getClass() != o.getClass()) return false;
75 | if (!super.equals(o)) return false;
76 |
77 | final RichMediaMessage that = (RichMediaMessage) o;
78 |
79 | if (!richMediaObject.equals(that.richMediaObject)) return false;
80 | if (minimalApiVersion != null ? !minimalApiVersion.equals(that.minimalApiVersion) : that.minimalApiVersion != null)
81 | return false;
82 | return alternativeText != null ? !alternativeText.equals(that.alternativeText) : that.alternativeText != null;
83 | }
84 |
85 | @Override
86 | public int hashCode() {
87 | int result = super.hashCode();
88 | result = 31 * result + richMediaObject.hashCode();
89 | result = 31 * result + (minimalApiVersion != null ? minimalApiVersion.hashCode() : 0);
90 | result = 31 * result + (alternativeText != null ? alternativeText.hashCode() : 0);
91 | return result;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/RichMediaObject.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.core.JsonParseException;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.JsonDeserializer;
8 | import com.fasterxml.jackson.databind.JsonMappingException;
9 | import com.fasterxml.jackson.databind.ObjectMapper;
10 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
11 | import com.google.common.base.MoreObjects;
12 | import com.google.common.base.Strings;
13 | import com.google.common.collect.ForwardingMap;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import javax.annotation.Nullable;
18 | import javax.annotation.concurrent.Immutable;
19 | import java.io.IOException;
20 | import java.util.Collections;
21 | import java.util.Map;
22 |
23 | /**
24 | * Simple Map(String, Object) wrapper class.
25 | */
26 | @Immutable
27 | @JsonDeserialize(using = RichMediaObject.RichMediaDeserializer.class)
28 | public class RichMediaObject extends ForwardingMap {
29 | private final Map map;
30 |
31 | public RichMediaObject(final @Nullable Map delegate) {
32 | this.map = Collections.unmodifiableMap(MoreObjects.firstNonNull(delegate, Collections.emptyMap()));
33 | }
34 |
35 | public RichMediaObject() {
36 | this(null);
37 | }
38 |
39 | @Override
40 | protected Map delegate() {
41 | return map;
42 | }
43 |
44 | static class RichMediaDeserializer extends JsonDeserializer {
45 | private static final Logger logger = LoggerFactory.getLogger(RichMediaDeserializer.class);
46 | private static final ObjectMapper objectMapper = new ObjectMapper();
47 | private static final String EMPTY_JSON_OBJECT = "{}";
48 |
49 | @Override
50 | public RichMediaObject deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
51 | Map richMediaMap = null;
52 | try {
53 | richMediaMap = objectMapper.readValue(MoreObjects.firstNonNull(
54 | Strings.emptyToNull(p.getValueAsString().trim()), EMPTY_JSON_OBJECT), Map.class);
55 | } catch (JsonMappingException | JsonParseException exception) {
56 | logger.warn("Could not deserialize message keyboard '{}'", p.getValueAsString().trim());
57 | }
58 | return new RichMediaObject(richMediaMap);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/StickerMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | import javax.annotation.Nullable;
8 | import javax.annotation.concurrent.Immutable;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | @Immutable
13 | public class StickerMessage extends Message {
14 |
15 | private final long stickerId;
16 |
17 | @JsonCreator
18 | public StickerMessage(final @JsonProperty("sticker_id") long stickerId,
19 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
20 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
21 | super("sticker", keyboard, trackingData);
22 | this.stickerId = stickerId;
23 | }
24 |
25 | @JsonIgnore
26 | public StickerMessage(final long stickerId) {
27 | this(stickerId, null, null);
28 | }
29 |
30 | @Override
31 | protected Map getPartialMapRepresentation() {
32 | return new HashMap() {{
33 | put("sticker_id", getStickerId());
34 | }};
35 | }
36 |
37 | public long getStickerId() {
38 | return stickerId;
39 | }
40 |
41 | @Override
42 | public boolean equals(final Object o) {
43 | if (this == o) return true;
44 | if (o == null || getClass() != o.getClass()) return false;
45 | if (!super.equals(o)) return false;
46 |
47 | final StickerMessage that = (StickerMessage) o;
48 |
49 | return stickerId == that.stickerId;
50 | }
51 |
52 | @Override
53 | public int hashCode() {
54 | int result = super.hashCode();
55 | result = 31 * result + (int) (stickerId ^ (stickerId >>> 32));
56 | return result;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/TextMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 |
7 | import javax.annotation.Nonnull;
8 | import javax.annotation.Nullable;
9 | import javax.annotation.concurrent.Immutable;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import static com.viber.bot.Preconditions.checkNotEmpty;
14 |
15 | @Immutable
16 | public class TextMessage extends Message {
17 |
18 | private final String text;
19 |
20 | @JsonCreator
21 | public TextMessage(final @JsonProperty("text") @Nonnull String text,
22 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
23 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
24 | super("text", keyboard, trackingData);
25 | this.text = checkNotEmpty(text);
26 | }
27 |
28 | @JsonIgnore
29 | public TextMessage(final @Nonnull String text) {
30 | this(text, null, null);
31 | }
32 |
33 | @Override
34 | protected Map getPartialMapRepresentation() {
35 | return new HashMap() {{
36 | put("text", getText());
37 | }};
38 | }
39 |
40 | public String getText() {
41 | return text;
42 | }
43 |
44 | @Override
45 | public boolean equals(final Object o) {
46 | if (this == o) return true;
47 | if (o == null || getClass() != o.getClass()) return false;
48 | if (!super.equals(o)) return false;
49 |
50 | final TextMessage that = (TextMessage) o;
51 | return text != null ? text.equals(that.text) : that.text == null;
52 | }
53 |
54 | @Override
55 | public int hashCode() {
56 | int result = super.hashCode();
57 | result = 31 * result + (text != null ? text.hashCode() : 0);
58 | return result;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/TrackingData.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.core.JsonParseException;
4 | import com.fasterxml.jackson.core.JsonParser;
5 | import com.fasterxml.jackson.core.JsonProcessingException;
6 | import com.fasterxml.jackson.databind.DeserializationContext;
7 | import com.fasterxml.jackson.databind.JsonDeserializer;
8 | import com.fasterxml.jackson.databind.JsonMappingException;
9 | import com.fasterxml.jackson.databind.ObjectMapper;
10 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
11 | import com.google.common.base.MoreObjects;
12 | import com.google.common.base.Strings;
13 | import com.google.common.collect.ForwardingMap;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import javax.annotation.Nullable;
18 | import javax.annotation.concurrent.Immutable;
19 | import java.io.IOException;
20 | import java.util.Collections;
21 | import java.util.Map;
22 |
23 | /**
24 | * Simple Map(String, Object) wrapper class.
25 | */
26 | @Immutable
27 | @JsonDeserialize(using = TrackingData.TrackingDataDeserializer.class)
28 | public class TrackingData extends ForwardingMap {
29 | private final Map map;
30 |
31 | public TrackingData(final @Nullable Map delegate) {
32 | this.map = Collections.unmodifiableMap(MoreObjects.firstNonNull(delegate, Collections.emptyMap()));
33 | }
34 |
35 | public TrackingData() {
36 | this(null);
37 | }
38 |
39 | @Override
40 | protected Map delegate() {
41 | return map;
42 | }
43 |
44 | static class TrackingDataDeserializer extends JsonDeserializer {
45 | private static final Logger logger = LoggerFactory.getLogger(TrackingDataDeserializer.class);
46 | private static final ObjectMapper objectMapper = new ObjectMapper();
47 | private static final String EMPTY_JSON_OBJECT = "{}";
48 |
49 | @Override
50 | public TrackingData deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException, JsonProcessingException {
51 | Map trackingData = null;
52 | try {
53 | trackingData = objectMapper.readValue(MoreObjects.firstNonNull(
54 | Strings.emptyToNull(p.getValueAsString().trim()), EMPTY_JSON_OBJECT), Map.class);
55 | } catch (JsonMappingException | JsonParseException exception) {
56 | logger.warn("Could not deserialize tracking data '{}'", p.getValueAsString().trim());
57 | }
58 | return new TrackingData(trackingData);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/UrlMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.google.common.net.UrlEscapers;
7 |
8 | import javax.annotation.Nonnull;
9 | import javax.annotation.Nullable;
10 | import javax.annotation.concurrent.Immutable;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | import static com.viber.bot.Preconditions.checkNotEmpty;
15 |
16 | @Immutable
17 | public class UrlMessage extends Message {
18 |
19 | private final String url;
20 |
21 | @JsonCreator
22 | public UrlMessage(final @JsonProperty("media") @Nonnull String url,
23 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
24 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
25 | super("url", keyboard, trackingData);
26 | this.url = UrlEscapers.urlPathSegmentEscaper().escape(checkNotEmpty(url));
27 | }
28 |
29 | @JsonIgnore
30 | public UrlMessage(final @Nonnull String url) {
31 | this(url, null, null);
32 | }
33 |
34 | @Override
35 | protected Map getPartialMapRepresentation() {
36 | return new HashMap() {{
37 | put("media", getUrl());
38 | }};
39 | }
40 |
41 | public String getUrl() {
42 | return url;
43 | }
44 |
45 | @Override
46 | public boolean equals(final Object o) {
47 | if (this == o) return true;
48 | if (o == null || getClass() != o.getClass()) return false;
49 | if (!super.equals(o)) return false;
50 |
51 | final UrlMessage that = (UrlMessage) o;
52 |
53 | return url != null ? url.equals(that.url) : that.url == null;
54 |
55 | }
56 |
57 | @Override
58 | public int hashCode() {
59 | int result = super.hashCode();
60 | result = 31 * result + (url != null ? url.hashCode() : 0);
61 | return result;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/message/VideoMessage.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.message;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnore;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.google.common.base.Strings;
7 |
8 | import javax.annotation.Nonnull;
9 | import javax.annotation.Nullable;
10 | import javax.annotation.concurrent.Immutable;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 | import java.util.Optional;
14 |
15 | import static com.viber.bot.Preconditions.checkNotEmpty;
16 |
17 | @Immutable
18 | public class VideoMessage extends Message {
19 |
20 | private final String url;
21 | private final int size;
22 |
23 | @Nullable
24 | private final String text;
25 |
26 | @Nullable
27 | private final String thumbnail;
28 |
29 | @Nullable
30 | private final Integer duration;
31 |
32 | @JsonCreator
33 | public VideoMessage(final @JsonProperty("media") @Nonnull String url,
34 | final @JsonProperty("size") int size,
35 | final @JsonProperty("text") @Nullable String text,
36 | final @JsonProperty("thumbnail") @Nullable String thumbnail,
37 | final @JsonProperty("duration") @Nullable Integer duration,
38 | final @JsonProperty("keyboard") @Nullable MessageKeyboard keyboard,
39 | final @JsonProperty("tracking_data") @Nullable TrackingData trackingData) {
40 | super("video", keyboard, trackingData);
41 | this.url = checkNotEmpty(url);
42 | this.size = size;
43 | this.text = text;
44 | this.thumbnail = Strings.emptyToNull(thumbnail);
45 | this.duration = duration;
46 | }
47 |
48 | @JsonIgnore
49 | public VideoMessage(final @Nonnull String url, final int size, final @Nullable String text,
50 | final @Nullable String thumbnail, final @Nullable Integer duration) {
51 | this(url, size, text, thumbnail, duration, null, null);
52 | }
53 |
54 | @Override
55 | protected Map getPartialMapRepresentation() {
56 | return new HashMap() {{
57 | put("media", getUrl());
58 | put("text", getText());
59 | put("thumbnail", getThumbnail());
60 | put("size", getSize());
61 | put("duration", getDuration());
62 | }};
63 | }
64 |
65 | public String getUrl() {
66 | return url;
67 | }
68 |
69 | public int getSize() {
70 | return size;
71 | }
72 |
73 | @Nullable
74 | public String getText() {
75 | return text;
76 | }
77 |
78 | @Nullable
79 | public String getThumbnail() {
80 | return thumbnail;
81 | }
82 |
83 | public Optional getDuration() {
84 | return Optional.ofNullable(duration);
85 | }
86 |
87 | @Override
88 | public boolean equals(Object o) {
89 | if (this == o) return true;
90 | if (o == null || getClass() != o.getClass()) return false;
91 | if (!super.equals(o)) return false;
92 |
93 | VideoMessage that = (VideoMessage) o;
94 |
95 | if (size != that.size) return false;
96 | if (url != null ? !url.equals(that.url) : that.url != null) return false;
97 | if (text != null ? !text.equals(that.text) : that.text != null) return false;
98 | if (thumbnail != null ? !thumbnail.equals(that.thumbnail) : that.thumbnail != null) return false;
99 | return duration != null ? duration.equals(that.duration) : that.duration == null;
100 | }
101 |
102 | @Override
103 | public int hashCode() {
104 | int result = super.hashCode();
105 | result = 31 * result + (url != null ? url.hashCode() : 0);
106 | result = 31 * result + size;
107 | result = 31 * result + (text != null ? text.hashCode() : 0);
108 | result = 31 * result + (thumbnail != null ? thumbnail.hashCode() : 0);
109 | result = 31 * result + (duration != null ? duration.hashCode() : 0);
110 | return result;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/middleware/DefaultMiddleware.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.middleware;
2 |
3 | import com.google.common.util.concurrent.ListenableFuture;
4 | import com.viber.bot.Request;
5 |
6 | import javax.annotation.Nonnull;
7 | import java.io.InputStream;
8 |
9 | public class DefaultMiddleware implements Middleware {
10 |
11 | private final Middleware middleware;
12 |
13 | public DefaultMiddleware(final @Nonnull RequestReceiver requestReceiver) {
14 | middleware = new PubSubMiddleware(requestReceiver);
15 | }
16 |
17 | @Override
18 | public ListenableFuture incoming(final Request request) {
19 | return middleware.incoming(request);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/middleware/Middleware.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.middleware;
2 |
3 | import com.google.common.util.concurrent.ListenableFuture;
4 | import com.viber.bot.Request;
5 |
6 | import javax.annotation.concurrent.ThreadSafe;
7 | import java.io.InputStream;
8 |
9 | @ThreadSafe
10 | public interface Middleware {
11 | ListenableFuture incoming(final Request request);
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/middleware/RequestReceiver.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.middleware;
2 |
3 | import com.viber.bot.Request;
4 |
5 | public interface RequestReceiver {
6 | void acceptRequest(final Request request);
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/profile/BotProfile.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.profile;
2 |
3 | import javax.annotation.Nonnull;
4 | import javax.annotation.Nullable;
5 | import javax.annotation.concurrent.Immutable;
6 |
7 | import static com.viber.bot.Preconditions.checkNotEmpty;
8 |
9 | @Immutable
10 | public class BotProfile {
11 |
12 | private final String name;
13 | private final String avatar;
14 |
15 | public BotProfile(final @Nonnull String name, final @Nullable String avatar) {
16 | this.name = checkNotEmpty(name);
17 | this.avatar = avatar;
18 | }
19 |
20 | public BotProfile(final @Nonnull String name) {
21 | this(name, null);
22 | }
23 |
24 | public String getName() {
25 | return name;
26 | }
27 |
28 | @Nullable
29 | public String getAvatar() {
30 | return avatar;
31 | }
32 |
33 | @Override
34 | public boolean equals(final Object o) {
35 | if (this == o) return true;
36 | if (o == null || getClass() != o.getClass()) return false;
37 |
38 | final BotProfile that = (BotProfile) o;
39 |
40 | if (name != null ? !name.equals(that.name) : that.name != null) return false;
41 | return avatar != null ? avatar.equals(that.avatar) : that.avatar == null;
42 | }
43 |
44 | @Override
45 | public int hashCode() {
46 | int result = name != null ? name.hashCode() : 0;
47 | result = 31 * result + (avatar != null ? avatar.hashCode() : 0);
48 | return result;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/viber/bot/profile/UserProfile.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.profile;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5 | import com.fasterxml.jackson.annotation.JsonProperty;
6 | import com.google.common.base.Strings;
7 |
8 | import javax.annotation.Nonnull;
9 | import javax.annotation.Nullable;
10 | import javax.annotation.concurrent.Immutable;
11 |
12 | import static com.google.common.base.Preconditions.checkNotNull;
13 | import static com.viber.bot.Preconditions.checkNotEmpty;
14 |
15 | @Immutable
16 | @JsonIgnoreProperties(ignoreUnknown = true)
17 | public class UserProfile {
18 |
19 | private final String id;
20 | private final String country;
21 | private final String language;
22 | private final Integer apiVersion;
23 |
24 | @Nullable
25 | private final String name;
26 |
27 | @Nullable
28 | private final String avatar;
29 |
30 | @JsonCreator
31 | UserProfile(final @JsonProperty("id") @Nonnull String id,
32 | final @JsonProperty("country") @Nonnull String country,
33 | final @JsonProperty("language") @Nonnull String language,
34 | final @JsonProperty("api_version") @Nonnull Integer apiVersion,
35 | final @JsonProperty("name") @Nullable String name,
36 | final @JsonProperty("avatar") @Nullable String avatar) {
37 |
38 | this.id = checkNotEmpty(id);
39 | this.name = Strings.emptyToNull(name);
40 | this.avatar = Strings.emptyToNull(avatar);
41 | this.country = checkNotEmpty(country);
42 | this.language = checkNotEmpty(language);
43 | this.apiVersion = checkNotNull(apiVersion);
44 | }
45 |
46 | public String getId() {
47 | return id;
48 | }
49 |
50 | public String getCountry() {
51 | return country;
52 | }
53 |
54 | public String getLanguage() {
55 | return language;
56 | }
57 |
58 | public Integer getApiVersion() {
59 | return apiVersion;
60 | }
61 |
62 | @Nullable
63 | public String getName() {
64 | return name;
65 | }
66 |
67 | @Nullable
68 | public String getAvatar() {
69 | return avatar;
70 | }
71 |
72 | @Override
73 | public boolean equals(Object o) {
74 | if (this == o) return true;
75 | if (o == null || getClass() != o.getClass()) return false;
76 |
77 | UserProfile that = (UserProfile) o;
78 |
79 | if (id != null ? !id.equals(that.id) : that.id != null) return false;
80 | if (name != null ? !name.equals(that.name) : that.name != null) return false;
81 | if (avatar != null ? !avatar.equals(that.avatar) : that.avatar != null) return false;
82 | if (country != null ? !country.equals(that.country) : that.country != null) return false;
83 | if (apiVersion != null ? !apiVersion.equals(that.apiVersion) : that.apiVersion != null) return false;
84 | return language != null ? language.equals(that.language) : that.language == null;
85 | }
86 |
87 | @Override
88 | public int hashCode() {
89 | int result = id != null ? id.hashCode() : 0;
90 | result = 31 * result + (name != null ? name.hashCode() : 0);
91 | result = 31 * result + (avatar != null ? avatar.hashCode() : 0);
92 | result = 31 * result + (country != null ? country.hashCode() : 0);
93 | result = 31 * result + (language != null ? language.hashCode() : 0);
94 | result = 31 * result + (apiVersion != null ? apiVersion.hashCode() : 0);
95 | return result;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/test/java/com/viber/bot/RequestTest.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import com.viber.bot.event.incoming.IncomingDeliveredEvent;
4 | import org.junit.Test;
5 |
6 | import java.io.ByteArrayInputStream;
7 | import java.nio.charset.Charset;
8 |
9 | import static org.assertj.core.api.Assertions.assertThat;
10 |
11 | public class RequestTest {
12 |
13 | private static final String VALID_JSON = "{\"event\":\"delivered\",\"timestamp\":1457764197627,\"message_token\":4912661846655238145,\"user_id\":\"01234567890A=\"}";
14 |
15 | @Test
16 | public void testValidJson() {
17 | final Request request = Request.fromJsonString(VALID_JSON);
18 | assertThat(request.getEvent()).isInstanceOf(IncomingDeliveredEvent.class);
19 | }
20 |
21 | @Test
22 | public void testValidInputStream() {
23 | final Request request = Request.fromInputStream(new ByteArrayInputStream(VALID_JSON.getBytes(Charset.defaultCharset())));
24 | assertThat(request.getEvent()).isInstanceOf(IncomingDeliveredEvent.class);
25 | }
26 |
27 | @Test(expected = RuntimeException.class)
28 | public void testJsonWithMissingFields() {
29 | Request.fromJsonString("{\"event\":\"delivered\"}");
30 | }
31 |
32 | @Test(expected = RuntimeException.class)
33 | public void testInvalidJson() {
34 | Request.fromJsonString("{");
35 | }
36 |
37 | @Test(expected = RuntimeException.class)
38 | public void testJsonWithInvalidTypeInField() {
39 | Request.fromJsonString("{\"event\":\"delivered\",\"timestamp\":\"hi\"}");
40 | }
41 | }
--------------------------------------------------------------------------------
/src/test/java/com/viber/bot/ViberSignatureValidatorTest.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.assertj.core.api.Assertions.assertThat;
6 |
7 | public class ViberSignatureValidatorTest {
8 |
9 | private static final String AUTH_TOKEN = "44dafb7e0f40021e-61a47a1e6778d187-f2c5a676a07050b3";
10 | private static final String VALID_SIGNATURE = "d21b343448c8aee33b8e93768ef6ceb64a6ba6163099973a2b8bd028fea510ef";
11 | private static final String SERVER_MESSAGE = "{\"event\":\"webhook\",\"timestamp\":4977069964384421269,\"message_token\":1478683725125}";
12 |
13 | @Test
14 | public void testSignatureValidationSanity() {
15 | final ViberSignatureValidator validator = new ViberSignatureValidator(AUTH_TOKEN);
16 | assertThat(validator.isSignatureValid(VALID_SIGNATURE, SERVER_MESSAGE)).isTrue();
17 | }
18 |
19 | @Test
20 | public void testSignatureIsInvalid() {
21 | final ViberSignatureValidator validator = new ViberSignatureValidator("abc");
22 | assertThat(validator.isSignatureValid(VALID_SIGNATURE, SERVER_MESSAGE)).isFalse();
23 | }
24 |
25 | @Test
26 | public void testInvalidDataInSignature() {
27 | final ViberSignatureValidator validator = new ViberSignatureValidator(AUTH_TOKEN);
28 | assertThat(validator.isSignatureValid(VALID_SIGNATURE, "{}")).isFalse();
29 | }
30 |
31 | @Test(expected = NullPointerException.class)
32 | public void testEmptySecret() {
33 | new ViberSignatureValidator(null);
34 | }
35 |
36 | }
--------------------------------------------------------------------------------
/src/test/java/com/viber/bot/api/RegexMatcherRouterTest.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 | import java.util.concurrent.atomic.AtomicInteger;
7 | import java.util.regex.Pattern;
8 |
9 | import static org.assertj.core.api.Assertions.assertThat;
10 |
11 | public class RegexMatcherRouterTest {
12 |
13 | private final RegexMatcherRouter regexMatcherRouter = new RegexMatcherRouter();
14 |
15 | @Test
16 | public void testRegexMatcherRouterSanity() {
17 | final AtomicBoolean isMessageReceived = new AtomicBoolean(false);
18 |
19 | regexMatcherRouter.newMatcher(Pattern.compile("hi", Pattern.CASE_INSENSITIVE),
20 | (event, message, response) -> isMessageReceived.compareAndSet(false, true));
21 | regexMatcherRouter.tryGetCallback("Hi").forEach(callback -> callback.emit(null, null, null));
22 |
23 | assertThat(isMessageReceived.get()).isEqualTo(true);
24 | }
25 |
26 | @Test
27 | public void testRegexMatcherRouterMultipleMatches() {
28 | final AtomicInteger numberOfMatches = new AtomicInteger(0);
29 |
30 | regexMatcherRouter.newMatcher(Pattern.compile("hi", Pattern.CASE_INSENSITIVE),
31 | (event, message, response) -> numberOfMatches.incrementAndGet());
32 |
33 | regexMatcherRouter.newMatcher(Pattern.compile("(hi|hello)", Pattern.CASE_INSENSITIVE),
34 | (event, message, response) -> numberOfMatches.incrementAndGet());
35 |
36 | regexMatcherRouter.tryGetCallback("Hi").forEach(callback -> callback.emit(null, null, null));
37 | assertThat(numberOfMatches.get()).isEqualTo(2);
38 | }
39 |
40 | @Test
41 | public void testRegexMatcherRouterNoMatches() {
42 | final AtomicBoolean isMessageReceived = new AtomicBoolean(false);
43 |
44 | regexMatcherRouter.newMatcher(Pattern.compile("hi", Pattern.CASE_INSENSITIVE),
45 | (event, message, response) -> isMessageReceived.compareAndSet(false, true));
46 | regexMatcherRouter.tryGetCallback("Hello").forEach(callback -> callback.emit(null, null, null));
47 |
48 | assertThat(isMessageReceived.get()).isEqualTo(false);
49 | }
50 | }
--------------------------------------------------------------------------------
/src/test/java/com/viber/bot/api/ViberClientTest.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.api;
2 |
3 | import okhttp3.MediaType;
4 | import okhttp3.Request;
5 | import okhttp3.RequestBody;
6 | import org.junit.Test;
7 |
8 | import static org.assertj.core.api.Assertions.assertThat;
9 |
10 | public class ViberClientTest {
11 |
12 | private static final ViberClient client = new ViberClient("http://url.com", "TOKEN");
13 | private static final RequestBody EMPTY_REQUEST_BODY = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), "");
14 |
15 | @Test
16 | public void testCreateRequestAuthTokenExistsSanity() {
17 | Request request = client.createRequest(ViberClient.Endpoint.SEND_MESSAGE, EMPTY_REQUEST_BODY);
18 | assertThat(request.headers().get(ViberClient.VIBER_AUTH_TOKEN_HEADER)).isNotEmpty();
19 | assertThat(request.headers().get(ViberClient.VIBER_AUTH_TOKEN_HEADER)).isEqualTo("TOKEN");
20 | }
21 |
22 | @Test
23 | public void testCreateRequestUserAgentExistsSanity() {
24 | Request request = client.createRequest(ViberClient.Endpoint.SEND_MESSAGE, EMPTY_REQUEST_BODY);
25 | assertThat(request.headers().get(ViberClient.USER_AGENT_HEADER_FIELD)).isNotEmpty();
26 | assertThat(request.headers().get(ViberClient.USER_AGENT_HEADER_FIELD))
27 | .isEqualTo(String.format("%s%s", ViberClient.USER_AGENT_HEADER_VALUE, ViberClient.VIBER_LIBRARY_VERSION));
28 | }
29 | }
--------------------------------------------------------------------------------
/src/test/java/com/viber/bot/event/EventEmitterTest.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.event;
2 |
3 | import com.google.common.collect.Lists;
4 | import com.google.common.util.concurrent.Futures;
5 | import org.junit.Test;
6 |
7 | import java.util.List;
8 | import java.util.concurrent.ExecutionException;
9 | import java.util.concurrent.Future;
10 | import java.util.concurrent.atomic.AtomicBoolean;
11 | import java.util.concurrent.atomic.AtomicInteger;
12 | import java.util.stream.IntStream;
13 |
14 | import static com.jayway.awaitility.Awaitility.await;
15 | import static org.assertj.core.api.Assertions.assertThat;
16 | import static org.hamcrest.core.IsEqual.equalTo;
17 |
18 | public class EventEmitterTest {
19 |
20 | private final EventEmitter eventEmitter = new EventEmitter();
21 |
22 | @Test
23 | public void testEventEmitterSanity() {
24 | final AtomicBoolean isEventReceived = new AtomicBoolean(false);
25 | eventEmitter.on(Event.ERROR, args -> {
26 | isEventReceived.compareAndSet(false, true);
27 | return null;
28 | });
29 |
30 | eventEmitter.emit(Event.ERROR);
31 | await().untilAtomic(isEventReceived, equalTo(true));
32 | }
33 |
34 | @Test
35 | public void testEventEmitterMultipleEmitsInOrder() throws ExecutionException, InterruptedException {
36 | final int nTests = 10;
37 | final AtomicInteger numberOfEvents = new AtomicInteger(0);
38 |
39 | eventEmitter.on(Event.WEBHOOK, args -> {
40 | numberOfEvents.incrementAndGet();
41 | return Futures.immediateFuture(args[0]);
42 | });
43 |
44 | final List> futures = Lists.newArrayList();
45 | IntStream.range(0, nTests).forEach(i -> futures.addAll(eventEmitter.emit(Event.WEBHOOK, i)));
46 | await().untilAtomic(numberOfEvents, equalTo(nTests));
47 |
48 | for (int i = 0; i < nTests; i++) {
49 | assertThat(futures.get(i).get()).isEqualTo(i);
50 | }
51 | }
52 |
53 | @Test
54 | public void testEventEmitterMultipleListenersInOrder() throws ExecutionException, InterruptedException {
55 | final int nTests = 10;
56 | final AtomicInteger numberOfEvents = new AtomicInteger(0);
57 |
58 | eventEmitter.on(Event.WEBHOOK, args -> {
59 | numberOfEvents.incrementAndGet();
60 | return Futures.immediateFuture("a_" + args[0]);
61 | });
62 |
63 | eventEmitter.on(Event.WEBHOOK, args -> {
64 | numberOfEvents.incrementAndGet();
65 | return Futures.immediateFuture("b_" + args[0]);
66 | });
67 |
68 | final List> futures = Lists.newArrayList();
69 | IntStream.range(0, nTests).forEach(i -> futures.addAll(eventEmitter.emit(Event.WEBHOOK, i)));
70 | await().untilAtomic(numberOfEvents, equalTo(nTests * 2));
71 |
72 | for (int i = 0; i < nTests; i += 2) {
73 | final int expected = i / 2;
74 | assertThat(futures.get(i).get()).isEqualTo("a_" + expected);
75 | assertThat(futures.get(i + 1).get()).isEqualTo("b_" + expected);
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/src/test/java/com/viber/bot/middleware/PubSubMiddlewareTest.java:
--------------------------------------------------------------------------------
1 | package com.viber.bot.middleware;
2 |
3 | import com.viber.bot.Request;
4 | import org.assertj.core.util.Closeables;
5 | import org.junit.Before;
6 | import org.junit.Test;
7 | import org.mockito.Mock;
8 | import org.mockito.MockitoAnnotations;
9 |
10 | import java.io.IOException;
11 | import java.util.concurrent.atomic.AtomicBoolean;
12 | import java.util.concurrent.atomic.AtomicInteger;
13 | import java.util.stream.IntStream;
14 |
15 | import static com.jayway.awaitility.Awaitility.await;
16 | import static org.hamcrest.core.IsEqual.equalTo;
17 | import static org.mockito.Mockito.doAnswer;
18 | import static org.mockito.Mockito.when;
19 |
20 | public class PubSubMiddlewareTest {
21 |
22 | @Mock
23 | private Request request;
24 |
25 | @Test
26 | public void testMiddlewareSanity() {
27 | final AtomicBoolean gotRequest = new AtomicBoolean(false);
28 | final Middleware middleware = new PubSubMiddleware(request -> {
29 | gotRequest.compareAndSet(false, true);
30 | Closeables.closeQuietly(request);
31 | });
32 |
33 | middleware.incoming(request);
34 | await().untilAtomic(gotRequest, equalTo(true));
35 | }
36 |
37 | @Test
38 | public void testMiddlewareMultipleRequestsTestSequence() {
39 | final int nRequests = 10;
40 | final AtomicInteger numberOfRequests = new AtomicInteger(0);
41 | final Middleware middleware = new PubSubMiddleware(request -> {
42 | numberOfRequests.incrementAndGet();
43 | Closeables.closeQuietly(request);
44 | });
45 |
46 | IntStream.range(0, nRequests).forEach(i -> middleware.incoming(request));
47 | await().untilAtomic(numberOfRequests, equalTo(nRequests));
48 | }
49 |
50 | @Before
51 | public void setup() throws IOException {
52 | MockitoAnnotations.initMocks(this);
53 |
54 | final AtomicBoolean isRequestClosed = new AtomicBoolean(false);
55 | doAnswer(invocation -> {
56 | synchronized (request) {
57 | request.notify();
58 | isRequestClosed.set(true);
59 | }
60 | return null;
61 | }).when(request).close();
62 | when(request.isClosed()).then(invocation -> isRequestClosed.get());
63 | }
64 |
65 | @Test(expected = NullPointerException.class)
66 | public void testMiddlewareNullRequest() {
67 | final Middleware middleware = new PubSubMiddleware(request -> {
68 | });
69 | middleware.incoming(null);
70 | }
71 | }
--------------------------------------------------------------------------------