Skip to content
This repository has been archived by the owner on Nov 9, 2022. It is now read-only.

Commit

Permalink
Resolve #107: deploy modules will deploy document transforms; also mo…
Browse files Browse the repository at this point in the history
…dified dir structure for rest-api config and extensions
  • Loading branch information
Peter Kim committed Jun 7, 2013
1 parent 13a6320 commit d661d45
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 9 deletions.
2 changes: 1 addition & 1 deletion deploy/default.properties
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ app-type=mvc
# the location of your REST API options
# relevant to app-types rest and hybrid.
#
rest-options.dir=${basedir}/rest-api
rest-options.dir=${basedir}/rest-api/config

#
# the location of your unit test code
Expand Down
93 changes: 91 additions & 2 deletions deploy/lib/ml_rest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def initialize(options)
def get_files(path, data = [])
@logger.debug "getting files for #{path}"
if (File.directory?(path))
Dir.glob("#{path}/*.xqy") do |entry|
Dir.glob("#{path}/*.{xqy,xslt,xsl}") do |entry|
if File.directory?(entry)
get_files(entry, data)
else
Expand Down Expand Up @@ -84,5 +84,94 @@ def install_extensions(path)
@logger.error "#{path} does not exist"
end
end

def install_transforms(path)
if (File.exists?(path))


data = get_files(path)
size = data.length

data.each_with_index do |d, i|

if (File.extname(d).include?("xq"))
file_type = 'xquery'
headers = {
'Content-Type' => 'application/xquery'
}
elsif (File.extname(d).include?("xsl"))
file_type = 'xslt'
headers = {
'Content-Type' => 'application/xslt+xml'
}
end

file = open(d, "rb")
contents = file.read
transformName = File.basename(d).gsub(/(.xqy|.xquery|.xq|.xslt|.xsl)$/, '')
params = []


