1 package org
.argeo
.slc
.akb
.core
;
4 import java
.sql
.Connection
;
5 import java
.sql
.DriverManager
;
6 import java
.sql
.PreparedStatement
;
7 import java
.sql
.ResultSet
;
8 import java
.sql
.SQLFeatureNotSupportedException
;
11 import javax
.annotation
.Resource
;
12 import javax
.jcr
.Node
;
13 import javax
.jcr
.Property
;
14 import javax
.jcr
.Repository
;
15 import javax
.jcr
.RepositoryException
;
16 import javax
.jcr
.Session
;
18 import org
.apache
.commons
.io
.IOUtils
;
19 import org
.apache
.commons
.logging
.Log
;
20 import org
.apache
.commons
.logging
.LogFactory
;
21 import org
.argeo
.jcr
.ArgeoNames
;
22 import org
.argeo
.jcr
.JcrUtils
;
23 import org
.argeo
.jcr
.UserJcrUtils
;
24 import org
.argeo
.slc
.SlcException
;
25 import org
.argeo
.slc
.akb
.AkbException
;
26 import org
.argeo
.slc
.akb
.AkbNames
;
27 import org
.argeo
.slc
.akb
.AkbService
;
28 import org
.argeo
.slc
.akb
.AkbTypes
;
29 import org
.argeo
.slc
.jsch
.SimpleUserInfo
;
30 import org
.argeo
.util
.security
.Keyring
;
32 import com
.jcraft
.jsch
.ChannelExec
;
33 import com
.jcraft
.jsch
.JSch
;
36 * Concrete access to akb services. It provides among other an initialized
39 public class AkbServiceImpl
implements AkbService
, AkbNames
{
40 private final static Log log
= LogFactory
.getLog(AkbServiceImpl
.class);
42 /* DEPENDENCY INJECTION */
43 private Repository repository
;
45 private Keyring keyring
;
47 // Populate the repository in a demo context.
48 private Map
<String
, Resource
> demoData
= null;
50 /* Life cycle management */
52 * Call by each startup in order to make sure the backend is ready to
53 * receive/provide data.
57 // TODO make it configurable
58 initJdbcDriver("org.postgresql.Driver");
60 Session adminSession
= null;
62 adminSession
= repository
.login();
64 // Initialization of the model
65 if (!adminSession
.nodeExists(AKB_TEMPLATES_BASE_PATH
)) {
66 JcrUtils
.mkdirs(adminSession
, AKB_TEMPLATES_BASE_PATH
);
67 JcrUtils
.mkdirs(adminSession
, AKB_ENVIRONMENTS_BASE_PATH
);
69 log
.info("Repository has been initialized "
70 + "with AKB's model");
73 // Fill the repository in a demo context
74 if (demoData
!= null) {
75 // Dev only force reload at each start
77 // if (!projectsPar.hasNodes()) {
79 } catch (Exception e
) {
80 throw new AkbException("Cannot initialize backend", e
);
82 JcrUtils
.logoutQuietly(adminSession
);
86 protected Boolean
initJdbcDriver(String driver
) {
88 Class
.forName(driver
);
90 } catch (ClassNotFoundException e
) {
91 if (log
.isDebugEnabled())
92 log
.debug("Cannot load JDBC driver : " + driver
+ ", "
98 /** Clean shutdown of the backend. */
99 public void destroy() {
103 public Node
createAkbTemplate(Node parentNode
, String name
)
104 throws RepositoryException
{
105 String connectorParentName
= "Connectors";
106 String itemsParentName
= "Items";
108 Node newTemplate
= parentNode
.addNode(name
, AkbTypes
.AKB_ENV_TEMPLATE
);
109 newTemplate
.setProperty(Property
.JCR_TITLE
, name
);
111 Node connectorParent
= newTemplate
.addNode(
112 AkbTypes
.AKB_CONNECTOR_FOLDER
, AkbTypes
.AKB_CONNECTOR_FOLDER
);
113 connectorParent
.setProperty(Property
.JCR_TITLE
, connectorParentName
);
115 Node itemsParent
= newTemplate
.addNode(AkbTypes
.AKB_ITEM_FOLDER
,
116 AkbTypes
.AKB_ITEM_FOLDER
);
117 itemsParent
.setProperty(Property
.JCR_TITLE
, itemsParentName
);
122 // ///////////////////////////////////////
125 public boolean testConnector(Node connectorNode
) {
127 if (connectorNode
.isNodeType(AkbTypes
.AKB_JDBC_CONNECTOR
)) {
128 String connectorUrl
= connectorNode
.getProperty(
129 AKB_CONNECTOR_URL
).getString();
130 String connectorUser
= connectorNode
.getProperty(
131 AKB_CONNECTOR_USER
).getString();
133 String pwdPath
= getPasswordPath(connectorNode
);
134 char[] pwd
= keyring
.getAsChars(pwdPath
);
135 DriverManager
.getConnection(connectorUrl
, connectorUser
,
137 savePassword(connectorNode
.getSession(), pwdPath
, pwd
);
139 } else if (connectorNode
.isNodeType(AkbTypes
.AKB_SSH_CONNECTOR
)) {
140 String connectorUrl
= connectorNode
.getProperty(
141 AKB_CONNECTOR_URL
).getString();
142 String connectorUser
= connectorNode
.getProperty(
143 AKB_CONNECTOR_USER
).getString();
144 String pwdPath
= getPasswordPath(connectorNode
);
145 char[] pwd
= keyring
.getAsChars(pwdPath
);
147 URI url
= new URI(connectorUrl
);
148 String host
= url
.getHost();
149 int port
= url
.getPort();
152 JSch jsch
= new JSch();
153 com
.jcraft
.jsch
.Session sess
= jsch
.getSession(connectorUser
,
155 SimpleUserInfo userInfo
= new SimpleUserInfo();
156 userInfo
.setPassword(new String(pwd
));
157 sess
.setUserInfo(userInfo
);
161 savePassword(connectorNode
.getSession(), pwdPath
, pwd
);
164 throw new SlcException("Unsupported connector " + connectorNode
);
166 } catch (Exception e
) {
167 throw new SlcException("Cannot test connection", e
);
172 * Opens a new connection each time. All resources must be cleaned by
175 public PreparedStatement
prepareJdbcQuery(Node node
) {
176 PreparedStatement statement
= null;
178 if (node
.isNodeType(AkbTypes
.AKB_JDBC_QUERY
)) {
179 String sqlQuery
= node
.getProperty(AKB_QUERY_TEXT
).getString();
181 String connectorPath
= node
.getProperty(AKB_USED_CONNECTOR
)
183 Node connectorNode
= node
.getSession().getNode(connectorPath
);
184 String connectorUrl
= connectorNode
.getProperty(
185 AKB_CONNECTOR_URL
).getString();
186 String connectorUser
= connectorNode
.getProperty(
187 AKB_CONNECTOR_USER
).getString();
189 String pwdPath
= getPasswordPath(connectorNode
);
190 // String pwdPath = connectorNode.getPath() + '/'
191 // + ArgeoNames.ARGEO_PASSWORD;
192 char[] pwd
= keyring
.getAsChars(pwdPath
);
193 Connection connection
= DriverManager
.getConnection(
194 connectorUrl
, connectorUser
, new String(pwd
));
196 statement
= connection
.prepareStatement(sqlQuery
,
197 ResultSet
.TYPE_SCROLL_INSENSITIVE
,
198 ResultSet
.CONCUR_READ_ONLY
);
199 } catch (SQLFeatureNotSupportedException e
) {
200 log
.warn("Scroll not supported for " + connectorUrl
);
201 statement
= connection
.prepareStatement(sqlQuery
);
204 throw new SlcException("Unsupported node " + node
);
207 } catch (Exception e
) {
208 throw new SlcException("Cannot execute test JDBC query on " + node
,
213 public String
executeCommand(Node node
) {
215 String command
= node
.getProperty(AkbNames
.AKB_COMMAND_TEXT
)
218 String connectorPath
= node
.getProperty(AKB_USED_CONNECTOR
)
220 Node connectorNode
= node
.getSession().getNode(connectorPath
);
221 String connectorUrl
= connectorNode
.getProperty(AKB_CONNECTOR_URL
)
223 String connectorUser
= connectorNode
224 .getProperty(AKB_CONNECTOR_USER
).getString();
225 String pwdPath
= getPasswordPath(connectorNode
);
226 char[] pwd
= keyring
.getAsChars(pwdPath
);
228 URI url
= new URI(connectorUrl
);
229 String host
= url
.getHost();
230 int port
= url
.getPort();
233 JSch jsch
= new JSch();
234 com
.jcraft
.jsch
.Session sess
= jsch
.getSession(connectorUser
, host
,
236 SimpleUserInfo userInfo
= new SimpleUserInfo();
237 userInfo
.setPassword(new String(pwd
));
238 sess
.setUserInfo(userInfo
);
241 sess
.openChannel("exec");
242 final ChannelExec channel
= (ChannelExec
) sess
.openChannel("exec");
243 channel
.setCommand(command
);
245 channel
.setInputStream(null);
246 channel
.setXForwarding(false);
247 channel
.setAgentForwarding(false);
248 channel
.setErrStream(null);
252 String output
= IOUtils
.toString(channel
.getInputStream());
253 channel
.disconnect();
258 } catch (Exception e
) {
259 throw new SlcException("Cannot execute command", e
);
264 public String
retrieveFile(Node node
) {
266 String filePath
= node
.getProperty(AkbNames
.AKB_FILE_PATH
)
268 String command
= "cat " + filePath
;
270 // TODO do a proper scp
271 String connectorPath
= node
.getProperty(AKB_USED_CONNECTOR
)
273 Node connectorNode
= node
.getSession().getNode(connectorPath
);
274 String connectorUrl
= connectorNode
.getProperty(AKB_CONNECTOR_URL
)
276 String connectorUser
= connectorNode
277 .getProperty(AKB_CONNECTOR_USER
).getString();
278 String pwdPath
= getPasswordPath(connectorNode
);
279 char[] pwd
= keyring
.getAsChars(pwdPath
);
281 URI url
= new URI(connectorUrl
);
282 String host
= url
.getHost();
283 int port
= url
.getPort();
286 JSch jsch
= new JSch();
287 com
.jcraft
.jsch
.Session sess
= jsch
.getSession(connectorUser
, host
,
289 SimpleUserInfo userInfo
= new SimpleUserInfo();
290 userInfo
.setPassword(new String(pwd
));
291 sess
.setUserInfo(userInfo
);
294 sess
.openChannel("exec");
295 final ChannelExec channel
= (ChannelExec
) sess
.openChannel("exec");
296 channel
.setCommand(command
);
298 channel
.setInputStream(null);
299 channel
.setXForwarding(false);
300 channel
.setAgentForwarding(false);
301 channel
.setErrStream(null);
305 String output
= IOUtils
.toString(channel
.getInputStream());
306 channel
.disconnect();
311 } catch (Exception e
) {
312 throw new SlcException("Cannot execute command", e
);
317 protected String
getPasswordPath(Node node
) throws RepositoryException
{
318 Node home
= UserJcrUtils
.getUserHome(node
.getSession());
319 if (node
.getPath().startsWith(home
.getPath()))
320 return node
.getPath() + '/' + ArgeoNames
.ARGEO_PASSWORD
;
322 return home
.getPath() + node
.getPath() + '/'
323 + ArgeoNames
.ARGEO_PASSWORD
;
326 private void savePassword(Session session
, String pwdPath
, char[] pwd
)
327 throws RepositoryException
{
328 if (!session
.itemExists(pwdPath
)) {
329 JcrUtils
.mkdirs(session
, JcrUtils
.parentPath(pwdPath
));
331 keyring
.set(pwdPath
, pwd
);
336 // /** Expose injected repository */
337 // public Repository getRepository() {
338 // return repository;
341 /* DEPENDENCY INJECTION */
342 public void setRepository(Repository repository
) {
343 this.repository
= repository
;
346 public void setDemoData(Map
<String
, Resource
> demoData
) {
347 this.demoData
= demoData
;
350 public void setKeyring(Keyring keyring
) {
351 this.keyring
= keyring
;