Skip to content

Commit 27dba84

Browse files
committed
Added support for connecting and disconnecting camera. Updated jlibgphoto2 version to 1.9. Changed version to 2.8
1 parent a90bd0f commit 27dba84

13 files changed

Lines changed: 192 additions & 35 deletions

File tree

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>x.mvmn.gp2srv</groupId>
66
<artifactId>GPhoto2Server</artifactId>
7-
<version>2.7</version>
7+
<version>2.8</version>
88
<packaging>jar</packaging>
99

1010
<properties>
@@ -16,7 +16,7 @@
1616
<dependency>
1717
<groupId>x.mvmn.jlibgphoto2</groupId>
1818
<artifactId>jlibgphoto2</artifactId>
19-
<version>1.7</version>
19+
<version>1.9</version>
2020
</dependency>
2121
<dependency>
2222
<groupId>com.google.code.gson</groupId>

src/main/java/x/mvmn/gp2srv/GPhoto2Server.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.eclipse.jetty.servlet.ServletContextHandler;
1919
import org.eclipse.jetty.servlet.ServletHolder;
2020

21+
import x.mvmn.gp2srv.camera.CameraProvider;
2122
import x.mvmn.gp2srv.camera.CameraService;
2223
import x.mvmn.gp2srv.camera.service.impl.CameraServiceImpl;
2324
import x.mvmn.gp2srv.mock.service.impl.MockCameraServiceImpl;
@@ -27,6 +28,7 @@
2728
import x.mvmn.gp2srv.web.service.velocity.VelocityContextService;
2829
import x.mvmn.gp2srv.web.servlets.AbstractErrorHandlingServlet;
2930
import x.mvmn.gp2srv.web.servlets.BasicAuthFilter;
31+
import x.mvmn.gp2srv.web.servlets.CameraChoiceFilter;
3032
import x.mvmn.gp2srv.web.servlets.CameraControlServlet;
3133
import x.mvmn.gp2srv.web.servlets.DevModeServlet;
3234
import x.mvmn.gp2srv.web.servlets.LiveViewServlet;
@@ -42,7 +44,7 @@
4244
import x.mvmn.log.api.Logger.LogLevel;
4345
import x.mvmn.util.FileBackedProperties;
4446