# TODO: I'm assuming there's a way to consolidate the following if/elsif but I'm a Ruby newbie and I'm being conservative
if (file_type == 'xquery')
# look for annotations of this form:
# %roxy:params("argname=type", "anotherarg=type")
contents.scan(/declare\s+(\%\w+:\w+\(([\"\w\-\=\,\s:]*)\))*\s*function/m).each do |m|
args = '';
if (m[0] && (m[0].include? "%roxy:params"))
if (m[1].match(/\"/))
m[1].gsub!(/\"/, '').split(',').each do |p|
arg = p.strip
parts = arg.split('=')
param = parts[0]
type = parts[1]
@logger.debug("param: #{param}")
@logger.debug("type: #{type}")
params << "trans:#{param}=#{url_encode(type)}"
end
end
end
end
elsif (file_type == 'xslt')
# look for annotations of this form:
# %roxy:params("argname=type", "anotherarg=type")
contents.scan(/<!--\s*(\%\w+:\w+\(([\"\w\-\=\,\s:]*)\))*\s*-->/m).each do |m|
args = '';
if (m[0] && (m[0].include? "%roxy:params"))
if (m[1].match(/\"/))
m[1].gsub!(/\"/, '').split(',').each do |p|
arg = p.strip
parts = arg.split('=')
param = parts[0]
type = parts[1]
@logger.debug("param: #{param}")
@logger.debug("type: #{type}")
params << "trans:#{param}=#{url_encode(type)}"
end
end
end
end
end

@logger.debug "params: #{params}"
@logger.debug "transformName: #{transformName}"
# @logger.debug "methods: #{methods}"
url = "http://#{@hostname}:#{@port}/v1/config/transforms/#{transformName}"
if (params.length > 0)
url << "?" << params.join("&")
end
@logger.debug "loading: #{d}"

@logger.debug "url: #{url}"
r = go url, "put", headers, nil, contents
if (r.code.to_i < 200 && r.code.to_i > 206)
@logger.error("code: #{r.code.to_i} body:#{r.body}")
end
end

else
@logger.error "#{path} does not exist"
end
end
end
end
end
17 changes: 13 additions & 4 deletions deploy/lib/server_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ def self.init
sample_config = File.expand_path("../../sample/ml-config.sample.xml", __FILE__)
sample_properties = File.expand_path("../../sample/build.sample.properties", __FILE__)
build_properties = File.expand_path("../../build.properties", __FILE__)
options_dir = File.expand_path("../../../rest-api/options", __FILE__)
rest_ext_dir = File.expand_path("../../../rest-ext", __FILE__)
options_file = File.expand_path("../../../rest-api/options/all.xml", __FILE__)
options_dir = File.expand_path("../../../rest-api/config/options", __FILE__)
rest_ext_dir = File.expand_path("../../../rest-api/ext", __FILE__)
rest_transforms_dir = File.expand_path("../../../rest-api/transforms", __FILE__)
options_file = File.expand_path("../../../rest-api/config/options/all.xml", __FILE__)
sample_options = File.expand_path("../../sample/all.sample.xml", __FILE__)

force = find_arg(['--force']).present?
Expand Down Expand Up @@ -148,11 +149,12 @@ def self.init
# If this is a rest or hybrid app, set up some initial options
if ["rest", "hybrid"].include? app_type
FileUtils.mkdir_p rest_ext_dir
FileUtils.mkdir_p rest_transforms_dir
FileUtils.mkdir_p options_dir
FileUtils.cp sample_options, options_file
FileUtils.cp(
File.expand_path("../../sample/properties.sample.xml", __FILE__),
File.expand_path("../../../rest-api/properties.xml", __FILE__))
File.expand_path("../../../rest-api/config/properties.xml", __FILE__))
end

target_config = File.expand_path(ServerConfig.properties["ml.config.file"], __FILE__)
Expand Down Expand Up @@ -757,6 +759,11 @@ def deploy_modules
logger.info "\nLoading REST extensions from #{@properties['ml.rest-ext.dir']}\n"
mlRest.install_extensions(File.expand_path(@properties['ml.rest-ext.dir']))
end

if (@properties.has_key?('ml.rest-transforms.dir') && File.exist?(@properties['ml.rest-transforms.dir']))
logger.info "\nLoading REST transforms from #{@properties['ml.rest-transforms.dir']}\n"
mlRest.install_transforms(File.expand_path(@properties['ml.rest-transforms.dir']))
end
end
end

Expand Down Expand Up @@ -867,6 +874,8 @@ def mlRest
:port => @properties["ml.app-port"],
:logger => @logger
})
else
@mlRest
end
end

Expand Down
10 changes: 8 additions & 2 deletions deploy/sample/build.sample.properties
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,19 @@ app-type=mvc
# the location of your REST API options
# relevant to app-types rest and hybrid.
#
rest-options.dir=${basedir}/rest-api
rest-options.dir=${basedir}/rest-api/config

#
# the location of your REST API extension modules
# relevant to app-types rest and hybrid.
#
rest-ext.dir=${basedir}/rest-ext
rest-ext.dir=${basedir}/rest-api/ext

#
# the location of your REST API transform modules
# relevant to app-types rest and hybrid.
#
rest-transforms.dir=${basedir}/rest-api/transforms

#
# The Roxy rewriter handles both Roxy MVC and the ML REST API
Expand Down
45 changes: 45 additions & 0 deletions deploy/sample/rest-transform.sample.xqy
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
xquery version "1.0-ml";
module namespace example = "http://marklogic.com/rest-api/transform/add-attr";

declare namespace roxy = "http://marklogic.com/roxy";

(: REST API transforms managed by Roxy must follow these conventions:
1. Their filenames must reflect the name of the transform.
For example, an XQuery transform named add-attr must be contained in a file named add-attr.xqy
and have a module namespace of "http://marklogic.com/rest-api/transform/add-attr".
2. Must declare the roxy namespace with the URI "http://marklogic.com/roxy".
declare namespace roxy = "http://marklogic.com/roxy";
3. Must annotate the transform function with the transform parameters:
%roxy:params("uri=xs:string", "priority=xs:int")
:)

declare
%roxy:params("uri=xs:string", "priority=xs:int")
function example:transform(
$context as map:map,
$params as map:map,
$content as document-node()
) as document-node()
{
if (fn:empty($content/*)) then $content
else
let $value := (map:get($params,"value"),"UNDEFINED")[1]
let $name := (map:get($params, "name"), "transformed")[1]
let $root := $content/*
return document {
$root/preceding-sibling::node(),
element {fn:name($root)} {
attribute { fn:QName("", $name) } {$value},
$root/@*,
$root/node()
},
$root/following-sibling::node()
}
};
30 changes: 30 additions & 0 deletions deploy/sample/rest-transform.sample.xslt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

<!--
REST API transforms managed by Roxy must follow these conventions:
1. Their filenames must reflect the name of the transform.
For example, an XSL transform named add-attr must be contained in a file named add-attr.xslt.
2. Must annotate the file with the transform parameters in an XML comment:
%roxy:params("uri=xs:string", "priority=xs:int")
-->

<!-- %roxy:params("uri=xs:string", "priority=xs:int") -->
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:example="http://marklogic.com/rest-api/example/transform"
xmlns:map="http://marklogic.com/xdmp/map">
<xsl:param name="context" as="map:map"/>
<xsl:param name="params" as="map:map"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:attribute
name='{(map:get($params,"name"),"transformed")[1]}'
select='(map:get($params,"value"),"UNDEFINED")[1]'/>
<xsl:copy-of select="@*"/>
<xsl:copy-of select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

0 comments on commit d661d45

Please sign in to comment.