2ead82b19a90d6bf3a84b25c9c44d9394fd0d171
1 package be
.nikiroo
.jvcard
.remote
;
4 import java
.io
.IOException
;
5 import java
.net
.ServerSocket
;
6 import java
.net
.Socket
;
7 import java
.net
.UnknownHostException
;
9 import java
.util
.LinkedList
;
10 import java
.util
.List
;
11 import java
.util
.ResourceBundle
;
13 import be
.nikiroo
.jvcard
.Card
;
14 import be
.nikiroo
.jvcard
.parsers
.Format
;
15 import be
.nikiroo
.jvcard
.parsers
.Parser
;
16 import be
.nikiroo
.jvcard
.remote
.Command
.Verb
;
17 import be
.nikiroo
.jvcard
.resources
.Bundles
;
18 import be
.nikiroo
.jvcard
.tui
.StringUtils
;
21 * This class implements a small server that can listen for requests to
22 * synchronise, get and put {@link Card}s.
25 * It is <b>NOT</b> secured in any way (it even is nice enough to give you a
26 * help message when you connect in raw mode via nc on how to use it), so do
27 * <b>NOT</b> enable such a server to be accessible from internet. This is not
28 * safe. Use a ssh/openssl tunnel or similar.
34 public class Server
implements Runnable
{
35 private ServerSocket ss
;
40 private Object clientsLock
= new Object();
41 private List
<SimpleSocket
> clients
= new LinkedList
<SimpleSocket
>();
43 private Object cardsLock
= new Object();
45 public static void main(String
[] args
) throws IOException
{
46 Server server
= new Server(4444);
51 * Create a new jVCard sercer on the given port.
59 public Server(int port
) throws IOException
{
61 ResourceBundle bundle
= Bundles
.getBundle("remote");
63 String dir
= bundle
.getString("SERVER_DATA_PATH");
64 dataDir
= new File(dir
);
67 if (!dataDir
.exists()) {
68 throw new IOException("Cannot open or create data store at: "
71 } catch (Exception e
) {
73 throw new IOException("Cannot open or create data store at: "
77 ss
= new ServerSocket(port
);
81 * Stop the server. It may take some time before returning, but will only
82 * return when the server is actually stopped.
87 SimpleSocket c
= new SimpleSocket(new Socket((String
) null, port
),
88 "special STOP client");
90 c
.sendCommand(Verb
.STOP
);
92 } catch (UnknownHostException e
) {
94 } catch (IOException e
) {
98 if (clients
.size() > 0) {
101 } catch (InterruptedException e
) {
104 if (clients
.size() > 0) {
105 synchronized (clientsLock
) {
106 for (SimpleSocket s
: clients
) {
108 .println("Forcefully closing client connection");
122 final Socket s
= ss
.accept();
123 // TODO: thread pool?
124 new Thread(new Runnable() {
127 accept(new SimpleSocket(s
, "[request]"));
130 } catch (IOException ioe
) {
131 ioe
.printStackTrace();
137 * Add a client to the current count.
139 * @return the client index number
141 private void addClient(SimpleSocket s
) {
142 synchronized (clientsLock
) {
148 * Remove a client from the current count.
151 * the client index number
153 private void removeClient(SimpleSocket s
) {
154 synchronized (clientsLock
) {
160 * Accept a client and process it.
163 * the client to process
165 private void accept(SimpleSocket s
) {
171 boolean clientStop
= false;
172 while (!clientStop
) {
173 Command cmd
= s
.receiveCommand();
174 Command
.Verb verb
= cmd
.getVerb();
179 System
.out
.println(s
+ " -> " + verb
);
186 s
.sendCommand(Verb
.VERSION
);
189 s
.sendLine(StringUtils
.fromTime(new Date().getTime()));
192 synchronized (cardsLock
) {
193 s
.sendBlock(doGetCard(cmd
.getParam()));
197 synchronized (cardsLock
) {
198 doPostCard(cmd
.getParam(), s
.receiveBlock());
203 for (File file
: dataDir
.listFiles()) {
204 if (cmd
.getParam() == null
205 || cmd
.getParam().length() == 0
206 || file
.getName().contains(cmd
.getParam())) {
207 s
.send(StringUtils
.fromTime(file
.lastModified())
208 + " " + file
.getName());
215 s
.send("The following commands are available:");
216 s
.send("- TIME: get the server time");
217 s
.send("- HELP: this help screen");
218 s
.send("- LIST: list the available cards on this server");
219 s
.send("- VERSION/GET/PUT/POST/DELETE/STOP: TODO");
224 .println("Unsupported command received from a client connection, closing it: "
230 } catch (IOException e
) {
240 * Return the serialised {@link Card} (with timestamp).
243 * the resource name to load
245 * @return the serialised data
247 * @throws IOException
250 private List
<String
> doGetCard(String name
) throws IOException
{
251 List
<String
> lines
= new LinkedList
<String
>();
253 if (name
!= null && name
.length() > 0) {
254 File vcf
= new File(dataDir
.getAbsolutePath() + File
.separator
258 Card card
= new Card(vcf
, Format
.VCard21
);
261 lines
.add(StringUtils
.fromTime(card
.getLastModified()));
263 // TODO: !!! fix this !!!
264 for (String line
: card
.toString(Format
.VCard21
).split("\r\n")) {
274 * Save the data to the new given resource.
277 * the resource name to save
281 * @throws IOException
284 private void doPostCard(String name
, List
<String
> data
) throws IOException
{
285 if (name
!= null && name
.length() > 0) {
286 File vcf
= new File(dataDir
.getAbsolutePath() + File
.separator
289 Card card
= new Card(Parser
.parse(data
, Format
.VCard21
));
290 card
.saveAs(vcf
, Format
.VCard21
);