45-
public class GPhoto2Server implements Provider<TemplateEngine> {
47+
public class GPhoto2Server implements Provider<TemplateEngine>, CameraProvider {
4648

4749
private static final String DEFAULT_CONTEXT_PATH = "/";
4850
private static final int DEFAULT_PORT = 8080;
@@ -51,8 +53,7 @@ public class GPhoto2Server implements Provider<TemplateEngine> {
5153
private final Logger logger;
5254
private volatile TemplateEngine templateEngine;
5355
private final VelocityContextService velocityContextService;
54-
private final GP2Camera camera;
55-
56+
private volatile GP2Camera camera;
5657
private final File userHome;
5758
private final File appHomeFolder;
5859
// private final File imagesFolder;
@@ -94,8 +95,6 @@ public GPhoto2Server(String contextPath, Integer port, final LogLevel logLevel,
9495
String imageDldPath) {
9596
this.logger = makeLogger(logLevel);
9697

97-
this.camera = mockMode ? null : new GP2Camera();
98-
9998
logger.info("Initializing...");
10099

101100
try {
@@ -156,7 +155,10 @@ protected void handleErrorPage(final HttpServletRequest request, final Writer wr
156155
EnumSet.of(DispatcherType.REQUEST));
157156
}
158157

159-
final CameraService cameraService = mockMode ? new MockCameraServiceImpl() : new CameraServiceImpl(camera);
158+
context.addFilter(new FilterHolder(new CameraChoiceFilter(this, velocityContextService, this, logger)), "/*",
159+
EnumSet.of(DispatcherType.REQUEST));
160+
161+
final CameraService cameraService = mockMode ? new MockCameraServiceImpl() : new CameraServiceImpl(this);
160162
AtomicBoolean scriptDumpVars = new AtomicBoolean(true);
161163
scriptManagementService = new ScriptsManagementServiceImpl(scriptsFolder, logger);
162164
scriptExecService = new ScriptExecutionServiceImpl(logger);
@@ -241,4 +243,12 @@ public TemplateEngine provide() {
241243
public GP2Camera getCamera() {
242244
return camera;
243245
}
246+
247+
public void setCamera(GP2Camera camera) {
248+
this.camera = camera;
249+
}
250+
251+
public boolean hasCamera() {
252+
return camera != null;
253+
}
244254
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package x.mvmn.gp2srv.camera;
2+
3+
import x.mvmn.jlibgphoto2.GP2Camera;
4+
5+
public interface CameraProvider {
6+
7+
public GP2Camera getCamera();
8+
9+
public boolean hasCamera();
10+
11+
public void setCamera(GP2Camera camera);
12+
}

src/main/java/x/mvmn/gp2srv/camera/CameraService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,6 @@ public interface CameraService {
4141
public byte[] fileGetThumb(final String filePath, final String fileName);
4242

4343
public String downloadFile(final String cameraFilePath, final String cameraFileName, final File downloadFolder);
44+
45+
public CameraProvider getCameraProvider();
4446
}

src/main/java/x/mvmn/gp2srv/camera/service/impl/CameraServiceImpl.java

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,74 +8,78 @@
88

99
import org.apache.commons.io.FileUtils;
1010

11+
import x.mvmn.gp2srv.camera.CameraProvider;
1112
import x.mvmn.gp2srv.camera.CameraService;
1213
import x.mvmn.jlibgphoto2.CameraConfigEntryBean;
1314
import x.mvmn.jlibgphoto2.CameraFileSystemEntryBean;
14-
import x.mvmn.jlibgphoto2.GP2Camera;
1515
import x.mvmn.jlibgphoto2.GP2Camera.GP2CameraCaptureType;
1616
import x.mvmn.jlibgphoto2.GP2Camera.GP2CameraEventType;
1717
import x.mvmn.jlibgphoto2.GP2CameraFilesHelper;
1818
import x.mvmn.jlibgphoto2.GP2ConfigHelper;
1919

2020
public class CameraServiceImpl implements CameraService, Closeable {
2121

22-
private GP2Camera camera;
22+
private final CameraProvider cameraProvider;
2323

24-
public CameraServiceImpl(final GP2Camera camera) {
25-
this.camera = camera;
24+
public CameraServiceImpl(final CameraProvider camera) {
25+
this.cameraProvider = camera;
2626
}
2727

2828
public void close() {
29-
camera.close();
29+
cameraProvider.getCamera().close();
3030
}
3131

3232
public synchronized byte[] capturePreview() {
33-
return camera.capturePreview();
33+
return cameraProvider.getCamera().capturePreview();
3434
}
3535

3636
public synchronized CameraServiceImpl releaseCamera() {
37-
camera.release();
37+
cameraProvider.getCamera().release();
3838
return this;
3939
}
4040

4141
public synchronized CameraFileSystemEntryBean capture() {
42-
return camera.capture();
42+
return cameraProvider.getCamera().capture();
4343
}
4444

4545
public synchronized CameraFileSystemEntryBean capture(final GP2CameraCaptureType captureType) {
46-
return camera.capture(captureType);
46+
return cameraProvider.getCamera().capture(captureType);
4747
}
4848

4949
public synchronized String getSummary() {
50-
return camera.getSummary();
50+
return cameraProvider.getCamera().getSummary();
5151
}
5252

5353
public GP2CameraEventType waitForSpecificEvent(int timeout, GP2CameraEventType expectedEventType) {
54-
return camera.waitForSpecificEvent(timeout, expectedEventType);
54+
return cameraProvider.getCamera().waitForSpecificEvent(timeout, expectedEventType);
5555
}
5656

5757
public GP2CameraEventType waitForEvent(int timeout) {
58-
return camera.waitForEvent(timeout);
58+
return cameraProvider.getCamera().waitForEvent(timeout);
5959
}
6060

6161
public synchronized List<CameraConfigEntryBean> getConfig() {
62-
return GP2ConfigHelper.getConfig(camera);
62+
return GP2ConfigHelper.getConfig(cameraProvider.getCamera());
6363
}
6464

6565
public synchronized CameraServiceImpl setConfig(CameraConfigEntryBean configEntry) {
66-
GP2ConfigHelper.setConfig(camera, configEntry);
66+
GP2ConfigHelper.setConfig(cameraProvider.getCamera(), configEntry);
6767
return this;
6868
}
6969

7070
public synchronized List<CameraFileSystemEntryBean> filesList(final String path, boolean includeFiles, boolean includeFolders, boolean recursive) {
71-
return GP2CameraFilesHelper.list(camera, path, includeFiles, includeFolders, recursive);
71+
return GP2CameraFilesHelper.list(cameraProvider.getCamera(), path, includeFiles, includeFolders, recursive);
7272
}
7373

7474
public synchronized CameraServiceImpl fileDelete(final String filePath, final String fileName) {
75-
GP2CameraFilesHelper.deleteCameraFile(camera, filePath, fileName);
75+
GP2CameraFilesHelper.deleteCameraFile(cameraProvider.getCamera(), filePath, fileName);
7676
return this;
7777
}
7878

79+
public CameraProvider getCameraProvider() {
80+
return cameraProvider;
81+
}
82+
7983
public String downloadFile(final String cameraFilePath, final String cameraFileName, final File downloadFolder) {
8084
String result = null;
8185
byte[] content = fileGetContents(cameraFilePath, cameraFileName);
@@ -99,11 +103,11 @@ public String downloadFile(final String cameraFilePath, final String cameraFileN
99103
}
100104

101105
public synchronized byte[] fileGetContents(final String filePath, final String fileName) {
102-
return GP2CameraFilesHelper.getCameraFileContents(camera, filePath, fileName);
106+
return GP2CameraFilesHelper.getCameraFileContents(cameraProvider.getCamera(), filePath, fileName);
103107
}
104108

105109
public synchronized byte[] fileGetThumb(final String filePath, final String fileName) {
106-
return GP2CameraFilesHelper.getCameraFileContents(camera, filePath, fileName, true);
110+
return GP2CameraFilesHelper.getCameraFileContents(cameraProvider.getCamera(), filePath, fileName, true);
107111
}
108112

109113
public Map<String, CameraConfigEntryBean> getConfigAsMap() {

src/main/java/x/mvmn/gp2srv/mock/service/impl/MockCameraServiceImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.gson.Gson;
2424
import com.google.gson.reflect.TypeToken;
2525

26+
import x.mvmn.gp2srv.camera.CameraProvider;
2627
import x.mvmn.gp2srv.camera.CameraService;
2728
import x.mvmn.gphoto2.jna.Gphoto2Library;
2829
import x.mvmn.jlibgphoto2.CameraConfigEntryBean;
@@ -229,4 +230,8 @@ public byte[] fileGetThumb(String filePath, String fileName) {
229230
public String downloadFile(String cameraFilePath, String cameraFileName, File downloadFolderPath) {
230231
return "Ok";
231232
}
233+
234+
public CameraProvider getCameraProvider() {
235+
return null;
236+
}
232237
}

src/main/java/x/mvmn/gp2srv/web/servlets/AbstractGP2Servlet.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@
1414
import x.mvmn.log.api.Logger;
1515

1616
/**
17-
* @author Mykola Makhin This type of servlets adds shared global context to template engine + inherits from {@link AbstractErrorHandlingServlet} error handling
18-
* with error pages rendered from properly templates + {@link AbstractErrorHandlingServlet} itself inherits from {@link HttpServletWithTemplates} a
19-
* template engine + methods for outputting render of templates.<br/>
20-
* <br/>
21-
* Thus we get templating in general, default error handing with proper templates and global context in templates.
17+
* This type of servlets adds shared global context to template engine + inherits from {@link AbstractErrorHandlingServlet} error handling with error pages
18+
* rendered from properly templates + {@link AbstractErrorHandlingServlet} itself inherits from {@link HttpServletWithTemplates} a template engine + methods for
19+
* outputting render of templates.<br/>
20+
* <br/>
21+
* Thus we get templating in general, default error handing with proper templates and global context in templates.
22+
*
23+
* @author Mykola Makhin
2224
*/
2325
public class AbstractGP2Servlet extends AbstractErrorHandlingServlet {
2426
private static final long serialVersionUID = 7210482012835862732L;
2527

26-
protected VelocityContextService velocityContextService;
28+
protected final VelocityContextService velocityContextService;
2729

2830
public AbstractGP2Servlet(final VelocityContextService velocityContextService, final Provider<TemplateEngine> templateEngineProvider, final Logger logger) {
2931
super(templateEngineProvider, logger);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package x.mvmn.gp2srv.web.servlets;
2+
3+
import java.io.IOException;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
import javax.servlet.Filter;
8+
import javax.servlet.FilterChain;
9+
import javax.servlet.FilterConfig;
10+
import javax.servlet.ServletException;
11+
import javax.servlet.ServletRequest;
12+
import javax.servlet.ServletResponse;
13+
import javax.servlet.http.HttpServletRequest;
14+
import javax.servlet.http.HttpServletResponse;
15+
16+
import x.mvmn.gp2srv.camera.CameraProvider;
17+
import x.mvmn.gp2srv.web.service.velocity.TemplateEngine;
18+
import x.mvmn.gp2srv.web.service.velocity.VelocityContextService;
19+
import x.mvmn.jlibgphoto2.GP2AutodetectCameraHelper;
20+
import x.mvmn.jlibgphoto2.GP2Camera;
21+
import x.mvmn.jlibgphoto2.GP2Context;
22+
import x.mvmn.jlibgphoto2.GP2PortInfoList;
23+
import x.mvmn.jlibgphoto2.GP2PortInfoList.GP2PortInfo;
24+
import x.mvmn.lang.util.Provider;
25+
import x.mvmn.log.api.Logger;
26+
27+
public class CameraChoiceFilter extends AbstractGP2Servlet implements Filter {
28+
private static final long serialVersionUID = 1827967172388376853L;
29+
30+
private final CameraProvider camProvider;
31+
32+
public CameraChoiceFilter(final CameraProvider camProvider, final VelocityContextService velocityContextService,
33+
final Provider<TemplateEngine> templateEngineProvider, final Logger logger) {
34+
super(velocityContextService, templateEngineProvider, logger);
35+
this.camProvider = camProvider;
36+
}
37+
38+
public void init(FilterConfig filterConfig) throws ServletException {
39+
}
40+
41+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
42+
if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
43+
HttpServletRequest httpRequest = (HttpServletRequest) request;
44+
HttpServletResponse httpResponse = (HttpServletResponse) response;
45+
if (httpRequest.getRequestURI().startsWith("/static") || camProvider.hasCamera()) {
46+
chain.doFilter(request, response);
47+
} else {
48+
synchronized (camProvider) {
49+
if (!camProvider.hasCamera()) {
50+
String cameraPortParam = httpRequest.getParameter("cameraPort");
51+
if (cameraPortParam != null) {
52+
// Set camera
53+
GP2PortInfoList portList = new GP2PortInfoList();
54+
GP2PortInfo gp2PortInfo = portList.getByPath(cameraPortParam);
55+
if (gp2PortInfo != null) {
56+
camProvider.setCamera(new GP2Camera(gp2PortInfo));
57+
httpResponse.sendRedirect("/");
58+
} else {
59+
httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
60+
}
61+
} else {
62+
// Show camera choice
63+
Map<String, Object> tempalteModel = new HashMap<String, Object>();
64+
tempalteModel.put("cameras", GP2AutodetectCameraHelper.autodetectCameras(new GP2Context()));
65+
serveTempalteUTF8Safely("camera/choice.vm", createContext(httpRequest, httpResponse, tempalteModel), httpResponse, logger);
66+
}
67+
}
68+
}
69+
}
70+
}
71+
}
72+
73+
public void destroy() {
74+
}
75+
}

src/main/java/x/mvmn/gp2srv/web/servlets/CameraControlServlet.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.apache.velocity.context.Context;
1414

1515
import x.mvmn.gp2srv.GPhoto2Server;
16+
import x.mvmn.gp2srv.camera.CameraProvider;
1617
import x.mvmn.gp2srv.camera.CameraService;
1718
import x.mvmn.gp2srv.web.service.velocity.TemplateEngine;
1819
import x.mvmn.gp2srv.web.service.velocity.VelocityContextService;
@@ -136,13 +137,20 @@ protected void processRequestByPath(final String requestPath, final Context velo
136137
try {
137138
if (requestPath.equals("/") || requestPath.equals("") || requestPath.equals("/index") || requestPath.equals("/index.html")) {
138139
serveTempalteUTF8Safely("camera/index.vm", velocityContext, response, logger);
139-
} else if (requestPath.equals("/cameraConfig.json")) {
140+
} else if ("/camdisconnect".equals(requestPath)) {
141+
final CameraProvider camProvider = cameraService.getCameraProvider();
142+
synchronized (camProvider) {
143+
camProvider.getCamera().close();
144+
camProvider.setCamera(null);
145+
}
146+
response.sendRedirect("/");
147+
} else if ("/cameraConfig.json".equals(requestPath)) {
140148
final boolean reRead = Boolean.parseBoolean(request.getParameter("reRead"));
141149
final Map<String, CameraConfigEntryBean> cameraConfig = getConfigAsMap(!reRead);
142150
serveJson(cameraConfig, response);
143-
} else if (requestPath.equals("/favedConfigs.json")) {
151+
} else if ("/favedConfigs.json".equals(requestPath)) {
144152
serveJson(favouredCamConfSettings, response);
145-
} else if (requestPath.equals("/browse.json")) {
153+
} else if ("/browse.json".equals(requestPath)) {
146154
Map<String, Object> result = new HashMap<String, Object>();
147155
String path = request.getParameter("path");
148156
if (path == null || path.trim().isEmpty()) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#parse("camera/head.vm")
2+
<div class="fullWidth">
3+
<div class="pageHead">GPhoto2Server</div>
4+
<div>Choose camera:</div>
5+
<div>
6+
<form method="POST">
7+
<select name="cameraPort">
8+
#foreach($cam in $cameras)
9+
<option value="$cam.portName">$cam.cameraModel</option>
10+
#end
11+
</select>
12+
<br/>
13+
<input type="submit" value="select" />
14+
</form>
15+
</div>
16+
</div>
17+
#parse("camera/foot.vm")

0 commit comments

Comments
 (0)