atna 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/atna.gemspec +27 -0
- data/lib/atna.rb +8 -0
- data/lib/atna/logger.rb +94 -0
- data/lib/atna/rfc3881.rb +188 -0
- data/lib/atna/udp_sender.rb +12 -0
- data/lib/atna/utils.rb +1 -0
- data/lib/atna/utils/xml_builder.rb +136 -0
- data/lib/atna/version.rb +3 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NGIyMmIwYmZiMGFhMzVlMWEwMDEyYmU2Y2Y2MWM5NzY1ODg5NmRlNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MDkwZDg3MGViMmY2NTg0MmM5ZWM0OTZkMzU5OTY1YzIxZTRlOTYwZQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YmU1MmQxNTg5NWY2MDMwMTBmNWY3NDcxNmQzMmIyZDM0OTUxMWVlNjVjNjMy
|
10
|
+
NmVjZTY1NmI1YjJkNmY1MjM1ZGIxMjg3MTg4MjZhMWEwYzg0OTgwYmVjMjc2
|
11
|
+
MWYwOWQwZWIxOGUxZjZmOTVlNDlkZGRhYWZjZTE2OGZmNzg3YmE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWNkMDcxYzg2OWQzNjBlMDZmODJlZDI0N2U0Y2RhYTc1NzFiMWIxMmExM2Jj
|
14
|
+
ZWMwYzdiMTBkYmQxNjhiY2ZhNzNjZGY3ODBjZjIwYjhhM2Q2ZWZiZDFmNzg3
|
15
|
+
NTNlNDEyODYxNDNiMzBhYzNkYmI4YmZjNWQ5NTQ3YWEzYjYwODE=
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Tetsuhisa MAKINO
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Tetsuhisa MAKINO
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Atna
|
2
|
+
|
3
|
+
IHE ITI ATNA Udp socket logger with RFC3881 Message builder.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'atna'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install atna
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/maki-tetsu/atna/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/atna.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8 -*- mode: ruby -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'atna/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "atna"
|
8
|
+
spec.version = Atna::VERSION
|
9
|
+
spec.authors = ["Tetsuhisa MAKINO"]
|
10
|
+
spec.email = ["tim.makino@gmail.com"]
|
11
|
+
spec.summary = %q{IHE ITI ATNA Udp socket logger with RFC3881 Message builder.}
|
12
|
+
# spec.description = %q{TODO: Write a longer description. Optional.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# for Development
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
|
25
|
+
# for production
|
26
|
+
spec.add_dependency "nokogiri"
|
27
|
+
end
|
data/lib/atna.rb
ADDED
data/lib/atna/logger.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "socket"
|
3
|
+
|
4
|
+
# ATNA 監査証跡対応版ライブラリ
|
5
|
+
#
|
6
|
+
# ログの送信にのみ利用します。
|
7
|
+
# 監査メッセージ本体は別途対応
|
8
|
+
module ATNA
|
9
|
+
class Logger
|
10
|
+
# ATNA メッセージ構築用パラメータ
|
11
|
+
VALID_OPTIONS = [:pri, :version, :timestamp, :hostname, :app_name, :procid, :msgid, :structured_data]
|
12
|
+
# ATNA 用の UTF-8 BOMB
|
13
|
+
UTF8_BOMB = 0xEFBBBF
|
14
|
+
# PRI の値
|
15
|
+
PRI = "<85>"
|
16
|
+
# MSGID の値(ATNA では固定値)
|
17
|
+
MSGID = "IHE+RFC-3881"
|
18
|
+
|
19
|
+
def initialize(host = 'localhost', port = 514, default_options = { })
|
20
|
+
@host, @port = host, port
|
21
|
+
@default_options = default_options
|
22
|
+
end
|
23
|
+
|
24
|
+
# メッセージを送信
|
25
|
+
#
|
26
|
+
# xmlmsg :: 送信すべき XML メッセージ本体
|
27
|
+
# options ::
|
28
|
+
# :version :: バージョン番号
|
29
|
+
# :timestamp :: Time インスタンス(未指定時は現在時刻を利用)
|
30
|
+
# :hostname :: メッセージ発信元 hostname(未指定時はホスト名を取得:localhost時は - を設定)
|
31
|
+
# :app_name :: アプリケーション名(未指定時は - を設定)
|
32
|
+
# :procid :: プロセスID(未指定時は - を設定)
|
33
|
+
# :msgid :: メッセージID(未指定時は - を設定)
|
34
|
+
# :structured_data :: 構造化データ
|
35
|
+
def notify!(xmlmsg, options = { })
|
36
|
+
options = @default_options.merge(options)
|
37
|
+
validate_options(options)
|
38
|
+
update_blank_options(options)
|
39
|
+
|
40
|
+
sender = UdpSender.new(@host, @port)
|
41
|
+
datagram = serialize_message(xmlmsg, options)
|
42
|
+
sender.send(datagram)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def validate_options(options)
|
48
|
+
unless (unknown_options = options.keys - VALID_OPTIONS).empty?
|
49
|
+
raise ArgumentError, "Unknown option keys(#{unknown_options.join(", ")})"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_blank_options(options)
|
54
|
+
VALID_OPTIONS.each do |key|
|
55
|
+
if options[key].nil? || options[key].empty?
|
56
|
+
case key
|
57
|
+
when :pri
|
58
|
+
options[key] = PRI
|
59
|
+
when :timestamp
|
60
|
+
options[key] = Time.now
|
61
|
+
when :hostname
|
62
|
+
options[key] = Socket.gethostname
|
63
|
+
options[key] = "-" if options[key] == "localhost"
|
64
|
+
when :msgid
|
65
|
+
options[key] = MSGID
|
66
|
+
else
|
67
|
+
options[key] = "-"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def serialize_message(xmlmsg, options)
|
74
|
+
buf = StringIO.new("wb")
|
75
|
+
# HEADER
|
76
|
+
buf.write("#{options[:pri]}#{options[:version]} #{options[:timestamp].utc.iso8601} ")
|
77
|
+
buf.write("#{options[:hostname]} #{options[:app_name]} #{options[:procid]} ")
|
78
|
+
buf.write("#{options[:msgid]}")
|
79
|
+
buf.write(" ")
|
80
|
+
|
81
|
+
# 構造化データ
|
82
|
+
buf.write("#{options[:structured_data]}")
|
83
|
+
buf.write(" ")
|
84
|
+
|
85
|
+
# MSG
|
86
|
+
buf.write(UTF8_BOMB)
|
87
|
+
buf.write(xmlmsg)
|
88
|
+
|
89
|
+
# 巻き戻し
|
90
|
+
buf.rewind
|
91
|
+
return buf.string
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/atna/rfc3881.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require "atna/utils"
|
3
|
+
|
4
|
+
module ATNA
|
5
|
+
# ATNA::RFC3881
|
6
|
+
#
|
7
|
+
# Build RFC 3881 Message(xml) Builder.
|
8
|
+
# Message building by +ATNA::RFC3881::AuditMessage.new+ and add child element +<<+ or
|
9
|
+
# +add_child+ method.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# include ATNA::RFC3881
|
13
|
+
#
|
14
|
+
# msg = AuditMessage.new
|
15
|
+
# msg << AuditMessage::EventParticipant.new(:UserID => "user1",
|
16
|
+
# "RoleIDCode" => [{ :code => "1" }, { :code => "2" }])
|
17
|
+
# msg << AuditMessage::EventIdentification.new(:EventActionCode => AuditMessage::EventIdentification::EVENT_ACTION_CODE["Create"],
|
18
|
+
# :EventDateTime => Time.now.utc.iso8601,
|
19
|
+
# :EventOutcomeIndicator => AuditMessage::EventIdentification::EVENT_OUTCOME_INDICATOR["Success"],
|
20
|
+
# "EventID" => { :code => "1" },
|
21
|
+
# "EventTypeCode" => [{ :code => "2" }, { :code => "3" }])
|
22
|
+
# msg << AuditMessage::ActiveParticipant.new(:UserID => "user2",
|
23
|
+
# "RoleIDCode" => [{ :code => "1" }, { :code => "2" }])
|
24
|
+
# # ...
|
25
|
+
module RFC3881
|
26
|
+
class AuditMessage < ATNA::Utils::XmlBuilder::Base
|
27
|
+
class EventIdentification < ATNA::Utils::XmlBuilder::Base
|
28
|
+
EVENT_ACTION_CODE = {
|
29
|
+
"Create" => "C",
|
30
|
+
"Read" => "R",
|
31
|
+
"Update" => "U",
|
32
|
+
"Delete" => "D",
|
33
|
+
"Execute" => "E",
|
34
|
+
}
|
35
|
+
|
36
|
+
EVENT_OUTCOME_INDICATOR = {
|
37
|
+
"Success" => 0,
|
38
|
+
"Minor failure" => 4,
|
39
|
+
"Serious failure" => 8,
|
40
|
+
"Major failure; action mode unavailable" => 12,
|
41
|
+
}
|
42
|
+
|
43
|
+
attributes :EventActionCode, :EventDateTime, :EventOutcomeIndicator
|
44
|
+
|
45
|
+
class EventID < ATNA::Utils::XmlBuilder::Base
|
46
|
+
attributes :code, :codeSystem, :codeSystemName, :displayName, :originalText
|
47
|
+
end
|
48
|
+
|
49
|
+
class EventTypeCode < ATNA::Utils::XmlBuilder::Base
|
50
|
+
attributes :code, :codeSystem, :codeSystemName, :displayName, :originalText
|
51
|
+
end
|
52
|
+
|
53
|
+
children_order EventID, EventTypeCode
|
54
|
+
end
|
55
|
+
|
56
|
+
class ActiveParticipant < ATNA::Utils::XmlBuilder::Base
|
57
|
+
NETWORK_ACCESS_POINT_TYPE_CODE = {
|
58
|
+
"Machine Name, including DNS namee" => 1,
|
59
|
+
"IP Address" => 2,
|
60
|
+
"Telephone Number" => 3,
|
61
|
+
}
|
62
|
+
|
63
|
+
attributes :UserID, :AlternativeUserID, :UserName, :UserIsRequester
|
64
|
+
attributes :NetworkAccessPointID, :NetworkAccessPointTypeCode
|
65
|
+
|
66
|
+
class RoleIDCode < ATNA::Utils::XmlBuilder::Base
|
67
|
+
attributes :code, :codeSystem, :codeSystemName, :displayName, :originalText
|
68
|
+
end
|
69
|
+
|
70
|
+
children_order RoleIDCode
|
71
|
+
end
|
72
|
+
|
73
|
+
class AuditSourceIdentification < ATNA::Utils::XmlBuilder::Base
|
74
|
+
attributes :AuditEnterpriseSiteID, :AuditSourceID
|
75
|
+
|
76
|
+
class AuditSourceTypeCode < ATNA::Utils::XmlBuilder::Base
|
77
|
+
AUDIT_SOURCE_TYPE_CODE = {
|
78
|
+
"End-user display device, diagnostic display" => "1",
|
79
|
+
"Data acquisition device or instrument" => "2",
|
80
|
+
"Web server process" => "3",
|
81
|
+
"Application server process" => "4",
|
82
|
+
"Database server process" => "5",
|
83
|
+
"Security server, e.g., a domain controller" => "6",
|
84
|
+
"ISO level 1-3 network component" => "7",
|
85
|
+
"ISO level 4-6 operating software" => "8",
|
86
|
+
"External source, other or unknown type" => "9",
|
87
|
+
}
|
88
|
+
|
89
|
+
attributes :code, :codeSystem, :codeSystemName, :displayName, :originalText
|
90
|
+
end
|
91
|
+
|
92
|
+
children_order AuditSourceTypeCode
|
93
|
+
end
|
94
|
+
|
95
|
+
class ParticipantObjectIdentification < ATNA::Utils::XmlBuilder::Base
|
96
|
+
PARTICIPANT_OBJECT_ID_TYPE_CODE = {
|
97
|
+
"Medical Record Number" => "1",
|
98
|
+
"Patient Number" => "2",
|
99
|
+
"Encounter Number" => "3",
|
100
|
+
"Enrollee Number" => "4",
|
101
|
+
"Social Security Number" => "5",
|
102
|
+
"Account Number" => "6",
|
103
|
+
"Guarantor Number" => "7",
|
104
|
+
"Report Name" => "8",
|
105
|
+
"Report Number" => "9",
|
106
|
+
"Search Criteria" => "10",
|
107
|
+
"User Identifier" => "11",
|
108
|
+
"URI" => "12",
|
109
|
+
"" => "",
|
110
|
+
}
|
111
|
+
|
112
|
+
PARTICIPANT_OBJECT_TYPE_CODE = {
|
113
|
+
"Person" => 1,
|
114
|
+
"System object" => 2,
|
115
|
+
"Organization" => 3,
|
116
|
+
"Other" => 4,
|
117
|
+
}
|
118
|
+
|
119
|
+
PARTICIPANT_OBJECT_TYPE_CODE_ROLE = {
|
120
|
+
"Patient" => 1,
|
121
|
+
"Location" => 2,
|
122
|
+
"Report" => 3,
|
123
|
+
"Resource" => 4,
|
124
|
+
"Master file" => 5,
|
125
|
+
"User" => 6,
|
126
|
+
"List" => 7,
|
127
|
+
"Doctor" => 8,
|
128
|
+
"Subscriber" => 9,
|
129
|
+
"Guarantor" => 10,
|
130
|
+
"Security User Entity" => 11,
|
131
|
+
"Security User Group" => 12,
|
132
|
+
"Security Resource" => 13,
|
133
|
+
"Security Granualarity Definition" => 14,
|
134
|
+
"Provider" => 15,
|
135
|
+
"Report Destination" => 16,
|
136
|
+
"Report Library" => 17,
|
137
|
+
"Schedule" => 18,
|
138
|
+
"Customer" => 19,
|
139
|
+
"Job" => 20,
|
140
|
+
"Job Stream" => 21,
|
141
|
+
"Table" => 22,
|
142
|
+
"Routing Criteria" => 23,
|
143
|
+
"Query" => 24,
|
144
|
+
}
|
145
|
+
|
146
|
+
PARTICIPANT_OBJECT_DATA_LIFE_CYCLE = {
|
147
|
+
"Origination / Creation" => 1,
|
148
|
+
"Import / Copy from original" => 2,
|
149
|
+
"Amendment" => 3,
|
150
|
+
"Verification" => 4,
|
151
|
+
"Translation" => 5,
|
152
|
+
"Access / Use" => 6,
|
153
|
+
"De-identification" => 7,
|
154
|
+
"Aggregation, summarization, derivation" => 8,
|
155
|
+
"Report" => 9,
|
156
|
+
"Export / Copy to target" => 10,
|
157
|
+
"Disclosure" => 11,
|
158
|
+
"Receipt of disclosure" => 12,
|
159
|
+
"Archiving" => 13,
|
160
|
+
"Logical deletion" => 14,
|
161
|
+
"Permanent erasure / Physical destruction" => 15,
|
162
|
+
}
|
163
|
+
|
164
|
+
attributes :ParticipantObjectID, :ParticipantObjectTypeCode
|
165
|
+
attributes :ParticipantObjectTypeCodeRole, :ParticipantObjectDataLifeCycle
|
166
|
+
attributes :ParticipantObjectSensitivity
|
167
|
+
|
168
|
+
class ParticipantObjectIDTypeCode < ATNA::Utils::XmlBuilder::Base
|
169
|
+
attributes :code, :codeSystem, :codeSystemName, :displayName, :originalText
|
170
|
+
end
|
171
|
+
|
172
|
+
class ParticipantObjectName < ATNA::Utils::XmlBuilder::Base
|
173
|
+
end
|
174
|
+
|
175
|
+
class ParticipantObjectQuery < ATNA::Utils::XmlBuilder::Base
|
176
|
+
end
|
177
|
+
|
178
|
+
class ParticipantObjectDetail < ATNA::Utils::XmlBuilder::Base
|
179
|
+
attributes :type, :value
|
180
|
+
end
|
181
|
+
|
182
|
+
children_order ParticipantObjectIDTypeCode, ParticipantObjectName, ParticipantObjectQuery, ParticipantObjectDetail
|
183
|
+
end
|
184
|
+
|
185
|
+
children_order EventIdentification, ActiveParticipant, AuditSourceIdentification, ParticipantObjectIdentification
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
data/lib/atna/utils.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "atna/utils/xml_builder"
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module ATNA
|
3
|
+
module Utils
|
4
|
+
module XmlBuilder
|
5
|
+
class Base
|
6
|
+
def self.attributes(*names)
|
7
|
+
self.instance_eval do
|
8
|
+
@attribute_names ||= []
|
9
|
+
names.each do |name|
|
10
|
+
@attribute_names << name.to_s.to_sym
|
11
|
+
end
|
12
|
+
|
13
|
+
next @attribute_names.dup
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.children_order(*klasses)
|
18
|
+
self.instance_eval do
|
19
|
+
@children ||= []
|
20
|
+
klasses.each do |klass|
|
21
|
+
raise "Unkown Element class [#{klass}]" unless self.node_class.include?(klass)
|
22
|
+
@children << klass
|
23
|
+
end
|
24
|
+
|
25
|
+
next @children.dup
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.valid_attribute?(name)
|
30
|
+
attributes.include?(name.to_s.to_sym)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.node_class(string = false)
|
34
|
+
classes = self.constants.map { |c|
|
35
|
+
if eval("::#{self.name}::#{c}.kind_of?(Class)")
|
36
|
+
next eval("::#{self.name}::#{c} < ATNA::Utils::XmlBuilder::Base ? ::#{self.name}::#{c} : nil")
|
37
|
+
end
|
38
|
+
next nil
|
39
|
+
}.compact
|
40
|
+
classes.map! { |c| c.name.split("::").pop.to_s } if string
|
41
|
+
|
42
|
+
return classes
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.find_element_class(node_name)
|
46
|
+
unless idx = node_class(true).index(node_name)
|
47
|
+
raise "Unknown Element [#{node_name}]"
|
48
|
+
end
|
49
|
+
|
50
|
+
return node_class[idx]
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize(values = { })
|
54
|
+
@children = []
|
55
|
+
@attributes = self.class.attributes.inject({ }) { |h,n| h[n] = nil; next h }
|
56
|
+
|
57
|
+
values.each do |key, value|
|
58
|
+
case key
|
59
|
+
when Symbol # Attribute
|
60
|
+
if self.class.valid_attribute?(key)
|
61
|
+
@attributes[key] = value # TODO value class check
|
62
|
+
else
|
63
|
+
raise "Unknown attribute [#{key}]"
|
64
|
+
end
|
65
|
+
when String # Element
|
66
|
+
element_class = self.class.find_element_class(key)
|
67
|
+
|
68
|
+
case value
|
69
|
+
when Array
|
70
|
+
value.each do |v|
|
71
|
+
add_child(element_class.new(v))
|
72
|
+
end
|
73
|
+
when Hash
|
74
|
+
add_child(element_class.new(value))
|
75
|
+
end
|
76
|
+
else
|
77
|
+
raise "Unknown key [#{key.inspect}]"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Add children(element)
|
83
|
+
def <<(element)
|
84
|
+
@children << element
|
85
|
+
|
86
|
+
return self
|
87
|
+
end
|
88
|
+
|
89
|
+
alias_method :add_child, :<<
|
90
|
+
|
91
|
+
# Convert XML
|
92
|
+
#
|
93
|
+
# xml ::
|
94
|
+
def to_xml(xml = nil)
|
95
|
+
if xml
|
96
|
+
build_xml(xml)
|
97
|
+
return
|
98
|
+
else
|
99
|
+
builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
|
100
|
+
build_xml(xml)
|
101
|
+
end
|
102
|
+
|
103
|
+
return builder.doc.to_xml
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def element_name
|
108
|
+
self.class.name.split("::").last.to_sym
|
109
|
+
end
|
110
|
+
|
111
|
+
def sorted_children
|
112
|
+
children_order = self.class.children_order
|
113
|
+
@children.sort do |a,b|
|
114
|
+
children_order.index(a.class) <=> children_order.index(b.class)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Build xml by Nokogiri
|
119
|
+
def build_xml(xml)
|
120
|
+
xml.send(element_name, attributes) do
|
121
|
+
sorted_children.each do |element|
|
122
|
+
element.to_xml(xml)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
private :build_xml
|
127
|
+
|
128
|
+
# Delete nil attributes on copy
|
129
|
+
def attributes
|
130
|
+
@attributes.dup.delete_if { |k,v| v.nil? }
|
131
|
+
end
|
132
|
+
private :attributes
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/atna/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: atna
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tetsuhisa MAKINO
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- tim.makino@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- atna.gemspec
|
69
|
+
- lib/atna.rb
|
70
|
+
- lib/atna/logger.rb
|
71
|
+
- lib/atna/rfc3881.rb
|
72
|
+
- lib/atna/udp_sender.rb
|
73
|
+
- lib/atna/utils.rb
|
74
|
+
- lib/atna/utils/xml_builder.rb
|
75
|
+
- lib/atna/version.rb
|
76
|
+
homepage: ''
|
77
|
+
licenses:
|
78
|
+
- MIT
|
79
|
+
metadata: {}
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.2.2
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: IHE ITI ATNA Udp socket logger with RFC3881 Message builder.
|
100
|
+
test_files: []
|