http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.js ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.js b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.js new file mode 100644 index 0000000..f5d3ecc --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.js @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +with (Scripting) { + + var instance = new ReaderScript({ + route: function (input) { + str = IOUtils.toString(input); + if (str.match(/sed do/i)) { + return Script.FAIL_RELATIONSHIP; + } else { + return Script.SUCCESS_RELATIONSHIP; + } + } + }); + logger.debug("Got a logger and properties" + properties); +}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.py ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.py b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.py new file mode 100644 index 0000000..91e6ca7 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.py @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os, re, subprocess + +class SimpleJythonReader(ReaderScript): + def route(self, input): + logger.info("In route") + returnid = os.system("c:\\cygwin\\bin\\echo GOOD") + fname = self.getAttribute("filename") + counter = self.getAttribute("counter") + fname = fname + '.' + counter + self.setAttribute("filename", fname) + for line in FileUtil.wrap(input): + if re.match("^sed",line): return self.FAIL_RELATIONSHIP + + return self.SUCCESS_RELATIONSHIP + + + +instance = SimpleJythonReader() http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.rb ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.rb b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.rb new file mode 100644 index 0000000..c10765d --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readTest.rb @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +class SimpleJRubyReader < ReaderScript + field_reader :FAIL_RELATIONSHIP, :SUCCESS_RELATIONSHIP, :logger, :attributes + + def route( input ) + logger.info("Route Input") + input.to_io.each_line do |line| + return FAIL_RELATIONSHIP if line.match /^sed/i + end + + attributes.put("filename", "NewFileNameFromReadTest") + return SUCCESS_RELATIONSHIP + end +end +$logger.info("Logger is made available in shared variables...however, the SimpleJRubyReader.logger is not set till after this script returns") + +SimpleJRubyReader.new http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.js ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.js b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.js new file mode 100644 index 0000000..e34ad5f --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.js @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +with (Scripting) { + var instance = new ReaderScript({ + route: function (input) { + var str = IOUtils.toString(input); + var expr = instance.getProperty("expr"); + filename = instance.attributes.get("filename"); + instance.setAttribute("filename", filename + ".modified"); + if (str.match(expr)) { + return Script.FAIL_RELATIONSHIP; + } else { + return Script.SUCCESS_RELATIONSHIP; + } + } + }); +} + http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.py ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.py b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.py new file mode 100644 index 0000000..23e55af --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.py @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import re + +class SimpleJythonReader(ReaderScript): + def getPropertyDescriptors( self ): + nev = StandardValidators.NON_EMPTY_VALIDATOR + return [PropertyDescriptor.Builder().name("expr").required(1).addValidator(nev).build()] + + def route( self, input ): + expr = self.getProperty("expr") + filename = self.getAttribute("filename") + self.setAttribute("filename", filename + ".modified") + for line in FileUtil.wrap(input): + if re.match(expr, line): return self.FAIL_RELATIONSHIP + + return self.SUCCESS_RELATIONSHIP + +instance = SimpleJythonReader() + http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.rb ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.rb b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.rb new file mode 100644 index 0000000..308b652 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/readWithParams.rb @@ -0,0 +1,33 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +class SimpleJRubyReader < ReaderScript + field_reader :FAIL_RELATIONSHIP, :SUCCESS_RELATIONSHIP, :properties, :attributes + + def route( input ) + expr = properties.get "expr" + raise "Must specify the 'expr' property!" if expr.nil? + filename = attributes.get "filename" + setAttribute("filename", filename + ".modified") + input.to_io.each_line do |line| + return FAIL_RELATIONSHIP if line.match expr + end + + return SUCCESS_RELATIONSHIP + end +end + +$logger.debug("Can access logger and properties via shared instance variables...props = " + @properties.to_s) +SimpleJRubyReader.new + http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.js ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.js b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.js new file mode 100644 index 0000000..47ef546 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.js @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +with (Scripting) { + var a = new Relationship.Builder().name("a").description("some good stuff").build() + var b = new Relationship.Builder().name("b").description("some other stuff").build() + var c = new Relationship.Builder().name("c").description("some bad stuff").build() + var instance = new ReaderScript({ + getExceptionRoute: function () { + return c; + }, + getRelationships: function () { + return [a, b, c]; + }, + route: function (input) { + var str = IOUtils.toString(input); + var lines = str.split("\n"); + for (var line in lines) { + if (lines[line].match(/^bad/i)) { + return b; + } else if (lines[line].match(/^sed/i)) { + throw "That's no good!"; + } + } + return a; + } + }); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.py ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.py b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.py new file mode 100644 index 0000000..ed5408a --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.py @@ -0,0 +1,37 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import re + +class RoutingReader(ReaderScript): + A = Relationship.Builder().name("a").description("some good stuff").build() + B = Relationship.Builder().name("b").description("some other stuff").build() + C = Relationship.Builder().name("c").description("some bad stuff").build() + + def getRelationships(self): + return [self.A,self.B,self.C] + + def getExceptionRoute(self): + return self.C + + def route( self, input ): + for line in FileUtil.wrap(input): + if re.match("^bad", line, re.IGNORECASE): + return self.B + if re.match("^sed", line): + raise RuntimeError("That's no good!") + + return self.A + +instance = RoutingReader() http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.rb ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.rb b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.rb new file mode 100644 index 0000000..38249ae --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/routeTest.rb @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +class SimpleJRubyReader < ReaderScript + + @@a = Relationship::Builder.new().name("a").description("some good stuff").build() + @@b = Relationship::Builder.new().name("b").description("some bad stuff").build() + @@c = Relationship::Builder.new().name("c").description("some other stuff").build() + + def getRelationships + return [@@a, @@b, @@c] + end + + def getExceptionRoute + @@c + end + + def route( input ) + input.to_io.each_line do |line| + return @@b if line.match /^bad/i + raise "That's no good!" if line.match /^sed/i + end + + @@a + end +end + +SimpleJRubyReader.new http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.js ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.js b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.js new file mode 100644 index 0000000..72bb80e --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.js @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +with (Scripting) { + + var instance = new ConverterScript({ + convert: function (input) { + var buffReader = new java.io.BufferedReader(new java.io.InputStreamReader(input)); + instance.createFlowFile("firstLine", Script.FAIL_RELATIONSHIP, function (output) { + var out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(output)); + var firstLine = buffReader.readLine(); + out.write(firstLine, 0, firstLine.length()); + out.flush(); + out.close(); + }); + + instance.createFlowFile("otherLines", Script.SUCCESS_RELATIONSHIP, function (output) { + var out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(output)); + var line = buffReader.readLine(); + while (line != null) { + out.write(line, 0, line.length()); + out.newLine(); + line = buffReader.readLine(); + } + out.flush(); + out.close(); + }); + } + + }); + logger.debug("Processor props" + properties) +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.py ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.py b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.py new file mode 100644 index 0000000..d52368e --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.py @@ -0,0 +1,60 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from org.python.core.io import TextIOWrapper,BufferedReader,BufferedWriter,StreamIO +from org.apache.nifi.scripting import OutputStreamHandler + +class WriteFirstLine(OutputStreamHandler): + def __init__(self, wrappedIn): + self.wrappedIn = wrappedIn + + def write(self, output): + streamOut = StreamIO(output, False) + bufWrtr = BufferedWriter(streamOut, 8192) + wrappedOut = TextIOWrapper(bufWrtr) + wrappedOut.write(self.wrappedIn.readline(8192)) + wrappedOut.flush() + wrappedOut.close() + +class WriteOtherLines(OutputStreamHandler): + def __init__(self, wrappedIn): + self.wrappedIn = wrappedIn + + def write(self, output): + streamOut = StreamIO(output, False) + bufWrtr = BufferedWriter(streamOut, 8192) + wrappedOut = TextIOWrapper(bufWrtr) + line = self.wrappedIn.readline(8192) + while line != '': + wrappedOut.write(line) + line = self.wrappedIn.readline(8192) + wrappedOut.flush() + wrappedOut.close() + +class SimpleConverter(ConverterScript): + + def convert(self, input): + streamIn = StreamIO(input, False) + bufRdr = BufferedReader(streamIn, 8192) + wrappedIn = TextIOWrapper(bufRdr) + + writeFirstLine = WriteFirstLine(wrappedIn) + self.createFlowFile("firstLine", self.FAIL_RELATIONSHIP, writeFirstLine) + + writeOtherLines = WriteOtherLines(wrappedIn) + self.createFlowFile("otherLines", self.SUCCESS_RELATIONSHIP, writeOtherLines) + +instance = SimpleConverter() + + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.rb ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.rb b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.rb new file mode 100644 index 0000000..f333294 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/simpleConverter.rb @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +java_import 'org.apache.nifi.scripting.OutputStreamHandler' +class SimpleConverter < ConverterScript + field_reader :FAIL_RELATIONSHIP, :SUCCESS_RELATIONSHIP, :logger, :attributes + + def convert(input) + in_io = input.to_io + createFlowFile("firstLine", FAIL_RELATIONSHIP, OutputStreamHandler.impl do |method, out| + out_io = out.to_io + out_io << in_io.readline.to_java_bytes + out_io.close + logger.debug("Wrote data to failure...this message logged with logger from super class") + end) + + createFlowFile("otherLines", SUCCESS_RELATIONSHIP, OutputStreamHandler.impl do |method, out| + out_io = out.to_io + in_io.each_line { |line| + out_io << line + } + out_io.close + logger.debug("Wrote data to success...this message logged with logger from super class") + end) + in_io.close + end + +end + +$logger.debug("Creating SimpleConverter...this message logged with logger from shared variables") +SimpleConverter.new \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.js ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.js b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.js new file mode 100644 index 0000000..1e055b7 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.js @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +with (Scripting) { + var instance = new WriterScript({ + process: function (input, output) { + var str = IOUtils.toString(input); + IOUtils.write(str.split("\n").pop(), output); + output.flush(); + } + }); +} + http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.py ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.py b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.py new file mode 100644 index 0000000..c563b66 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.py @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +class SimpleWriter(WriterScript): + def process( self, input, output ): + last = FileUtil.wrap(input).readlines()[-1] + writer = FileUtil.wrap(output) + writer.write(last) + writer.close() + +instance = SimpleWriter() http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.rb ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.rb b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.rb new file mode 100644 index 0000000..5be4553 --- /dev/null +++ b/nar-bundles/execute-script-bundle/execute-script-processors/src/test/resources/writeTest.rb @@ -0,0 +1,32 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +class SimpleJRubyRunner < WriterScript + def process( input, output ) + in_io = input.to_io + out_io = output.to_io + + last = nil + in_io.each_line do |line| + last = line + end + + out_io << last unless last.nil? + + in_io.close + out_io.close + end +end + +SimpleJRubyRunner.new http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/nar/pom.xml ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/nar/pom.xml b/nar-bundles/execute-script-bundle/nar/pom.xml new file mode 100644 index 0000000..1cc28dc --- /dev/null +++ b/nar-bundles/execute-script-bundle/nar/pom.xml @@ -0,0 +1,36 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.nifi</groupId> + <artifactId>execute-script-bundle</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>execute-script-nar</artifactId> + <name>Execute Script NAR</name> + <packaging>nar</packaging> + <description>NiFi Script Running NAR</description> + + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>execute-script-processors</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/execute-script-bundle/pom.xml ---------------------------------------------------------------------- diff --git a/nar-bundles/execute-script-bundle/pom.xml b/nar-bundles/execute-script-bundle/pom.xml new file mode 100644 index 0000000..b3abb36 --- /dev/null +++ b/nar-bundles/execute-script-bundle/pom.xml @@ -0,0 +1,81 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.nifi</groupId> + <artifactId>nar-container-common</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>execute-script-bundle</artifactId> + <version>0.0.1-SNAPSHOT</version> + + <name>Execute Script Bundle</name> + <packaging>pom</packaging> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-processor-utils</artifactId> + <version>0.0.1-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-stream-utils</artifactId> + <version>0.0.1-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-utils</artifactId> + <version>0.0.1-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-core-flowfile-attributes</artifactId> + <version>0.0.1-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-mock</artifactId> + <version>0.0.1-SNAPSHOT</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.jruby</groupId> + <artifactId>jruby</artifactId> + <version>1.7.16.1</version> + </dependency> + + <dependency> + <groupId>org.python</groupId> + <artifactId>jython-standalone</artifactId> + <version>2.7-b3</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.4</version> + </dependency> + </dependencies> + </dependencyManagement> + + <modules> + <module>execute-script-processors</module> + <module>nar</module> + </modules> +</project> http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/.gitignore ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/.gitignore b/nar-bundles/framework-bundle/framework/administration/.gitignore new file mode 100755 index 0000000..ea8c4bf --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/.gitignore @@ -0,0 +1 @@ +/target http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/pom.xml ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/pom.xml b/nar-bundles/framework-bundle/framework/administration/pom.xml new file mode 100644 index 0000000..b5dd171 --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/pom.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-framework-parent</artifactId> + <version>0.0.1-SNAPSHOT</version> + </parent> + + <artifactId>nifi-administration</artifactId> + <version>0.0.1-SNAPSHOT</version> + <name>NiFi Administration</name> + <build> + <resources> + <resource> + <directory>src/main/resources</directory> + </resource> + <resource> + <directory>src/main/xsd</directory> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>jaxb2-maven-plugin</artifactId> + <executions> + <execution> + <id>current</id> + <goals> + <goal>xjc</goal> + </goals> + <configuration> + <packageName>org.apache.nifi.authorization.generated</packageName> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-user-actions</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>core-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-nar</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-utils</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-properties</artifactId> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-security-utils</artifactId> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-beans</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjweaver</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-collections4</artifactId> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/AuditDataSourceFactoryBean.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/AuditDataSourceFactoryBean.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/AuditDataSourceFactoryBean.java new file mode 100644 index 0000000..aeb2755 --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/AuditDataSourceFactoryBean.java @@ -0,0 +1,222 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin; + +import java.io.File; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import org.apache.commons.lang3.StringUtils; +import org.h2.jdbcx.JdbcConnectionPool; +import org.apache.nifi.util.NiFiProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.FactoryBean; + +/** + * + */ +public class AuditDataSourceFactoryBean implements FactoryBean { + + private static final Logger logger = LoggerFactory.getLogger(AuditDataSourceFactoryBean.class); + private static final String NF_USERNAME_PASSWORD = "nf"; + private static final int MAX_CONNECTIONS = 5; + + // database file name + private static final String AUDIT_DATABASE_FILE_NAME = "nifi-audit"; + + // ------------ + // action table + // ------------ + private static final String CREATE_ACTION_TABLE = "CREATE TABLE ACTION (" + + "ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, " + + "USER_DN VARCHAR2(255) NOT NULL, " + + "USER_NAME VARCHAR2(100) NOT NULL, " + + "SOURCE_ID VARCHAR2(100) NOT NULL, " + + "SOURCE_NAME VARCHAR2(1000) NOT NULL, " + + "SOURCE_TYPE VARCHAR2(1000) NOT NULL, " + + "OPERATION VARCHAR2(50) NOT NULL, " + + "ACTION_TIMESTAMP TIMESTAMP NOT NULL " + + ")"; + + // ----------------- + // component details + // ----------------- + private static final String CREATE_PROCESSOR_DETAILS_TABLE = "CREATE TABLE PROCESSOR_DETAILS (" + + "ACTION_ID INT NOT NULL PRIMARY KEY, " + + "TYPE VARCHAR2(1000) NOT NULL, " + + "FOREIGN KEY (ACTION_ID) REFERENCES ACTION(ID)" + + ")"; + + private static final String CREATE_REMOTE_PROCESS_GROUP_DETAILS_TABLE = "CREATE TABLE REMOTE_PROCESS_GROUP_DETAILS (" + + "ACTION_ID INT NOT NULL PRIMARY KEY, " + + "URI VARCHAR2(2500) NOT NULL, " + + "FOREIGN KEY (ACTION_ID) REFERENCES ACTION(ID)" + + ")"; + + // -------------- + // action details + // -------------- + private static final String CREATE_MOVE_DETAILS_TABLE = "CREATE TABLE MOVE_DETAILS (" + + "ACTION_ID INT NOT NULL PRIMARY KEY, " + + "GROUP_ID VARCHAR2(100) NOT NULL, " + + "GROUP_NAME VARCHAR2(1000) NOT NULL, " + + "PREVIOUS_GROUP_ID VARCHAR2(100) NOT NULL, " + + "PREVIOUS_GROUP_NAME VARCHAR2(1000) NOT NULL, " + + "FOREIGN KEY (ACTION_ID) REFERENCES ACTION(ID)" + + ")"; + + private static final String CREATE_CONFIGURE_DETAILS_TABLE = "CREATE TABLE CONFIGURE_DETAILS (" + + "ACTION_ID INT NOT NULL PRIMARY KEY, " + + "NAME VARCHAR2(1000) NOT NULL, " + + "VALUE VARCHAR2(5000), " + + "PREVIOUS_VALUE VARCHAR2(5000), " + + "FOREIGN KEY (ACTION_ID) REFERENCES ACTION(ID)" + + ")"; + + private static final String CREATE_CONNECT_DETAILS_TABLE = "CREATE TABLE CONNECT_DETAILS (" + + "ACTION_ID INT NOT NULL PRIMARY KEY, " + + "SOURCE_ID VARCHAR2(100) NOT NULL, " + + "SOURCE_NAME VARCHAR2(1000), " + + "SOURCE_TYPE VARCHAR2(1000) NOT NULL, " + + "RELATIONSHIP VARCHAR2(1000), " + + "DESTINATION_ID VARCHAR2(100) NOT NULL, " + + "DESTINATION_NAME VARCHAR2(1000), " + + "DESTINATION_TYPE VARCHAR2(1000) NOT NULL, " + + "FOREIGN KEY (ACTION_ID) REFERENCES ACTION(ID)" + + ")"; + + private static final String CREATE_PURGE_DETAILS_TABLE = "CREATE TABLE PURGE_DETAILS (" + + "ACTION_ID INT NOT NULL PRIMARY KEY, " + + "END_DATE TIMESTAMP NOT NULL, " + + "FOREIGN KEY (ACTION_ID) REFERENCES ACTION(ID)" + + ")"; + + private JdbcConnectionPool connectionPool; + + private NiFiProperties properties; + + @Override + public Object getObject() throws Exception { + if (connectionPool == null) { + + // locate the repository directory + String repositoryDirectoryPath = properties.getProperty(NiFiProperties.REPOSITORY_DATABASE_DIRECTORY); + + // ensure the repository directory is specified + if (repositoryDirectoryPath == null) { + throw new NullPointerException("Database directory must be specified."); + } + + // create a handle to the repository directory + File repositoryDirectory = new File(repositoryDirectoryPath); + + // get a handle to the database file + File databaseFile = new File(repositoryDirectory, AUDIT_DATABASE_FILE_NAME); + + // format the database url + String databaseUrl = "jdbc:h2:" + databaseFile + ";AUTOCOMMIT=OFF;DB_CLOSE_ON_EXIT=FALSE;LOCK_MODE=3"; + String databaseUrlAppend = properties.getProperty(NiFiProperties.H2_URL_APPEND); + if (StringUtils.isNotBlank(databaseUrlAppend)) { + databaseUrl += databaseUrlAppend; + } + + // create the pool + connectionPool = JdbcConnectionPool.create(databaseUrl, NF_USERNAME_PASSWORD, NF_USERNAME_PASSWORD); + connectionPool.setMaxConnections(MAX_CONNECTIONS); + + Connection connection = null; + ResultSet rs = null; + Statement statement = null; + try { + // get a connection + connection = connectionPool.getConnection(); + connection.setAutoCommit(false); + + // determine if the tables need to be created + rs = connection.getMetaData().getTables(null, null, "ACTION", null); + if (!rs.next()) { + logger.info("Database not built for repository: " + databaseUrl + ". Building now..."); + RepositoryUtils.closeQuietly(rs); + + // create a statement for initializing the database + statement = connection.createStatement(); + + // action table + statement.execute(CREATE_ACTION_TABLE); + + // component details + statement.execute(CREATE_PROCESSOR_DETAILS_TABLE); + statement.execute(CREATE_REMOTE_PROCESS_GROUP_DETAILS_TABLE); + + // action details + statement.execute(CREATE_MOVE_DETAILS_TABLE); + statement.execute(CREATE_CONFIGURE_DETAILS_TABLE); + statement.execute(CREATE_CONNECT_DETAILS_TABLE); + statement.execute(CREATE_PURGE_DETAILS_TABLE); + } else { + logger.info("Existing database found and connected to at: " + databaseUrl); + } + + // commit any changes + connection.commit(); + } catch (SQLException sqle) { + RepositoryUtils.rollback(connection, logger); + throw sqle; + } finally { + RepositoryUtils.closeQuietly(rs); + RepositoryUtils.closeQuietly(statement); + RepositoryUtils.closeQuietly(connection); + } + } + + return connectionPool; + } + + @Override + public Class getObjectType() { + return JdbcConnectionPool.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public void setProperties(NiFiProperties properties) { + this.properties = properties; + } + + /** + * Disposes resources. + */ + public void shutdown() { + + // shutdown the connection pool + if (connectionPool != null) { + try { + connectionPool.dispose(); + } catch (Exception e) { + logger.warn("Unable to dispose of connection pool: " + e.getMessage()); + if (logger.isDebugEnabled()) { + logger.warn(StringUtils.EMPTY, e); + } + } + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/RepositoryUtils.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/RepositoryUtils.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/RepositoryUtils.java new file mode 100644 index 0000000..b95388b --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/RepositoryUtils.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import org.slf4j.Logger; + +/** + * A utility class for useful methods dealing with the repository + * + * @author unattributed + */ +public class RepositoryUtils { + + public static void rollback(final Connection conn, final Logger logger) { + try { + if (null != conn) { + conn.rollback(); + } + } catch (final SQLException sqe) { + logger.warn("The following problem occurred while trying to rollback " + conn + ": " + sqe.getLocalizedMessage()); + if (logger.isDebugEnabled()) { + logger.debug("", sqe); + } + } + } + + /** + * Closes the given statement quietly - no logging, no exceptions + * + * @param statement + */ + public static void closeQuietly(final Statement statement) { + + if (null != statement) { + try { + statement.close(); + } catch (final SQLException se) { /*IGNORE*/ + + } + } + } + + /** + * Closes the given result set quietly - no logging, no exceptions + * + * @param resultSet + */ + public static void closeQuietly(final ResultSet resultSet) { + if (null != resultSet) { + try { + resultSet.close(); + } catch (final SQLException se) {/*IGNORE*/ + + } + } + } + + /** + * Closes the given connection quietly - no logging, no exceptions + * + * @param conn + */ + public static void closeQuietly(final Connection conn) { + if (null != conn) { + try { + conn.close(); + } catch (final SQLException se) {/*IGNORE*/ + + } + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/UserDataSourceFactoryBean.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/UserDataSourceFactoryBean.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/UserDataSourceFactoryBean.java new file mode 100644 index 0000000..1f64f6e --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/UserDataSourceFactoryBean.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin; + +import java.io.File; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; +import org.h2.jdbcx.JdbcConnectionPool; +import org.apache.nifi.user.NiFiUser; +import org.apache.nifi.util.NiFiProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.FactoryBean; + +/** + * + */ +public class UserDataSourceFactoryBean implements FactoryBean { + + private static final Logger logger = LoggerFactory.getLogger(UserDataSourceFactoryBean.class); + private static final String NF_USERNAME_PASSWORD = "nf"; + private static final int MAX_CONNECTIONS = 5; + + // database file name + private static final String AUDIT_DATABASE_FILE_NAME = "nifi-users"; + + private static final String CREATE_USER_TABLE = "CREATE TABLE USER (" + + "ID VARCHAR2(100) NOT NULL PRIMARY KEY, " + + "DN VARCHAR2(255) NOT NULL UNIQUE, " + + "USER_NAME VARCHAR2(100) NOT NULL, " + + "USER_GROUP VARCHAR2(100), " + + "CREATION TIMESTAMP NOT NULL, " + + "LAST_ACCESSED TIMESTAMP, " + + "LAST_VERIFIED TIMESTAMP, " + + "JUSTIFICATION VARCHAR2(500) NOT NULL, " + + "STATUS VARCHAR2(10) NOT NULL" + + ")"; + + private static final String CREATE_AUTHORITY_TABLE = "CREATE TABLE AUTHORITY (" + + "ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, " + + "USER_ID VARCHAR2(100) NOT NULL, " + + "ROLE VARCHAR2(50) NOT NULL, " + + "FOREIGN KEY (USER_ID) REFERENCES USER (ID), " + + "CONSTRAINT USER_ROLE_UNIQUE_CONSTRAINT UNIQUE (USER_ID, ROLE)" + + ")"; + + private static final String INSERT_ANONYMOUS_USER = "INSERT INTO USER (" + + "ID, DN, USER_NAME, CREATION, LAST_VERIFIED, JUSTIFICATION, STATUS" + + ") VALUES (" + + "'" + UUID.randomUUID().toString() + "', " + + "'" + NiFiUser.ANONYMOUS_USER_DN + "', " + + "'" + NiFiUser.ANONYMOUS_USER_DN + "', " + + "NOW(), " + + "NOW(), " + + "'Anonymous user needs no justification', " + + "'ACTIVE'" + + ")"; + + private static final String INSERT_ANONYMOUS_MONITOR_AUTHORITY = "INSERT INTO AUTHORITY (" + + "USER_ID, ROLE" + + ") VALUES (" + + "(SELECT ID FROM USER WHERE DN = '" + NiFiUser.ANONYMOUS_USER_DN + "'), " + + "'ROLE_MONITOR'" + + ")"; + + private static final String INSERT_ANONYMOUS_DFM_AUTHORITY = "INSERT INTO AUTHORITY (" + + "USER_ID, ROLE" + + ") VALUES (" + + "(SELECT ID FROM USER WHERE DN = '" + NiFiUser.ANONYMOUS_USER_DN + "'), " + + "'ROLE_DFM'" + + ")"; + + private static final String INSERT_ANONYMOUS_ADMIN_AUTHORITY = "INSERT INTO AUTHORITY (" + + "USER_ID, ROLE" + + ") VALUES (" + + "(SELECT ID FROM USER WHERE DN = '" + NiFiUser.ANONYMOUS_USER_DN + "'), " + + "'ROLE_ADMIN'" + + ")"; + + private static final String INSERT_ANONYMOUS_NIFI_AUTHORITY = "INSERT INTO AUTHORITY (" + + "USER_ID, ROLE" + + ") VALUES (" + + "(SELECT ID FROM USER WHERE DN = '" + NiFiUser.ANONYMOUS_USER_DN + "'), " + + "'ROLE_NIFI'" + + ")"; + + private static final String INSERT_ANONYMOUS_PROVENANCE_AUTHORITY = "INSERT INTO AUTHORITY (" + + "USER_ID, ROLE" + + ") VALUES (" + + "(SELECT ID FROM USER WHERE DN = '" + NiFiUser.ANONYMOUS_USER_DN + "'), " + + "'ROLE_PROVENANCE'" + + ")"; + + private static final String SELECT_ANONYMOUS_PROVENANCE_AUTHORITY = "SELECT * FROM AUTHORITY " + + "WHERE " + + "USER_ID = (SELECT ID FROM USER WHERE DN = '" + NiFiUser.ANONYMOUS_USER_DN + "') " + + "AND " + + "ROLE = 'ROLE_PROVENANCE'"; + + private JdbcConnectionPool connectionPool; + + private NiFiProperties properties; + + @Override + public Object getObject() throws Exception { + if (connectionPool == null) { + + // locate the repository directory + String repositoryDirectoryPath = properties.getProperty(NiFiProperties.REPOSITORY_DATABASE_DIRECTORY); + + // ensure the repository directory is specified + if (repositoryDirectoryPath == null) { + throw new NullPointerException("Database directory must be specified."); + } + + // create a handle to the repository directory + File repositoryDirectory = new File(repositoryDirectoryPath); + + // create a handle to the database directory and file + File databaseFile = new File(repositoryDirectory, AUDIT_DATABASE_FILE_NAME); + String databaseUrl = getDatabaseUrl(databaseFile); + + // create the pool + connectionPool = JdbcConnectionPool.create(databaseUrl, NF_USERNAME_PASSWORD, NF_USERNAME_PASSWORD); + connectionPool.setMaxConnections(MAX_CONNECTIONS); + + Connection connection = null; + ResultSet rs = null; + Statement statement = null; + try { + // get a connection + connection = connectionPool.getConnection(); + connection.setAutoCommit(false); + + // create a statement for creating/updating the database + statement = connection.createStatement(); + + // determine if the tables need to be created + rs = connection.getMetaData().getTables(null, null, "USER", null); + if (!rs.next()) { + logger.info("Database not built for repository: " + databaseUrl + ". Building now..."); + + // create the tables + statement.execute(CREATE_USER_TABLE); + statement.execute(CREATE_AUTHORITY_TABLE); + + // seed the anonymous user + statement.execute(INSERT_ANONYMOUS_USER); + statement.execute(INSERT_ANONYMOUS_MONITOR_AUTHORITY); + statement.execute(INSERT_ANONYMOUS_DFM_AUTHORITY); + statement.execute(INSERT_ANONYMOUS_ADMIN_AUTHORITY); + statement.execute(INSERT_ANONYMOUS_NIFI_AUTHORITY); + } else { + logger.info("Existing database found and connected to at: " + databaseUrl); + } + + // close the previous result set + RepositoryUtils.closeQuietly(rs); + + // merge in the provenance role to handle existing databases + rs = statement.executeQuery(SELECT_ANONYMOUS_PROVENANCE_AUTHORITY); + if (!rs.next()) { + statement.execute(INSERT_ANONYMOUS_PROVENANCE_AUTHORITY); + } + + // commit any changes + connection.commit(); + } catch (SQLException sqle) { + RepositoryUtils.rollback(connection, logger); + throw sqle; + } finally { + RepositoryUtils.closeQuietly(rs); + RepositoryUtils.closeQuietly(statement); + RepositoryUtils.closeQuietly(connection); + } + } + + return connectionPool; + } + + /** + * Get the database url for the specified database file. + * + * @param databaseFile + * @return + */ + private String getDatabaseUrl(File databaseFile) { + String databaseUrl = "jdbc:h2:" + databaseFile + ";AUTOCOMMIT=OFF;DB_CLOSE_ON_EXIT=FALSE;LOCK_MODE=3"; + String databaseUrlAppend = properties.getProperty(NiFiProperties.H2_URL_APPEND); + if (StringUtils.isNotBlank(databaseUrlAppend)) { + databaseUrl += databaseUrlAppend; + } + return databaseUrl; + } + + @Override + public Class getObjectType() { + return JdbcConnectionPool.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public void setProperties(NiFiProperties properties) { + this.properties = properties; + } + + /** + * Disposes resources. + */ + public void shutdown() { + + // shutdown the connection pool + if (connectionPool != null) { + try { + connectionPool.dispose(); + } catch (Exception e) { + logger.warn("Unable to dispose of connection pool: " + e.getMessage()); + if (logger.isDebugEnabled()) { + logger.warn(StringUtils.EMPTY, e); + } + } + } + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/ActionDAO.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/ActionDAO.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/ActionDAO.java new file mode 100644 index 0000000..5d6d222 --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/ActionDAO.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin.dao; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import org.apache.nifi.action.Action; +import org.apache.nifi.history.HistoryQuery; +import org.apache.nifi.history.History; +import org.apache.nifi.history.PreviousValue; + +/** + * Action data access. + */ +public interface ActionDAO { + + /** + * Persists the specified action. + * + * @param action + * @throws DataAccessException + */ + void createAction(Action action) throws DataAccessException; + + /** + * Finds all actions that meet the specified criteria. + * + * @param actionQuery + * @return + * @throws DataAccessException + */ + History findActions(HistoryQuery actionQuery) throws DataAccessException; + + /** + * Finds the previous values for the specified property in the specified + * processor. Returns empty list if there are none. + * + * @param processorId + * @return + */ + Map<String, List<PreviousValue>> getPreviousValues(String processorId); + + /** + * Finds the specified action. + * + * @param actionId + * @return + * @throws DataAccessException + */ + Action getAction(Integer actionId) throws DataAccessException; + + /** + * Deletes all actions up to the specified end date. + * + * @param endDate + * @throws DataAccessException + */ + void deleteActions(Date endDate) throws DataAccessException; +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/AuthorityDAO.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/AuthorityDAO.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/AuthorityDAO.java new file mode 100644 index 0000000..2992884 --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/AuthorityDAO.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin.dao; + +import java.util.Set; +import org.apache.nifi.authorization.Authority; + +/** + * Authority data access. + */ +public interface AuthorityDAO { + + /** + * Finds all Authority for the specified user. + * + * @param userId + * @return + */ + Set<Authority> findAuthoritiesByUserId(String userId) throws DataAccessException; + + /** + * Creates a new Authorities for the specified user. + * + * @param authorities + * @param userId + */ + void createAuthorities(Set<Authority> authorities, String userId) throws DataAccessException; + + /** + * Removes all Authorities for the specified user. + * + * @param userId + * @throws DataAccessException + */ + void deleteAuthorities(String userId) throws DataAccessException; + + /** + * Removes the specified Authority. + * + * @param authorities + * @param userId + */ + void deleteAuthorities(Set<Authority> authorities, String userId) throws DataAccessException; +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DAOFactory.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DAOFactory.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DAOFactory.java new file mode 100644 index 0000000..dee4ef9 --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DAOFactory.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin.dao; + +/** + * + */ +public interface DAOFactory { + + UserDAO getUserDAO(); + + ActionDAO getActionDAO(); + + AuthorityDAO getAuthorityDAO(); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DataAccessException.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DataAccessException.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DataAccessException.java new file mode 100644 index 0000000..05bf4af --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/DataAccessException.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin.dao; + +/** + * Represents any error that might occur while administering NiFi accounts. + */ +public class DataAccessException extends RuntimeException { + + public DataAccessException(Throwable cause) { + super(cause); + } + + public DataAccessException(String message, Throwable cause) { + super(message, cause); + } + + public DataAccessException(String message) { + super(message); + } + + public DataAccessException() { + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/UserDAO.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/UserDAO.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/UserDAO.java new file mode 100644 index 0000000..9ffab5d --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/UserDAO.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin.dao; + +import java.util.Date; +import java.util.Set; +import org.apache.nifi.user.AccountStatus; +import org.apache.nifi.user.NiFiUser; + +/** + * Defines the user data access object. + */ +public interface UserDAO { + + /** + * Determines whether there are any PENDING user accounts. + * + * @return + * @throws DataAccessException + */ + Boolean hasPendingUserAccounts() throws DataAccessException; + + /** + * Returns all users. + * + * @return + * @throws DataAccessException + */ + Set<NiFiUser> findUsers() throws DataAccessException; + + /** + * Returns all user groups. + * + * @return + * @throws DataAccessException + */ + Set<String> findUserGroups() throws DataAccessException; + + /** + * Returns all users for the specified group. + * + * @param group + * @return + * @throws DataAccessException + */ + Set<NiFiUser> findUsersForGroup(String group) throws DataAccessException; + + /** + * Returns the user with the specified id. + * + * @param id + * @return + * @throws DataAccessException + */ + NiFiUser findUserById(String id) throws DataAccessException; + + /** + * Returns the user with the specified DN. + * + * @param dn + * @return + */ + NiFiUser findUserByDn(String dn) throws DataAccessException; + + /** + * Creates a new user based off the specified NiFiUser. + * + * @param user + */ + void createUser(NiFiUser user) throws DataAccessException; + + /** + * Updates the specified NiFiUser. + * + * @param user + */ + void updateUser(NiFiUser user) throws DataAccessException; + + /** + * Deletes the specified user. + * + * @param id + * @throws DataAccessException + */ + void deleteUser(String id) throws DataAccessException; + + /** + * Sets the status of the specified group. + * + * @param group + * @param status + * @throws DataAccessException + */ + void updateGroupStatus(String group, AccountStatus status) throws DataAccessException; + + /** + * Sets the last verified time for all users in the specified group. + * + * @param group + * @param lastVerified + * @throws DataAccessException S + */ + void updateGroupVerification(String group, Date lastVerified) throws DataAccessException; + + /** + * Ungroups the specified group. + * + * @param group + * @throws DataAccessException + */ + void ungroup(String group) throws DataAccessException; + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/4d998c12/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/impl/DAOFactoryImpl.java ---------------------------------------------------------------------- diff --git a/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/impl/DAOFactoryImpl.java b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/impl/DAOFactoryImpl.java new file mode 100644 index 0000000..2f3de0e --- /dev/null +++ b/nar-bundles/framework-bundle/framework/administration/src/main/java/org/apache/nifi/admin/dao/impl/DAOFactoryImpl.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.admin.dao.impl; + +import java.sql.Connection; +import org.apache.nifi.admin.dao.ActionDAO; +import org.apache.nifi.admin.dao.AuthorityDAO; +import org.apache.nifi.admin.dao.DAOFactory; +import org.apache.nifi.admin.dao.UserDAO; + +/** + * + */ +public class DAOFactoryImpl implements DAOFactory { + + private final Connection connection; + + public DAOFactoryImpl(Connection connection) { + this.connection = connection; + } + + @Override + public ActionDAO getActionDAO() { + return new StandardActionDAO(connection); + } + + @Override + public AuthorityDAO getAuthorityDAO() { + return new StandardAuthorityDAO(connection); + } + + @Override + public UserDAO getUserDAO() { + return new StandardUserDAO(connection); + } + +}