Skip to content
This repository has been archived by the owner on Jan 27, 2021. It is now read-only.

Commit

Permalink
fixed #5 - add ability to read files off of filesystem
Browse files Browse the repository at this point in the history
fixed #2 - breakpoints working better
fixed #1 - added consistent highlighting
- added history to console commands
- added support for ML < 8
  • Loading branch information
paxtonhare committed Feb 8, 2017
1 parent 225f681 commit 8899d29
Show file tree
Hide file tree
Showing 39 changed files with 622 additions and 109 deletions.
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ targetCompatibility = 1.8
repositories {
mavenLocal()
jcenter()
maven { url 'https://developer.marklogic.com/maven2/' }
}

dependencies {
Expand All @@ -38,6 +39,7 @@ dependencies {
compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}")
compile('com.marklogic:java-client-api:3.0.5')
compile('com.marklogic:marklogic-xcc:8.0.6')
compile('commons-io:commons-io:2.4')

// Optional Boot library - see https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-devtools.html
Expand All @@ -47,10 +49,10 @@ dependencies {

node {
// Version of node to use.
version = '6.8.1'
version = '7.4.0'

// Version of npm to use.
npmVersion = '3.10.8'
npmVersion = '4.0.5'

download = true

Expand Down
3 changes: 2 additions & 1 deletion src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">

</head>
<body>
<app-root>Loading...</app-root>
<dialog-outlet></dialog-outlet>
</body>
</html>
4 changes: 3 additions & 1 deletion src/main/java/com/marklogic/debugger/LoginInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ public class LoginInfo {
public String username;
public String password;
public String hostname;
public int port;

public String toString() {
return "{\"username\":\"" + username + "\"," +
"\"hostname\": \"" + hostname + "\"}";
"\"hostname\": \"" + hostname + "\"," +
"\"port\": \"" + port + "\"}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ public class ConnectionAuthenticationFilter extends
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
public static final String SPRING_SECURITY_FORM_HOST_KEY = "hostname";
public static final String SPRING_SECURITY_FORM_PORT_KEY = "port";

private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
private String hostnameParameter = SPRING_SECURITY_FORM_HOST_KEY;
private String hostportParameter = SPRING_SECURITY_FORM_PORT_KEY;
private boolean postOnly = true;

// ~ Constructors
Expand All @@ -63,8 +65,10 @@ public Authentication attemptAuthentication(HttpServletRequest request,
String username = obtainUsername(request);
String password = obtainPassword(request);
String hostname = obtainHostname(request);
Integer port = obtainPort(request);
LoginInfo loginInfo = new LoginInfo();
loginInfo.hostname = hostname;
loginInfo.port = port;
loginInfo.username = username;
loginInfo.password = password;
request.getSession().setAttribute("loginInfo", loginInfo);
Expand All @@ -81,10 +85,14 @@ public Authentication attemptAuthentication(HttpServletRequest request,
hostname = "";
}

if (port == null) {
port = 8000;
}

username = username.trim();

ConnectionAuthenticationToken authRequest = new ConnectionAuthenticationToken(
username, password, hostname);
username, password, hostname, port);

// Allow subclasses to set the "details" property
setDetails(request, authRequest);
Expand Down Expand Up @@ -128,6 +136,10 @@ protected String obtainHostname(HttpServletRequest request) {
return request.getParameter(hostnameParameter);
}

protected Integer obtainPort(HttpServletRequest request) {
return Integer.parseInt(request.getParameter(hostportParameter));
}

/**
* Provided so that subclasses may configure what is put into the authentication
* request's details property.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class ConnectionAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private Object credentials;
private Object hostname;
private Object port;

// ~ Constructors
// ===================================================================================================
Expand All @@ -37,11 +38,12 @@ public class ConnectionAuthenticationToken extends AbstractAuthenticationToken {
* will return <code>false</code>.
*
*/
public ConnectionAuthenticationToken(Object principal, Object credentials, Object hostname) {
public ConnectionAuthenticationToken(Object principal, Object credentials, Object hostname, Object port) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.hostname = hostname;
this.port = port;
setAuthenticated(false);
}

Expand All @@ -55,12 +57,13 @@ public ConnectionAuthenticationToken(Object principal, Object credentials, Objec
* @param credentials
* @param authorities
*/
public ConnectionAuthenticationToken(Object principal, Object credentials, Object hostname,
public ConnectionAuthenticationToken(Object principal, Object credentials, Object hostname, Object port,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
this.hostname = hostname;
this.port = port;
super.setAuthenticated(true); // must use super, as we override
}

Expand All @@ -79,6 +82,8 @@ public Object getHostname() {
return this.hostname;
}

public Object getPort() { return this.port; }

public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,17 @@ public Authentication authenticate(Authentication authentication) throws Authent
String username = token.getPrincipal().toString();
String password = token.getCredentials().toString();
String hostname = token.getHostname().toString();
int port = Integer.parseInt(token.getPort().toString());

if (username == "" || password == "" || hostname == "") {
if (username == "" || password == "" || hostname == "" || port == 0) {
throw new BadCredentialsException("Invalid credentials");
}
/**
* For now, building a new RestTemplate each time. This should in general be okay, because we're typically not
* authenticating users over and over.
*/
restConfig.setHost(hostname);
restConfig.setRestPort(port);
RestClient client = new RestClient(restConfig, new SimpleCredentialsProvider(username, password));
URI uri = client.buildUri(pathToAuthenticateAgainst, null);
try {
Expand All @@ -78,7 +80,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
}

return new ConnectionAuthenticationToken(token.getPrincipal(), token.getCredentials(),
token.getHostname(), token.getAuthorities());
token.getHostname(), token.getPort(), token.getAuthorities());
}

public void setPathToAuthenticateAgainst(String pathToAuthenticateAgainst) {
Expand Down
38 changes: 37 additions & 1 deletion src/main/java/com/marklogic/debugger/web/ApiController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
import com.marklogic.client.DatabaseClientFactory;
import com.marklogic.client.DatabaseClientFactory.Authentication;
import com.marklogic.client.FailedRequestException;
import com.marklogic.client.ResourceNotFoundException;
import com.marklogic.client.eval.EvalResult;
import com.marklogic.client.eval.EvalResultIterator;
import com.marklogic.client.eval.ServerEvaluationCall;
import com.marklogic.debugger.auth.ConnectionAuthenticationToken;
import com.marklogic.debugger.errors.InvalidRequestException;
import com.marklogic.xcc.*;
import com.marklogic.xcc.exceptions.RequestException;
import com.marklogic.xcc.types.ValueType;
import org.apache.commons.io.IOUtils;
import org.springframework.http.MediaType;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -91,6 +95,15 @@ public String getServerFiles(@PathVariable String serverId) throws InvalidReques
}


@RequestMapping(value = "/marklogic/files", method = RequestMethod.GET)
@ResponseBody
public String getMarkLogicSystemFiles() throws InvalidRequestException {
ConnectionAuthenticationToken auth = (ConnectionAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
HashMap<String, String> hm = new HashMap<>();
return evalQuery(auth, "get-marklogic-system-files.xqy", hm);
}


@RequestMapping(value = "/servers/{serverId}/file", method = RequestMethod.GET)
@ResponseBody
public String getServerFile(@PathVariable String serverId, @RequestParam String uri) throws InvalidRequestException {
Expand Down Expand Up @@ -169,6 +182,15 @@ public String setBreakpoints(@PathVariable String requestId, @RequestBody List<B
return "";
}

@RequestMapping(value = "/requests/{requestId}/breakpoints", method = RequestMethod.GET)
@ResponseBody
public String getBreakpoints(@PathVariable String requestId) throws InvalidRequestException {
ConnectionAuthenticationToken auth = (ConnectionAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
HashMap<String, String> hm = new HashMap<>();
hm.put("requestId", requestId);
return evalQuery(auth, "set-breakpoints.xqy", hm);
}

@RequestMapping(value = "/requests/{requestId}/eval", method = RequestMethod.POST)
@ResponseBody
public String evalExpression(@PathVariable String requestId, @RequestBody String xquery) throws InvalidRequestException {
Expand Down Expand Up @@ -207,7 +229,7 @@ private String evalQuery(ConnectionAuthenticationToken auth, String xquery, Hash
String result = "";
if (auth != null) {
try {
DatabaseClient client = DatabaseClientFactory.newClient((String)auth.getHostname(), 8000, (String)auth.getPrincipal(), (String)auth.getCredentials(), Authentication.DIGEST);
DatabaseClient client = DatabaseClientFactory.newClient((String)auth.getHostname(), (Integer)auth.getPort(), (String)auth.getPrincipal(), (String)auth.getCredentials(), Authentication.DIGEST);
String q = getQuery(xquery);
ServerEvaluationCall sec = client.newServerEval().xquery(q);
for (String key : params.keySet()) {
Expand All @@ -219,6 +241,20 @@ private String evalQuery(ConnectionAuthenticationToken auth, String xquery, Hash
result += res.getString();
}
}
catch(ResourceNotFoundException e) {
try {
ContentSource contentSource = ContentSourceFactory.newContentSource((String)auth.getHostname(), (Integer)auth.getPort(), (String)auth.getPrincipal(), (String)auth.getCredentials());
Session session = contentSource.newSession();
AdhocQuery adhocQuery = session.newAdhocQuery(getQuery(xquery));
for (String key : params.keySet()) {
adhocQuery.setNewVariable(key, ValueType.XS_STRING, params.get(key));
}
ResultSequence res = session.submitRequest(adhocQuery);
result += res.asString();
} catch (RequestException e1) {
e1.printStackTrace();
}
}
catch(FailedRequestException e) {
if (e.getFailedRequest().getMessageCode().equals("DBG-REQUESTRECORD")) {
throw new InvalidRequestException();
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/modules/continue.xqy
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
declare variable $requestId external;

dbg:continue($requestId)
dbg:continue(xs:unsignedLong($requestId))
2 changes: 1 addition & 1 deletion src/main/resources/modules/disable-server.xqy
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
declare variable $serverId external;

dbg:disconnect($serverId)
dbg:disconnect(xs:unsignedLong($serverId))
2 changes: 1 addition & 1 deletion src/main/resources/modules/enable-server.xqy
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
declare variable $serverId external;

dbg:connect($serverId)
dbg:connect(xs:unsignedLong($serverId))
10 changes: 5 additions & 5 deletions src/main/resources/modules/get-attached.xqy
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ declare variable $serverId external;

let $a := json:array()
let $_ :=
for $attached in dbg:attached($serverId)
let $status := xdmp:request-status(xdmp:host(), $serverId, $attached)
for $attached in dbg:attached(xs:unsignedLong($serverId))
let $status := xdmp:request-status(xdmp:host(), xs:unsignedLong($serverId), $attached)
let $o := map:new((
map:entry("server", xdmp:server-name($status/*:server-id)),
map:entry("host", xdmp:host-name($status/*:host-id)),
map:entry("modules", xdmp:database-name($status/*:modules)),
map:entry("database", xdmp:database-name($status/*:database)),
map:entry("modules", if ($status/*:modules = 0) then "FileSystem" else xdmp:database-name($status/*:modules)),
map:entry("database", if ($status/*:database = 0) then "FileSystem" else xdmp:database-name($status/*:database)),
for $item in $status/*[fn:not(self::*:server-id or self::*:host-id or self::*:modules or self::*:database)]
return
map:entry(functx:words-to-camel-case(fn:replace(fn:local-name($item), "-", " ")), $item/fn:data())
))
return
json:array-push($a, $o)
return
$a
xdmp:to-json($a)
12 changes: 12 additions & 0 deletions src/main/resources/modules/get-breakpoints.xqy
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
declare variable $requestId external;

let $request-id := xs:unsignedLong($requestId)
let $expr := dbg:expr($request-id, dbg:breakpoints($request-id))
let $o := json:object()
let $_ := (
map:put($o, "uri", $expr/dbg:uri/fn:string()),
map:put($o, "line", $expr/dbg:line/fn:data()),
map:put($o, "statement", $expr/dbg:expr-source/fn:string())
)
return
xdmp:to-json($o)
30 changes: 21 additions & 9 deletions src/main/resources/modules/get-file.xqy
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import module namespace admin = "http://marklogic.com/xdmp/admin"
at "/MarkLogic/admin.xqy";

declare variable $serverId external;
declare variable $uri external;

declare variable $ml-dir := xdmp:filesystem-filepath('.') || '/Modules';

let $modules-db := xdmp:server-modules-database($serverId)
let $server-id := xs:unsignedLong($serverId)
let $config := admin:get-configuration()
let $modules-db := admin:appserver-get-modules-database($config, $server-id)
let $server-root := admin:appserver-get-root($config, $server-id)
return
xdmp:invoke-function(function() {
if ($modules-db = 0) then
if (fn:starts-with($uri, "/MarkLogic/")) then
xdmp:document-get($ml-dir || $uri)
else
fn:doc($uri)
},
map:new((
map:entry("isolation", "different-transaction"),
map:entry("database", $modules-db),
map:entry("transactionMode", "update-auto-commit")
)))
xdmp:document-get($server-root || $uri)
else
xdmp:invoke-function(function() {
if (fn:starts-with($uri, "/MarkLogic/")) then
xdmp:document-get($ml-dir || $uri)
else
fn:doc($uri)
},
<options xmlns="xdmp:eval">
<isolation>different-transaction</isolation>
<database>{$modules-db}</database>
<transaction-mode>update-auto-commit</transaction-mode>
</options>)
Loading

0 comments on commit 8899d29

Please sign in to comment.