diff options
Diffstat (limited to 'music-rest')
63 files changed, 12507 insertions, 0 deletions
diff --git a/music-rest/distribution/README.md b/music-rest/distribution/README.md new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/music-rest/distribution/README.md @@ -0,0 +1 @@ + diff --git a/music-rest/distribution/cassandra/Dockerfile b/music-rest/distribution/cassandra/Dockerfile new file mode 100644 index 00000000..fe13322c --- /dev/null +++ b/music-rest/distribution/cassandra/Dockerfile @@ -0,0 +1,4 @@ +#registry.hub.docker.com/ +FROM library/cassandra:3.11 +COPY cassandra.yaml /etc/cassandra/ +ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/music-rest/distribution/cassandra/cassandra.yaml b/music-rest/distribution/cassandra/cassandra.yaml new file mode 100644 index 00000000..fa7c74a6 --- /dev/null +++ b/music-rest/distribution/cassandra/cassandra.yaml @@ -0,0 +1,1002 @@ +# Cassandra storage config YAML + +# NOTE: +# See http://wiki.apache.org/cassandra/StorageConfiguration for +# full explanations of configuration directives +# /NOTE + +# The name of the cluster. This is mainly used to prevent machines in +# one logical cluster from joining another. +cluster_name: 'Test Cluster' + +# This defines the number of tokens randomly assigned to this node on the ring +# The more tokens, relative to other nodes, the larger the proportion of data +# that this node will store. You probably want all nodes to have the same number +# of tokens assuming they have equal hardware capability. +# +# If you leave this unspecified, Cassandra will use the default of 1 token for legacy compatibility, +# and will use the initial_token as described below. +# +# Specifying initial_token will override this setting on the node's initial start, +# on subsequent starts, this setting will apply even if initial token is set. +# +# If you already have a cluster with 1 token per node, and wish to migrate to +# multiple tokens per node, see http://wiki.apache.org/cassandra/Operations +num_tokens: 256 + +# Triggers automatic allocation of num_tokens tokens for this node. The allocation +# algorithm attempts to choose tokens in a way that optimizes replicated load over +# the nodes in the datacenter for the replication strategy used by the specified +# keyspace. +# +# The load assigned to each node will be close to proportional to its number of +# vnodes. +# +# Only supported with the Murmur3Partitioner. +# allocate_tokens_for_keyspace: KEYSPACE + +# initial_token allows you to specify tokens manually. While you can use # it with +# vnodes (num_tokens > 1, above) -- in which case you should provide a +# comma-separated list -- it's primarily used when adding nodes # to legacy clusters +# that do not have vnodes enabled. +# initial_token: + +# See http://wiki.apache.org/cassandra/HintedHandoff +# May either be "true" or "false" to enable globally +hinted_handoff_enabled: true +# When hinted_handoff_enabled is true, a black list of data centers that will not +# perform hinted handoff +#hinted_handoff_disabled_datacenters: +# - DC1 +# - DC2 +# this defines the maximum amount of time a dead host will have hints +# generated. After it has been dead this long, new hints for it will not be +# created until it has been seen alive and gone down again. +max_hint_window_in_ms: 10800000 # 3 hours + +# Maximum throttle in KBs per second, per delivery thread. This will be +# reduced proportionally to the number of nodes in the cluster. (If there +# are two nodes in the cluster, each delivery thread will use the maximum +# rate; if there are three, each will throttle to half of the maximum, +# since we expect two nodes to be delivering hints simultaneously.) +hinted_handoff_throttle_in_kb: 1024 + +# Number of threads with which to deliver hints; +# Consider increasing this number when you have multi-dc deployments, since +# cross-dc handoff tends to be slower +max_hints_delivery_threads: 2 + +# Directory where Cassandra should store hints. +# If not set, the default directory is $CASSANDRA_HOME/data/hints. +# hints_directory: /var/lib/cassandra/hints + +# How often hints should be flushed from the internal buffers to disk. +# Will *not* trigger fsync. +hints_flush_period_in_ms: 10000 + +# Maximum size for a single hints file, in megabytes. +max_hints_file_size_in_mb: 128 + +# Compression to apply to the hint files. If omitted, hints files +# will be written uncompressed. LZ4, Snappy, and Deflate compressors +# are supported. +#hints_compression: +# - class_name: LZ4Compressor +# parameters: +# - + +# Maximum throttle in KBs per second, total. This will be +# reduced proportionally to the number of nodes in the cluster. +batchlog_replay_throttle_in_kb: 1024 + +# Authentication backend, implementing IAuthenticator; used to identify users +# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthenticator, +# PasswordAuthenticator}. +# +# - AllowAllAuthenticator performs no checks - set it to disable authentication. +# - PasswordAuthenticator relies on username/password pairs to authenticate +# users. It keeps usernames and hashed passwords in system_auth.roles table. +# Please increase system_auth keyspace replication factor if you use this authenticator. +# If using PasswordAuthenticator, CassandraRoleManager must also be used (see below) +authenticator: PasswordAuthenticator + +# Authorization backend, implementing IAuthorizer; used to limit access/provide permissions +# Out of the box, Cassandra provides org.apache.cassandra.auth.{AllowAllAuthorizer, +# CassandraAuthorizer}. +# +# - AllowAllAuthorizer allows any action to any user - set it to disable authorization. +# - CassandraAuthorizer stores permissions in system_auth.role_permissions table. Please +# increase system_auth keyspace replication factor if you use this authorizer. +authorizer: CassandraAuthorizer + +# Part of the Authentication & Authorization backend, implementing IRoleManager; used +# to maintain grants and memberships between roles. +# Out of the box, Cassandra provides org.apache.cassandra.auth.CassandraRoleManager, +# which stores role information in the system_auth keyspace. Most functions of the +# IRoleManager require an authenticated login, so unless the configured IAuthenticator +# actually implements authentication, most of this functionality will be unavailable. +# +# - CassandraRoleManager stores role data in the system_auth keyspace. Please +# increase system_auth keyspace replication factor if you use this role manager. +role_manager: CassandraRoleManager + +# Validity period for roles cache (fetching permissions can be an +# expensive operation depending on the authorizer). Granted roles are cached for +# authenticated sessions in AuthenticatedUser and after the period specified +# here, become eligible for (async) reload. +# Defaults to 2000, set to 0 to disable. +# Will be disabled automatically for AllowAllAuthenticator. +roles_validity_in_ms: 2000 + +# Refresh interval for roles cache (if enabled). +# After this interval, cache entries become eligible for refresh. Upon next +# access, an async reload is scheduled and the old value returned until it +# completes. If roles_validity_in_ms is non-zero, then this must be +# also. +# Defaults to the same value as roles_validity_in_ms. +# roles_update_interval_in_ms: 1000 + +# Validity period for permissions cache (fetching permissions can be an +# expensive operation depending on the authorizer, CassandraAuthorizer is +# one example). Defaults to 2000, set to 0 to disable. +# Will be disabled automatically for AllowAllAuthorizer. +permissions_validity_in_ms: 2000 + +# Refresh interval for permissions cache (if enabled). +# After this interval, cache entries become eligible for refresh. Upon next +# access, an async reload is scheduled and the old value returned until it +# completes. If permissions_validity_in_ms is non-zero, then this must be +# also. +# Defaults to the same value as permissions_validity_in_ms. +# permissions_update_interval_in_ms: 1000 + +# The partitioner is responsible for distributing groups of rows (by +# partition key) across nodes in the cluster. You should leave this +# alone for new clusters. The partitioner can NOT be changed without +# reloading all data, so when upgrading you should set this to the +# same partitioner you were already using. +# +# Besides Murmur3Partitioner, partitioners included for backwards +# compatibility include RandomPartitioner, ByteOrderedPartitioner, and +# OrderPreservingPartitioner. +# +partitioner: org.apache.cassandra.dht.Murmur3Partitioner + +# Directories where Cassandra should store data on disk. Cassandra +# will spread data evenly across them, subject to the granularity of +# the configured compaction strategy. +# If not set, the default directory is $CASSANDRA_HOME/data/data. +data_file_directories: + - /var/lib/cassandra/data + +# commit log. when running on magnetic HDD, this should be a +# separate spindle than the data directories. +# If not set, the default directory is $CASSANDRA_HOME/data/commitlog. +commitlog_directory: /var/lib/cassandra/commitlog + +# policy for data disk failures: +# die: shut down gossip and client transports and kill the JVM for any fs errors or +# single-sstable errors, so the node can be replaced. +# stop_paranoid: shut down gossip and client transports even for single-sstable errors, +# kill the JVM for errors during startup. +# stop: shut down gossip and client transports, leaving the node effectively dead, but +# can still be inspected via JMX, kill the JVM for errors during startup. +# best_effort: stop using the failed disk and respond to requests based on +# remaining available sstables. This means you WILL see obsolete +# data at CL.ONE! +# ignore: ignore fatal errors and let requests fail, as in pre-1.2 Cassandra +disk_failure_policy: stop + +# policy for commit disk failures: +# die: shut down gossip and Thrift and kill the JVM, so the node can be replaced. +# stop: shut down gossip and Thrift, leaving the node effectively dead, but +# can still be inspected via JMX. +# stop_commit: shutdown the commit log, letting writes collect but +# continuing to service reads, as in pre-2.0.5 Cassandra +# ignore: ignore fatal errors and let the batches fail +commit_failure_policy: stop + +# Maximum size of the key cache in memory. +# +# Each key cache hit saves 1 seek and each row cache hit saves 2 seeks at the +# minimum, sometimes more. The key cache is fairly tiny for the amount of +# time it saves, so it's worthwhile to use it at large numbers. +# The row cache saves even more time, but must contain the entire row, +# so it is extremely space-intensive. It's best to only use the +# row cache if you have hot rows or static rows. +# +# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup. +# +# Default value is empty to make it "auto" (min(5% of Heap (in MB), 100MB)). Set to 0 to disable key cache. +key_cache_size_in_mb: + +# Duration in seconds after which Cassandra should +# save the key cache. Caches are saved to saved_caches_directory as +# specified in this configuration file. +# +# Saved caches greatly improve cold-start speeds, and is relatively cheap in +# terms of I/O for the key cache. Row cache saving is much more expensive and +# has limited use. +# +# Default is 14400 or 4 hours. +key_cache_save_period: 14400 + +# Number of keys from the key cache to save +# Disabled by default, meaning all keys are going to be saved +# key_cache_keys_to_save: 100 + +# Row cache implementation class name. +# Available implementations: +# org.apache.cassandra.cache.OHCProvider Fully off-heap row cache implementation (default). +# org.apache.cassandra.cache.SerializingCacheProvider This is the row cache implementation availabile +# in previous releases of Cassandra. +# row_cache_class_name: org.apache.cassandra.cache.OHCProvider + +# Maximum size of the row cache in memory. +# Please note that OHC cache implementation requires some additional off-heap memory to manage +# the map structures and some in-flight memory during operations before/after cache entries can be +# accounted against the cache capacity. This overhead is usually small compared to the whole capacity. +# Do not specify more memory that the system can afford in the worst usual situation and leave some +# headroom for OS block level cache. Do never allow your system to swap. +# +# Default value is 0, to disable row caching. +row_cache_size_in_mb: 0 + +# Duration in seconds after which Cassandra should save the row cache. +# Caches are saved to saved_caches_directory as specified in this configuration file. +# +# Saved caches greatly improve cold-start speeds, and is relatively cheap in +# terms of I/O for the key cache. Row cache saving is much more expensive and +# has limited use. +# +# Default is 0 to disable saving the row cache. +row_cache_save_period: 0 + +# Number of keys from the row cache to save. +# Specify 0 (which is the default), meaning all keys are going to be saved +# row_cache_keys_to_save: 100 + +# Maximum size of the counter cache in memory. +# +# Counter cache helps to reduce counter locks' contention for hot counter cells. +# In case of RF = 1 a counter cache hit will cause Cassandra to skip the read before +# write entirely. With RF > 1 a counter cache hit will still help to reduce the duration +# of the lock hold, helping with hot counter cell updates, but will not allow skipping +# the read entirely. Only the local (clock, count) tuple of a counter cell is kept +# in memory, not the whole counter, so it's relatively cheap. +# +# NOTE: if you reduce the size, you may not get you hottest keys loaded on startup. +# +# Default value is empty to make it "auto" (min(2.5% of Heap (in MB), 50MB)). Set to 0 to disable counter cache. +# NOTE: if you perform counter deletes and rely on low gcgs, you should disable the counter cache. +counter_cache_size_in_mb: + +# Duration in seconds after which Cassandra should +# save the counter cache (keys only). Caches are saved to saved_caches_directory as +# specified in this configuration file. +# +# Default is 7200 or 2 hours. +counter_cache_save_period: 7200 + +# Number of keys from the counter cache to save +# Disabled by default, meaning all keys are going to be saved +# counter_cache_keys_to_save: 100 + +# saved caches +# If not set, the default directory is $CASSANDRA_HOME/data/saved_caches. +saved_caches_directory: /var/lib/cassandra/saved_caches + +# commitlog_sync may be either "periodic" or "batch." +# +# When in batch mode, Cassandra won't ack writes until the commit log +# has been fsynced to disk. It will wait +# commitlog_sync_batch_window_in_ms milliseconds between fsyncs. +# This window should be kept short because the writer threads will +# be unable to do extra work while waiting. (You may need to increase +# concurrent_writes for the same reason.) +# +# commitlog_sync: batch +# commitlog_sync_batch_window_in_ms: 2 +# +# the other option is "periodic" where writes may be acked immediately +# and the CommitLog is simply synced every commitlog_sync_period_in_ms +# milliseconds. +commitlog_sync: periodic +commitlog_sync_period_in_ms: 10000 + +# The size of the individual commitlog file segments. A commitlog +# segment may be archived, deleted, or recycled once all the data +# in it (potentially from each columnfamily in the system) has been +# flushed to sstables. +# +# The default size is 32, which is almost always fine, but if you are +# archiving commitlog segments (see commitlog_archiving.properties), +# then you probably want a finer granularity of archiving; 8 or 16 MB +# is reasonable. +# Max mutation size is also configurable via max_mutation_size_in_kb setting in +# cassandra.yaml. The default is half the size commitlog_segment_size_in_mb * 1024. +# This should be positive and less than 2048. +# +# NOTE: If max_mutation_size_in_kb is set explicitly then commitlog_segment_size_in_mb must +# be set to at least twice the size of max_mutation_size_in_kb / 1024 +# +commitlog_segment_size_in_mb: 32 + +# Compression to apply to the commit log. If omitted, the commit log +# will be written uncompressed. LZ4, Snappy, and Deflate compressors +# are supported. +#commitlog_compression: +# - class_name: LZ4Compressor +# parameters: +# - + +# any class that implements the SeedProvider interface and has a +# constructor that takes a Map<String, String> of parameters will do. +seed_provider: + # Addresses of hosts that are deemed contact points. + # Cassandra nodes use this list of hosts to find each other and learn + # the topology of the ring. You must change this if you are running + # multiple nodes! + - class_name: org.apache.cassandra.locator.SimpleSeedProvider + parameters: + # seeds is actually a comma-delimited list of addresses. + # Ex: "<ip1>,<ip2>,<ip3>" + - seeds: "127.0.0.1" + +# For workloads with more data than can fit in memory, Cassandra's +# bottleneck will be reads that need to fetch data from +# disk. "concurrent_reads" should be set to (16 * number_of_drives) in +# order to allow the operations to enqueue low enough in the stack +# that the OS and drives can reorder them. Same applies to +# "concurrent_counter_writes", since counter writes read the current +# values before incrementing and writing them back. +# +# On the other hand, since writes are almost never IO bound, the ideal +# number of "concurrent_writes" is dependent on the number of cores in +# your system; (8 * number_of_cores) is a good rule of thumb. +concurrent_reads: 32 +concurrent_writes: 32 +concurrent_counter_writes: 32 + +# For materialized view writes, as there is a read involved, so this should +# be limited by the less of concurrent reads or concurrent writes. +concurrent_materialized_view_writes: 32 + +# Maximum memory to use for pooling sstable buffers. Defaults to the smaller +# of 1/4 of heap or 512MB. This pool is allocated off-heap, so is in addition +# to the memory allocated for heap. Memory is only allocated as needed. +# file_cache_size_in_mb: 512 + +# Flag indicating whether to allocate on or off heap when the sstable buffer +# pool is exhausted, that is when it has exceeded the maximum memory +# file_cache_size_in_mb, beyond which it will not cache buffers but allocate on request. + +# buffer_pool_use_heap_if_exhausted: true + +# The strategy for optimizing disk read +# Possible values are: +# ssd (for solid state disks, the default) +# spinning (for spinning disks) +# disk_optimization_strategy: ssd + +# Total permitted memory to use for memtables. Cassandra will stop +# accepting writes when the limit is exceeded until a flush completes, +# and will trigger a flush based on memtable_cleanup_threshold +# If omitted, Cassandra will set both to 1/4 the size of the heap. +# memtable_heap_space_in_mb: 2048 +# memtable_offheap_space_in_mb: 2048 + +# Ratio of occupied non-flushing memtable size to total permitted size +# that will trigger a flush of the largest memtable. Larger mct will +# mean larger flushes and hence less compaction, but also less concurrent +# flush activity which can make it difficult to keep your disks fed +# under heavy write load. +# +# memtable_cleanup_threshold defaults to 1 / (memtable_flush_writers + 1) +# memtable_cleanup_threshold: 0.11 + +# Specify the way Cassandra allocates and manages memtable memory. +# Options are: +# heap_buffers: on heap nio buffers +# +# Note: offheap_buffers are not supported in Cassandra 3.0 - 3.3. +# They have been re-introduced in Cassandra 3.4. For details see +# https://issues.apache.org/jira/browse/CASSANDRA-9472 and +# https://issues.apache.org/jira/browse/CASSANDRA-11039 +memtable_allocation_type: heap_buffers + +# Total space to use for commit logs on disk. +# +# If space gets above this value, Cassandra will flush every dirty CF +# in the oldest segment and remove it. So a small total commitlog space +# will tend to cause more flush activity on less-active columnfamilies. +# +# The default value is the smaller of 8192, and 1/4 of the total space +# of the commitlog volume. +# +# commitlog_total_space_in_mb: 8192 + +# This sets the amount of memtable flush writer threads. These will +# be blocked by disk io, and each one will hold a memtable in memory +# while blocked. +# +# memtable_flush_writers defaults to the smaller of (number of disks, +# number of cores), with a minimum of 2 and a maximum of 8. +# +# If your data directories are backed by SSD, you should increase this +# to the number of cores. +#memtable_flush_writers: 8 + +# A fixed memory pool size in MB for for SSTable index summaries. If left +# empty, this will default to 5% of the heap size. If the memory usage of +# all index summaries exceeds this limit, SSTables with low read rates will +# shrink their index summaries in order to meet this limit. However, this +# is a best-effort process. In extreme conditions Cassandra may need to use +# more than this amount of memory. +index_summary_capacity_in_mb: + +# How frequently index summaries should be resampled. This is done +# periodically to redistribute memory from the fixed-size pool to sstables +# proportional their recent read rates. Setting to -1 will disable this +# process, leaving existing index summaries at their current sampling level. +index_summary_resize_interval_in_minutes: 60 + +# Whether to, when doing sequential writing, fsync() at intervals in +# order to force the operating system to flush the dirty +# buffers. Enable this to avoid sudden dirty buffer flushing from +# impacting read latencies. Almost always a good idea on SSDs; not +# necessarily on platters. +trickle_fsync: false +trickle_fsync_interval_in_kb: 10240 + +# TCP port, for commands and data +# For security reasons, you should not expose this port to the internet. Firewall it if needed. +storage_port: 7000 + +# SSL port, for encrypted communication. Unused unless enabled in +# encryption_options +# For security reasons, you should not expose this port to the internet. Firewall it if needed. +ssl_storage_port: 7001 + +# Address or interface to bind to and tell other Cassandra nodes to connect to. +# You _must_ change this if you want multiple nodes to be able to communicate! +# +# Set listen_address OR listen_interface, not both. Interfaces must correspond +# to a single address, IP aliasing is not supported. +# +# Leaving it blank leaves it up to InetAddress.getLocalHost(). This +# will always do the Right Thing _if_ the node is properly configured +# (hostname, name resolution, etc), and the Right Thing is to use the +# address associated with the hostname (it might not be). +# +# Setting listen_address to 0.0.0.0 is always wrong. +# +# If you choose to specify the interface by name and the interface has an ipv4 and an ipv6 address +# you can specify which should be chosen using listen_interface_prefer_ipv6. If false the first ipv4 +# address will be used. If true the first ipv6 address will be used. Defaults to false preferring +# ipv4. If there is only one address it will be selected regardless of ipv4/ipv6. +listen_address: localhost +# listen_interface: eth0 +# listen_interface_prefer_ipv6: false + +# Address to broadcast to other Cassandra nodes +# Leaving this blank will set it to the same value as listen_address +# broadcast_address: 1.2.3.4 + +# When using multiple physical network interfaces, set this +# to true to listen on broadcast_address in addition to +# the listen_address, allowing nodes to communicate in both +# interfaces. +# Ignore this property if the network configuration automatically +# routes between the public and private networks such as EC2. +# listen_on_broadcast_address: false + +# Internode authentication backend, implementing IInternodeAuthenticator; +# used to allow/disallow connections from peer nodes. +# internode_authenticator: org.apache.cassandra.auth.AllowAllInternodeAuthenticator + +# Whether to start the native transport server. +# Please note that the address on which the native transport is bound is the +# same as the rpc_address. The port however is different and specified below. +start_native_transport: true +# port for the CQL native transport to listen for clients on +# For security reasons, you should not expose this port to the internet. Firewall it if needed. +native_transport_port: 9042 +# Enabling native transport encryption in client_encryption_options allows you to either use +# encryption for the standard port or to use a dedicated, additional port along with the unencrypted +# standard native_transport_port. +# Enabling client encryption and keeping native_transport_port_ssl disabled will use encryption +# for native_transport_port. Setting native_transport_port_ssl to a different value +# from native_transport_port will use encryption for native_transport_port_ssl while +# keeping native_transport_port unencrypted. +# native_transport_port_ssl: 9142 +# The maximum threads for handling requests when the native transport is used. +# This is similar to rpc_max_threads though the default differs slightly (and +# there is no native_transport_min_threads, idle threads will always be stopped +# after 30 seconds). +# native_transport_max_threads: 128 +# +# The maximum size of allowed frame. Frame (requests) larger than this will +# be rejected as invalid. The default is 256MB. If you're changing this parameter, +# you may want to adjust max_value_size_in_mb accordingly. This should be positive and less than 2048. +# native_transport_max_frame_size_in_mb: 256 + +# The maximum number of concurrent client connections. +# The default is -1, which means unlimited. +# native_transport_max_concurrent_connections: -1 + +# The maximum number of concurrent client connections per source ip. +# The default is -1, which means unlimited. +# native_transport_max_concurrent_connections_per_ip: -1 + +# Whether to start the thrift rpc server. +#start_rpc: false +start_rpc: true + +# The address or interface to bind the Thrift RPC service and native transport +# server to. +# +# Set rpc_address OR rpc_interface, not both. Interfaces must correspond +# to a single address, IP aliasing is not supported. +# +# Leaving rpc_address blank has the same effect as on listen_address +# (i.e. it will be based on the configured hostname of the node). +# +# Note that unlike listen_address, you can specify 0.0.0.0, but you must also +# set broadcast_rpc_address to a value other than 0.0.0.0. +# +# For security reasons, you should not expose this port to the internet. Firewall it if needed. +# +# If you choose to specify the interface by name and the interface has an ipv4 and an ipv6 address +# you can specify which should be chosen using rpc_interface_prefer_ipv6. If false the first ipv4 +# address will be used. If true the first ipv6 address will be used. Defaults to false preferring +# ipv4. If there is only one address it will be selected regardless of ipv4/ipv6. +rpc_address: localhost +# rpc_interface: eth1 +# rpc_interface_prefer_ipv6: false + +# port for Thrift to listen for clients on +rpc_port: 9160 + +# RPC address to broadcast to drivers and other Cassandra nodes. This cannot +# be set to 0.0.0.0. If left blank, this will be set to the value of +# rpc_address. If rpc_address is set to 0.0.0.0, broadcast_rpc_address must +# be set. +# broadcast_rpc_address: 1.2.3.4 + +# enable or disable keepalive on rpc/native connections +rpc_keepalive: true + +# Cassandra provides two out-of-the-box options for the RPC Server: +# +# sync -> One thread per thrift connection. For a very large number of clients, memory +# will be your limiting factor. On a 64 bit JVM, 180KB is the minimum stack size +# per thread, and that will correspond to your use of virtual memory (but physical memory +# may be limited depending on use of stack space). +# +# hsha -> Stands for "half synchronous, half asynchronous." All thrift clients are handled +# asynchronously using a small number of threads that does not vary with the amount +# of thrift clients (and thus scales well to many clients). The rpc requests are still +# synchronous (one thread per active request). If hsha is selected then it is essential +# that rpc_max_threads is changed from the default value of unlimited. +# +# The default is sync because on Windows hsha is about 30% slower. On Linux, +# sync/hsha performance is about the same, with hsha of course using less memory. +# +# Alternatively, can provide your own RPC server by providing the fully-qualified class name +# of an o.a.c.t.TServerFactory that can create an instance of it. +rpc_server_type: sync + +# Uncomment rpc_min|max_thread to set request pool size limits. +# +# Regardless of your choice of RPC server (see above), the number of maximum requests in the +# RPC thread pool dictates how many concurrent requests are possible (but if you are using the sync +# RPC server, it also dictates the number of clients that can be connected at all). +# +# The default is unlimited and thus provides no protection against clients overwhelming the server. You are +# encouraged to set a maximum that makes sense for you in production, but do keep in mind that +# rpc_max_threads represents the maximum number of client requests this server may execute concurrently. +# +# rpc_min_threads: 16 +# rpc_max_threads: 2048 + +# uncomment to set socket buffer sizes on rpc connections +# rpc_send_buff_size_in_bytes: +# rpc_recv_buff_size_in_bytes: + +# Uncomment to set socket buffer size for internode communication +# Note that when setting this, the buffer size is limited by net.core.wmem_max +# and when not setting it it is defined by net.ipv4.tcp_wmem +# See: +# /proc/sys/net/core/wmem_max +# /proc/sys/net/core/rmem_max +# /proc/sys/net/ipv4/tcp_wmem +# /proc/sys/net/ipv4/tcp_wmem +# and: man tcp +# internode_send_buff_size_in_bytes: +# internode_recv_buff_size_in_bytes: + +# Frame size for thrift (maximum message length). +thrift_framed_transport_size_in_mb: 15 + +# Set to true to have Cassandra create a hard link to each sstable +# flushed or streamed locally in a backups/ subdirectory of the +# keyspace data. Removing these links is the operator's +# responsibility. +incremental_backups: false + +# Whether or not to take a snapshot before each compaction. Be +# careful using this option, since Cassandra won't clean up the +# snapshots for you. Mostly useful if you're paranoid when there +# is a data format change. +snapshot_before_compaction: false + +# Whether or not a snapshot is taken of the data before keyspace truncation +# or dropping of column families. The STRONGLY advised default of true +# should be used to provide data safety. If you set this flag to false, you will +# lose data on truncation or drop. +auto_snapshot: true + +# When executing a scan, within or across a partition, we need to keep the +# tombstones seen in memory so we can return them to the coordinator, which +# will use them to make sure other replicas also know about the deleted rows. +# With workloads that generate a lot of tombstones, this can cause performance +# problems and even exaust the server heap. +# (http://www.datastax.com/dev/blog/cassandra-anti-patterns-queues-and-queue-like-datasets) +# Adjust the thresholds here if you understand the dangers and want to +# scan more tombstones anyway. These thresholds may also be adjusted at runtime +# using the StorageService mbean. +tombstone_warn_threshold: 1000 +tombstone_failure_threshold: 100000 + +# Granularity of the collation index of rows within a partition. +# Increase if your rows are large, or if you have a very large +# number of rows per partition. The competing goals are these: +# 1) a smaller granularity means more index entries are generated +# and looking up rows withing the partition by collation column +# is faster +# 2) but, Cassandra will keep the collation index in memory for hot +# rows (as part of the key cache), so a larger granularity means +# you can cache more hot rows +column_index_size_in_kb: 64 + + +# Log WARN on any batch size exceeding this value. 5kb per batch by default. +# Caution should be taken on increasing the size of this threshold as it can lead to node instability. +batch_size_warn_threshold_in_kb: 5 + +# Fail any batch exceeding this value. 50kb (10x warn threshold) by default. +batch_size_fail_threshold_in_kb: 50 + +# Log WARN on any batches not of type LOGGED than span across more partitions than this limit +unlogged_batch_across_partitions_warn_threshold: 10 + +# Number of simultaneous compactions to allow, NOT including +# validation "compactions" for anti-entropy repair. Simultaneous +# compactions can help preserve read performance in a mixed read/write +# workload, by mitigating the tendency of small sstables to accumulate +# during a single long running compactions. The default is usually +# fine and if you experience problems with compaction running too +# slowly or too fast, you should look at +# compaction_throughput_mb_per_sec first. +# +# concurrent_compactors defaults to the smaller of (number of disks, +# number of cores), with a minimum of 2 and a maximum of 8. +# +# If your data directories are backed by SSD, you should increase this +# to the number of cores. +#concurrent_compactors: 1 + +# Throttles compaction to the given total throughput across the entire +# system. The faster you insert data, the faster you need to compact in +# order to keep the sstable count down, but in general, setting this to +# 16 to 32 times the rate you are inserting data is more than sufficient. +# Setting this to 0 disables throttling. Note that this account for all types +# of compaction, including validation compaction. +compaction_throughput_mb_per_sec: 16 + +# Log a warning when compacting partitions larger than this value +compaction_large_partition_warning_threshold_mb: 100 + +# When compacting, the replacement sstable(s) can be opened before they +# are completely written, and used in place of the prior sstables for +# any range that has been written. This helps to smoothly transfer reads +# between the sstables, reducing page cache churn and keeping hot rows hot +sstable_preemptive_open_interval_in_mb: 50 + +# Throttles all outbound streaming file transfers on this node to the +# given total throughput in Mbps. This is necessary because Cassandra does +# mostly sequential IO when streaming data during bootstrap or repair, which +# can lead to saturating the network connection and degrading rpc performance. +# When unset, the default is 200 Mbps or 25 MB/s. +# stream_throughput_outbound_megabits_per_sec: 200 + +# Throttles all streaming file transfer between the datacenters, +# this setting allows users to throttle inter dc stream throughput in addition +# to throttling all network stream traffic as configured with +# stream_throughput_outbound_megabits_per_sec +# When unset, the default is 200 Mbps or 25 MB/s +# inter_dc_stream_throughput_outbound_megabits_per_sec: 200 + +# How long the coordinator should wait for read operations to complete +read_request_timeout_in_ms: 5000 +# How long the coordinator should wait for seq or index scans to complete +range_request_timeout_in_ms: 15000 +# How long the coordinator should wait for writes to complete +write_request_timeout_in_ms: 2000 +# How long the coordinator should wait for counter writes to complete +counter_write_request_timeout_in_ms: 5000 +# How long a coordinator should continue to retry a CAS operation +# that contends with other proposals for the same row +cas_contention_timeout_in_ms: 1000 +# How long the coordinator should wait for truncates to complete +# (This can be much longer, because unless auto_snapshot is disabled +# we need to flush first so we can snapshot before removing the data.) +truncate_request_timeout_in_ms: 60000 +# The default timeout for other, miscellaneous operations +request_timeout_in_ms: 10000 + +# Enable operation timeout information exchange between nodes to accurately +# measure request timeouts. If disabled, replicas will assume that requests +# were forwarded to them instantly by the coordinator, which means that +# under overload conditions we will waste that much extra time processing +# already-timed-out requests. +# +# Warning: before enabling this property make sure to ntp is installed +# and the times are synchronized between the nodes. +cross_node_timeout: false + +# Set socket timeout for streaming operation. +# The stream session is failed if no data/ack is received by any of the participants +# within that period, which means this should also be sufficient to stream a large +# sstable or rebuild table indexes. +# Default value is 86400000ms, which means stale streams timeout after 24 hours. +# A value of zero means stream sockets should never time out. +# streaming_socket_timeout_in_ms: 86400000 + +# phi value that must be reached for a host to be marked down. +# most users should never need to adjust this. +# phi_convict_threshold: 8 + +# endpoint_snitch -- Set this to a class that implements +# IEndpointSnitch. The snitch has two functions: +# - it teaches Cassandra enough about your network topology to route +# requests efficiently +# - it allows Cassandra to spread replicas around your cluster to avoid +# correlated failures. It does this by grouping machines into +# "datacenters" and "racks." Cassandra will do its best not to have +# more than one replica on the same "rack" (which may not actually +# be a physical location) +# +# CASSANDRA WILL NOT ALLOW YOU TO SWITCH TO AN INCOMPATIBLE SNITCH +# ONCE DATA IS INSERTED INTO THE CLUSTER. This would cause data loss. +# This means that if you start with the default SimpleSnitch, which +# locates every node on "rack1" in "datacenter1", your only options +# if you need to add another datacenter are GossipingPropertyFileSnitch +# (and the older PFS). From there, if you want to migrate to an +# incompatible snitch like Ec2Snitch you can do it by adding new nodes +# under Ec2Snitch (which will locate them in a new "datacenter") and +# decommissioning the old ones. +# +# Out of the box, Cassandra provides +# - SimpleSnitch: +# Treats Strategy order as proximity. This can improve cache +# locality when disabling read repair. Only appropriate for +# single-datacenter deployments. +# - GossipingPropertyFileSnitch +# This should be your go-to snitch for production use. The rack +# and datacenter for the local node are defined in +# cassandra-rackdc.properties and propagated to other nodes via +# gossip. If cassandra-topology.properties exists, it is used as a +# fallback, allowing migration from the PropertyFileSnitch. +# - PropertyFileSnitch: +# Proximity is determined by rack and data center, which are +# explicitly configured in cassandra-topology.properties. +# - Ec2Snitch: +# Appropriate for EC2 deployments in a single Region. Loads Region +# and Availability Zone information from the EC2 API. The Region is +# treated as the datacenter, and the Availability Zone as the rack. +# Only private IPs are used, so this will not work across multiple +# Regions. +# - Ec2MultiRegionSnitch: +# Uses public IPs as broadcast_address to allow cross-region +# connectivity. (Thus, you should set seed addresses to the public +# IP as well.) You will need to open the storage_port or +# ssl_storage_port on the public IP firewall. (For intra-Region +# traffic, Cassandra will switch to the private IP after +# establishing a connection.) +# - RackInferringSnitch: +# Proximity is determined by rack and data center, which are +# assumed to correspond to the 3rd and 2nd octet of each node's IP +# address, respectively. Unless this happens to match your +# deployment conventions, this is best used as an example of +# writing a custom Snitch class and is provided in that spirit. +# +# You can use a custom Snitch by setting this to the full class name +# of the snitch, which will be assumed to be on your classpath. +endpoint_snitch: SimpleSnitch + +# controls how often to perform the more expensive part of host score +# calculation +dynamic_snitch_update_interval_in_ms: 100 +# controls how often to reset all host scores, allowing a bad host to +# possibly recover +dynamic_snitch_reset_interval_in_ms: 600000 +# if set greater than zero and read_repair_chance is < 1.0, this will allow +# 'pinning' of replicas to hosts in order to increase cache capacity. +# The badness threshold will control how much worse the pinned host has to be +# before the dynamic snitch will prefer other replicas over it. This is +# expressed as a double which represents a percentage. Thus, a value of +# 0.2 means Cassandra would continue to prefer the static snitch values +# until the pinned host was 20% worse than the fastest. +dynamic_snitch_badness_threshold: 0.1 + +# request_scheduler -- Set this to a class that implements +# RequestScheduler, which will schedule incoming client requests +# according to the specific policy. This is useful for multi-tenancy +# with a single Cassandra cluster. +# NOTE: This is specifically for requests from the client and does +# not affect inter node communication. +# org.apache.cassandra.scheduler.NoScheduler - No scheduling takes place +# org.apache.cassandra.scheduler.RoundRobinScheduler - Round robin of +# client requests to a node with a separate queue for each +# request_scheduler_id. The scheduler is further customized by +# request_scheduler_options as described below. +request_scheduler: org.apache.cassandra.scheduler.NoScheduler + +# Scheduler Options vary based on the type of scheduler +# NoScheduler - Has no options +# RoundRobin +# - throttle_limit -- The throttle_limit is the number of in-flight +# requests per client. Requests beyond +# that limit are queued up until +# running requests can complete. +# The value of 80 here is twice the number of +# concurrent_reads + concurrent_writes. +# - default_weight -- default_weight is optional and allows for +# overriding the default which is 1. +# - weights -- Weights are optional and will default to 1 or the +# overridden default_weight. The weight translates into how +# many requests are handled during each turn of the +# RoundRobin, based on the scheduler id. +# +# request_scheduler_options: +# throttle_limit: 80 +# default_weight: 5 +# weights: +# Keyspace1: 1 +# Keyspace2: 5 + +# request_scheduler_id -- An identifier based on which to perform +# the request scheduling. Currently the only valid option is keyspace. +# request_scheduler_id: keyspace + +# Enable or disable inter-node encryption +# Default settings are TLS v1, RSA 1024-bit keys (it is imperative that +# users generate their own keys) TLS_RSA_WITH_AES_128_CBC_SHA as the cipher +# suite for authentication, key exchange and encryption of the actual data transfers. +# Use the DHE/ECDHE ciphers if running in FIPS 140 compliant mode. +# NOTE: No custom encryption options are enabled at the moment +# The available internode options are : all, none, dc, rack +# +# If set to dc cassandra will encrypt the traffic between the DCs +# If set to rack cassandra will encrypt the traffic between the racks +# +# The passwords used in these options must match the passwords used when generating +# the keystore and truststore. For instructions on generating these files, see: +# http://download.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CreateKeystore +# +server_encryption_options: + internode_encryption: none + keystore: conf/.keystore + keystore_password: cassandra + truststore: conf/.truststore + truststore_password: cassandra + # More advanced defaults below: + # protocol: TLS + # algorithm: SunX509 + # store_type: JKS + # cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] + # require_client_auth: false + +# enable or disable client/server encryption. +client_encryption_options: + enabled: false + # If enabled and optional is set to true encrypted and unencrypted connections are handled. + optional: false + keystore: conf/.keystore + keystore_password: cassandra + # require_client_auth: false + # Set trustore and truststore_password if require_client_auth is true + # truststore: conf/.truststore + # truststore_password: cassandra + # More advanced defaults below: + # protocol: TLS + # algorithm: SunX509 + # store_type: JKS + # cipher_suites: [TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA] + +# internode_compression controls whether traffic between nodes is +# compressed. +# can be: all - all traffic is compressed +# dc - traffic between different datacenters is compressed +# none - nothing is compressed. +internode_compression: all + +# Enable or disable tcp_nodelay for inter-dc communication. +# Disabling it will result in larger (but fewer) network packets being sent, +# reducing overhead from the TCP protocol itself, at the cost of increasing +# latency if you block for cross-datacenter responses. +inter_dc_tcp_nodelay: false + +# TTL for different trace types used during logging of the repair process. +tracetype_query_ttl: 86400 +tracetype_repair_ttl: 604800 + +# By default, Cassandra logs GC Pauses greater than 200 ms at INFO level +# This threshold can be adjusted to minimize logging if necessary +# gc_log_threshold_in_ms: 200 + +# GC Pauses greater than gc_warn_threshold_in_ms will be logged at WARN level +# If unset, all GC Pauses greater than gc_log_threshold_in_ms will log at +# INFO level +# Adjust the threshold based on your application throughput requirement +gc_warn_threshold_in_ms: 1000 + +# UDFs (user defined functions) are disabled by default. +# As of Cassandra 3.0 there is a sandbox in place that should prevent execution of evil code. +enable_user_defined_functions: false + +# Enables scripted UDFs (JavaScript UDFs). +# Java UDFs are always enabled, if enable_user_defined_functions is true. +# Enable this option to be able to use UDFs with "language javascript" or any custom JSR-223 provider. +# This option has no effect, if enable_user_defined_functions is false. +enable_scripted_user_defined_functions: false + +# The default Windows kernel timer and scheduling resolution is 15.6ms for power conservation. +# Lowering this value on Windows can provide much tighter latency and better throughput, however +# some virtualized environments may see a negative performance impact from changing this setting +# below their system default. The sysinternals 'clockres' tool can confirm your system's default +# setting. +windows_timer_interval: 1 + +# Maximum size of any value in SSTables. Safety measure to detect SSTable corruption +# early. Any value size larger than this threshold will result into marking an SSTable +# as corrupted. This should be positive and less than 2048. +# max_value_size_in_mb: 256 + +# Coalescing Strategies # +# Coalescing multiples messages turns out to significantly boost message processing throughput (think doubling or more). +# On bare metal, the floor for packet processing throughput is high enough that many applications won't notice, but in +# virtualized environments, the point at which an application can be bound by network packet processing can be +# surprisingly low compared to the throughput of task processing that is possible inside a VM. It's not that bare metal +# doesn't benefit from coalescing messages, it's that the number of packets a bare metal network interface can process +# is sufficient for many applications such that no load starvation is experienced even without coalescing. +# There are other benefits to coalescing network messages that are harder to isolate with a simple metric like messages +# per second. By coalescing multiple tasks together, a network thread can process multiple messages for the cost of one +# trip to read from a socket, and all the task submission work can be done at the same time reducing context switching +# and increasing cache friendliness of network message processing. +# See CASSANDRA-8692 for details. + +# Strategy to use for coalescing messages in OutboundTcpConnection. +# Can be fixed, movingaverage, timehorizon (default), disabled. +# You can also specify a subclass of CoalescingStrategies.CoalescingStrategy by name. +# otc_coalescing_strategy: TIMEHORIZON + +# How many microseconds to wait for coalescing. For fixed strategy this is the amount of time after the first +# message is received before it will be sent with any accompanying messages. For moving average this is the +# maximum amount of time that will be waited as well as the interval at which messages must arrive on average +# for coalescing to be enabled. +# otc_coalescing_window_us: 200 + +# Do not try to coalesce messages if we already got that many messages. This should be more than 2 and less than 128. +# otc_coalescing_enough_coalesced_messages: 8 + +# How many milliseconds to wait between two expiration runs on the backlog (queue) of the OutboundTcpConnection. +# Expiration is done if messages are piling up in the backlog. Droppable messages are expired to free the memory +# taken by expired messages. The interval should be between 0 and 1000, and in most installations the default value +# will be appropriate. A smaller value could potentially expire messages slightly sooner at the expense of more CPU +# time and queue contention while iterating the backlog of messages. +# An interval of 0 disables any wait time, which is the behavior of former Cassandra versions. +# +# otc_backlog_expiration_interval_ms: 200 diff --git a/music-rest/distribution/cassandra/docker-entrypoint.sh b/music-rest/distribution/cassandra/docker-entrypoint.sh new file mode 100644 index 00000000..34825bd2 --- /dev/null +++ b/music-rest/distribution/cassandra/docker-entrypoint.sh @@ -0,0 +1,107 @@ +#!/bin/bash +set -e + +# first arg is `-f` or `--some-option` +# or there are no args +if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then + set -- cassandra -f "$@" +fi + +# allow the container to be started with `--user` +if [ "$1" = 'cassandra' -a "$(id -u)" = '0' ]; then + chown -R cassandra /var/lib/cassandra /var/log/cassandra "$CASSANDRA_CONFIG" + exec gosu cassandra "$BASH_SOURCE" "$@" +fi + +_ip_address() { + # scrape the first non-localhost IP address of the container + # in Swarm Mode, we often get two IPs -- the container IP, and the (shared) VIP, and the container IP should always be first + ip address | awk ' + $1 == "inet" && $NF != "lo" { + gsub(/\/.+$/, "", $2) + print $2 + exit + } + ' +} + +if [ "$1" = 'cassandra' ]; then + : ${CASSANDRA_RPC_ADDRESS='0.0.0.0'} + + : ${CASSANDRA_LISTEN_ADDRESS='auto'} + if [ "$CASSANDRA_LISTEN_ADDRESS" = 'auto' ]; then + CASSANDRA_LISTEN_ADDRESS="$(_ip_address)" + fi + +echo "#############################################" +echo "############## Update music.cql #############" +echo "#############################################" + + if [ "$CASSANDRA_BROADCAST_ADDRESS" = 'auto' ]; then + CASSANDRA_BROADCAST_ADDRESS="$(_ip_address)" + fi + if [ "${MUSIC_REPLICATION_FACTOR}" ]; then + sed -ri 's/REPLICATION_FACTOR/'${MUSIC_REPLICATION_FACTOR}'/' "$f" + fi +done + +echo "#############################################" +echo "############## Update music.cql #############" +echo "#############################################" + +for f in /docker-entrypoint-initdb.d/a_music.cql; do + if [ "${MUSIC_REPLICATION_CLASS}" ]; then + sed -ri 's/REPLICATION_CLASS/'${MUSIC_REPLICATION_CLASS}'/' "$f" + fi + if [ "${MUSIC_REPLICATION_FACTOR}" ]; then + sed -ri 's/REPLICATION_FACTOR/'${MUSIC_REPLICATION_FACTOR}'/' "$f" + fi +done + +echo "#############################################" +echo "######Updating username and password #######" +echo "#############################################" +for f in /docker-entrypoint-initdb.d/b_pw.cql; do + if [ "${CASSUSER}" ]; then + sed -ri 's/CASSUSER/'${CASSUSER}'/' "$f" + fi + if [ "${CASSPASS}" ]; then + sed -ri 's/CASSPASS/'${CASSPASS}'/' "$f" + fi +done + +echo "#############################################" +echo "############## Let run cql's ################" +echo "#############################################" +for f in /docker-entrypoint-initdb.d/*; do + case "$f" in + *zzz*.cql) + echo "$0: running $f" && until $AM && cqlsh -u ${CASSUSER} -p ${CASSPASS} -f "$f"; + do >&2 echo "Cassandra is unavailable - sleeping [${f}] $C";let C=C+1; sleep 5; done & ;; + *a_music.cql) + echo "$0: running $f" && until $PW && cqlsh -u ${CASSUSER} -p ${CASSPASS} -f "$f" && AM=true; + do >&2 echo "Cassandra is unavailable - sleeping [${f}] $D";let D=D+1; sleep 5; done & ;; + *b_pw.cql) + echo "$0: running $f" && until cqlsh -u cassandra -p cassandra -f "$f" && PW=true; + do >&2 echo "Cassandra is unavailable - sleeping [${f}] $E";let E=E+1; sleep 5; done & ;; + *) echo "$0: ignoring $f" ;; + esac + + echo +done + + +echo "#############################################" +echo "########### Running Password CQL ############" +echo "#############################################" + +#echo "$0: running $f" && +#until cqlsh -u cassandra -p cassandra -f /pw.cql; +#do >&2 echo "Cassandra is unavailable - sleeping"; sleep 10; done + +echo "#############################################" +echo "########### Cassandra Running ###############" +echo "#############################################" + + +exec "$@"
\ No newline at end of file diff --git a/music-rest/distribution/cassandra_job/Dockerfile b/music-rest/distribution/cassandra_job/Dockerfile new file mode 100644 index 00000000..937afdee --- /dev/null +++ b/music-rest/distribution/cassandra_job/Dockerfile @@ -0,0 +1,30 @@ +# +# ============LICENSE_START========================================== +# org.onap.music +# =================================================================== +# Copyright (c) 2019 AT&T Intellectual Property +# =================================================================== +# Licensed 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. +# +# ============LICENSE_END============================================= +# ==================================================================== + +#registry.hub.docker.com/ +FROM library/cassandra:3.11 +ENV DEF_USER=cassandra +ENV DEF_PASS=cassandra +COPY runcql.sh / +RUN mkdir -p cql/extra && \ + chmod 755 runcql.sh && \ + chown cassandra runcql.sh +CMD ["/runcql.sh"] diff --git a/music-rest/distribution/cassandra_job/admin.cql b/music-rest/distribution/cassandra_job/admin.cql new file mode 100644 index 00000000..904a2bab --- /dev/null +++ b/music-rest/distribution/cassandra_job/admin.cql @@ -0,0 +1,17 @@ +CREATE KEYSPACE IF NOT EXISTS admin + WITH REPLICATION = { + 'class' : 'SimpleStrategy', + 'replication_factor': 1 + } + AND DURABLE_WRITES = true; + +CREATE TABLE IF NOT EXISTS admin.keyspace_master ( + uuid uuid, + keyspace_name text, + application_name text, + is_api boolean, + password text, + username text, + is_aaf boolean, + PRIMARY KEY (uuid) +); diff --git a/music-rest/distribution/cassandra_job/admin_pw.cql b/music-rest/distribution/cassandra_job/admin_pw.cql new file mode 100644 index 00000000..bbad8d1d --- /dev/null +++ b/music-rest/distribution/cassandra_job/admin_pw.cql @@ -0,0 +1,2 @@ +CREATE ROLE IF NOT EXISTS <CASSUSER> WITH PASSWORD = '<CASSPASS>' AND SUPERUSER = True AND LOGIN = True; +ALTER ROLE cassandra WITH PASSWORD = 'SomeLongRandomStringNoonewillthinkof'; diff --git a/music-rest/distribution/cassandra_job/runcql.sh b/music-rest/distribution/cassandra_job/runcql.sh new file mode 100644 index 00000000..89396bfc --- /dev/null +++ b/music-rest/distribution/cassandra_job/runcql.sh @@ -0,0 +1,112 @@ +#! /bin/bash +# +# ============LICENSE_START========================================== +# org.onap.music +# =================================================================== +# Copyright (c) 2019 AT&T Intellectual Property +# =================================================================== +# Licensed 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. +# +# ============LICENSE_END============================================= +# ==================================================================== + +if [ -z "$TIMEOUT" ]; then + TIMEOUT=10; +fi +if [ -z "$DELAY" ]; then + DELAY=60; +fi +TO="--request-timeout=$TIMEOUT" + +if [ $CASS_HOSTNAME ]; then + echo "Sleeping for $DELAY seconds before running cql"; + sleep $DELAY; + >&2 echo "#############################################" + >&2 echo "############## Let run cql's ################" + >&2 echo "#############################################" + >&2 echo "Current Variables in play" + >&2 echo "Default User" + >&2 echo "DEF_USER="$DEF_USER + >&2 echo "DEF_PASS=***********" + >&2 echo "New User" + >&2 echo "USERNAME="$USERNAME + >&2 echo "PASSWORD=***********" + >&2 echo "TIMEOUT="$TIMEOUT + >&2 echo "Running cqlsh $TO -u cassandra -p cassandra -e \"describe keyspaces;\" ${CASS_HOSTNAME} ${PORT};" + if cqlsh $TO -u cassandra -p cassandra -e "describe keyspaces;" ${CASS_HOSTNAME} ${PORT}; + then + >&2 echo "Cassandra user still avalable, will continue as usual"; + else + CASSFAIL=true + >&2 echo "$DEF_USER failed, trying with $USERNAME" + if cqlsh $TO -u $USERNAME -p $PASSWORD -e "describe keyspaces;" ${CASS_HOSTNAME} ${PORT}; + then + >&2 echo "Password $USERNAME in play, update Variables" + DEF_USER=$USERNAME + DEF_PASS=$PASSWORD + >&2 echo "DEF_USER="$DEF_USER + >&2 echo "DEF_PASS=***********" + if cqlsh $TO -u $USERNAME -p $PASSWORD -e "describe keyspaces;" ${CASS_HOSTNAME} ${PORT} | grep admin; + then + >&2 echo "Admin table exists, everything looks good" + exit 0; + else + >&2 echo "Admin does not exists but password has changed. Continue as usual with proper username set" + >&2 echo "DEF_USER=" $DEF_USER + fi + else + if [ $CASSFAIL ]; then + >&2 echo "$DEF_USER and $USERNAME fail. DB might need to be initialized again. This shouldn't have happend." + exit 1; + else + >&2 echo "Continue and as usual" + fi + fi + fi + >&2 echo "Running admin.cql file:" + >&2 echo "Running cqlsh -u $DEF_USER -p $DEF_PASS -f /cql/admin.cql ${CASS_HOSTNAME} ${PORT}" + sleep 1; + if cqlsh $TO -u $DEF_USER -p $DEF_PASS -f /cql/admin.cql ${CASS_HOSTNAME} ${PORT}; + then + >&2 echo "Success - admin.cql - Admin keyspace created"; + else + >&2 echo "Failure - admin.cql"; + exit 0; + fi + >&2 echo "Running admin_pw.cql file:" + >&2 echo "Running cqlsh -u $DEF_USER -p $DEF_PASS -f /cql/admin_pw.cql ${CASS_HOSTNAME} ${PORT}" + sleep 1; + if cqlsh $TO -u $DEF_USER -p $DEF_PASS -f /cql/admin_pw.cql ${CASS_HOSTNAME} ${PORT}; + then + >&2 echo "Success - admin_pw.cql - Password Changed"; + else + >&2 echo "Failure - admin_pw.cql"; + exit 0; + fi + + >&2 echo "Running Test - look for admin keyspace:" + >&2 echo "Running cqlsh -u $USERNAME -p $PASSWORD -e "select * from system_auth.roles;" ${CASS_HOSTNAME} ${PORT}" + sleep 1; + if cqlsh $TO -u $USERNAME -p $PASSWORD -e "select * from system_auth.roles;" ${CASS_HOSTNAME} ${PORT} + then + >&2 echo "Success - running test"; + else + >&2 echo "Failure - running test"; + exit 0; + fi + +else + >&2 echo "Missing CASS_HOSTNAME"; + exit 0; +fi + diff --git a/music-rest/distribution/cassandra_job/test.cql b/music-rest/distribution/cassandra_job/test.cql new file mode 100644 index 00000000..196fea22 --- /dev/null +++ b/music-rest/distribution/cassandra_job/test.cql @@ -0,0 +1,2 @@ +DESCRIBE keyspaces; + diff --git a/music-rest/distribution/music/Dockerfile b/music-rest/distribution/music/Dockerfile new file mode 100644 index 00000000..9868ceee --- /dev/null +++ b/music-rest/distribution/music/Dockerfile @@ -0,0 +1,35 @@ +# +# ============LICENSE_START========================================== +# org.onap.music +# =================================================================== +# Copyright (c) 2019 AT&T Intellectual Property +# =================================================================== +# Licensed 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. +# +# ============LICENSE_END============================================= +# ==================================================================== + +FROM openjdk:8 +LABEL purpose="Springboot for MUSIC" +RUN apt-get update && apt-get install -y netcat telnet vim vim-common curl +RUN groupadd --gid 1000 music && useradd --gid 1000 --uid 1000 music +RUN mkdir -p /opt/app/music/logs/MUSIC +COPY MUSIC-SB.jar /opt/app/music +COPY startup.sh /opt/app/music +RUN mkdir -p /opt/app/music/logs && \ + mkdir -p /opt/app/music/etc && \ + chown -R music:music /opt/app/music/ && \ + chmod 755 /opt/app/music/startup.sh +USER music:music +WORKDIR /opt/app/music +CMD ["/opt/app/music/startup.sh"] diff --git a/music-rest/distribution/music/startup.sh b/music-rest/distribution/music/startup.sh new file mode 100644 index 00000000..98b3ae09 --- /dev/null +++ b/music-rest/distribution/music/startup.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# +# ============LICENSE_START========================================== +# org.onap.music +# =================================================================== +# Copyright (c) 2019 AT&T Intellectual Property +# =================================================================== +# Licensed 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. +# +# ============LICENSE_END============================================= +# ==================================================================== + +echo "Running startup script to get password from certman" +PWFILE=/opt/app/aafcertman/.password +LOGFILE=/opt/app/music/logs/MUSIC/music-sb.log +PROPS=/opt/app/music/etc/music-sb.properties +LOGBACK=/opt/app/music/etc/logback.xml +LOGGING= +DEBUG_PROP= +# Debug Setup. Uses env variables +# DEBUG and DEBUG_PORT +# DEBUG=true/false | DEBUG_PORT=<Port valie must be integer> +if [ "${DEBUG}" == "true" ]; then + if [ "${DEBUG_PORT}" == "" ]; then + DEBUG_PORT=8000 + fi + echo "Debug mode on" + DEBUG_PROP="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=${DEBUG_PORT},suspend=n" +fi + +# LOGBACK file: if /opt/app/music/etc/logback.xml exists thenuse that. +if [ -f $LOGBACK ]; then + LOGGING="--logging.config=file:${LOGBACK}" +fi + +# Get Passwords from /opt/app/aafcertman +if [ -f $PWFILE ]; then + echo "Found ${PWFILE}" >> $LOGFILE + PASSWORD=$(cat ${PWFILE}) + echo "#### Using Password from ${PWFILE} for Certs" >> ${LOGFILE} +else + PASSWORD=changeit + echo "#### Using Default Password for Certs" >> ${LOGFILE} +fi + +# If music-sb.properties exists in /opt/app/music/etc then use that to override the application.properties +if [ -f $PROPS ]; then + # Run with different Property file + #echo "java ${DEBUG_PROP} -jar MUSIC.jar --spring.config.location=file:${PROPS} ${LOGGING} 2>&1 | tee ${LOGFILE}" + java ${DEBUG_PROP} ${JAVA_OPTS} -jar MUSIC-SB.jar ${SPRING_OPTS} --spring.config.location=file:${PROPS} ${LOGGING} 2>&1 | tee ${LOGFILE} +else + #echo "java ${DEBUG_PROP} -jar MUSIC.jar --server.ssl.key-store-password=${PASSWORD} ${LOGGING} 2>&1 | tee ${LOGFILE}" + java ${DEBUG_PROP} ${JAVA_OPTS} -jar MUSIC-SB.jar ${SPRING_OPTS} --server.ssl.key-store-password="${PASSWORD}" ${LOGGING} 2>&1 | tee ${LOGFILE} +fi + + + + diff --git a/music-rest/pom.xml b/music-rest/pom.xml new file mode 100755 index 00000000..9bcfd396 --- /dev/null +++ b/music-rest/pom.xml @@ -0,0 +1,385 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START========================================== + org.onap.music + =================================================================== + Copyright (c) 2017 AT&T Intellectual Property + =================================================================== + Modifications Copyright (c) 2019 IBM. + =================================================================== + Licensed 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. + + ============LICENSE_END============================================= + ==================================================================== +--> +<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> + <groupId>org.onap.music</groupId> + <artifactId>MUSIC-rest</artifactId> + <packaging>jar</packaging> + <version>3.2.40-SNAPSHOT</version> + <description> + This is the MUSIC Spring-based REST service. + </description> + <name>music-rest</name> + + <parent> + <groupId>org.onap.music</groupId> + <artifactId>MUSIC</artifactId> + <version>3.2.40-SNAPSHOT</version> + </parent> + + <properties> + <start-class>org.onap.music.MusicApplication</start-class> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java.version>1.8</java.version> + <jersey1.version>1.19</jersey1.version> + <jersey2.version>2.25.1</jersey2.version> + <jaxrs.version>2.0.1</jaxrs.version> + + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <!--nexus --> + <nexusproxy>https://nexus.onap.org</nexusproxy> + <onap.nexus.url>https://nexus.onap.org</onap.nexus.url> + <snapshotNexusPath>/content/repositories/snapshots/</snapshotNexusPath> + <releaseNexusPath>/content/repositories/releases/</releaseNexusPath> + <stagingNexusPath>/content/repositories/staging/</stagingNexusPath> + <sitePath>/content/sites/site/org/onap/music/${project.version}</sitePath> + <!--maven --> + <timestamp>${maven.build.timestamp}</timestamp> + <maven.build.timestamp.format>yyyy.MM.dd.HH.mm</maven.build.timestamp.format> + <!--skip checkstyle --> + <maven.check.skip>false</maven.check.skip> + <!--docker --> + <docker.tag>${project.version}-${timestamp}</docker.tag> + <docker.latest.tag>${project.version}-latest</docker.latest.tag> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>2.1.1.RELEASE</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-cassandra</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-jersey</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-autoconfigure</artifactId> + </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjweaver</artifactId> + <scope>compile</scope> + </dependency> + <!-- Springboot --> + <dependency> + <groupId>org.onap.music</groupId> + <artifactId>MUSIC-core</artifactId> + <version>3.2.40-SNAPSHOT</version> + </dependency> + <!-- Jersey --> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + <version>${jersey1.version}</version> + <exclusions> + <exclusion> + <groupId>javax.ws.rs</groupId> + <artifactId>jsr311-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-server</artifactId> + <version>${jersey1.version}</version> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-json</artifactId> + <version>${jersey1.version}</version> + <exclusions> + <exclusion> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-jaxrs</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-servlet</artifactId> + <version>${jersey1.version}</version> + </dependency> + <!-- /Jersey --> + <!-- Testing --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.cassandraunit</groupId> + <artifactId>cassandra-unit-spring</artifactId> + <version>3.5.0.1</version> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + </exclusion> + <exclusion> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </exclusion> + <exclusion> + <groupId>org.cassandraunit</groupId> + <artifactId>cassandra-unit</artifactId> + </exclusion> + <exclusion> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-core</artifactId> + </exclusion> + <exclusion> + <groupId>com.addthis.metrics</groupId> + <artifactId>reporter-config-base</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.cassandraunit</groupId> + <artifactId>cassandra-unit-shaded</artifactId> + <version>3.5.0.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>2.23.4</version> + <scope>test</scope> + </dependency> + <!-- /Testing --> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>2.1.1.RELEASE</version> + <configuration> + <mainClass>org.onap.music.MusicApplication</mainClass> + <outputDirectory>${project.basedir}/distribution/music/</outputDirectory> + <addResources>true</addResources> + <finalName>MUSIC-SB</finalName> + <excludes> + <exclude> + <groupId>javax.ws.rs</groupId> + <artifactId>jsr311-api</artifactId> + </exclude> + </excludes> + </configuration> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> + <plugins> + <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> + <plugin> + <artifactId>maven-clean-plugin</artifactId> + <version>3.1.0</version> + </plugin> + <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>3.0.2</version> + </plugin> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.0</version> + </plugin> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.22.1</version> + </plugin> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <version>3.0.2</version> + </plugin> + <plugin> + <artifactId>maven-install-plugin</artifactId> + <version>2.5.2</version> + </plugin> + <plugin> + <artifactId>maven-deploy-plugin</artifactId> + <version>2.8.2</version> + </plugin> + <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> + <plugin> + <artifactId>maven-site-plugin</artifactId> + <version>3.7.1</version> + </plugin> + <plugin> + <artifactId>maven-project-info-reports-plugin</artifactId> + <version>3.0.0</version> + </plugin> + </plugins> + </pluginManagement> + </build> + <profiles> + <profile> + <id>docker</id> + <build> + <plugins> + <plugin> + <groupId>io.fabric8</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>0.19.1</version> + <configuration> + <verbose>true</verbose> + <apiVersion>1.23</apiVersion> + <registry>nexus3.onap.org:10003</registry> + <images> + <!-- MUSIC War --> + <image> + <name>onap/music/music_sb</name> + <alias>docker_music</alias> + <build> + <cleanup>true</cleanup> + <tags> + <tag>${docker.tag}</tag> + <tag>${docker.latest.tag}</tag> + </tags> + <dockerFileDir>${project.basedir}/distribution/music</dockerFileDir> + </build> + </image> + <!-- Cassandra --> + <image> + <name>onap/music/cassandra_3_11</name> + <alias>docker_cassandra_sec</alias> + <build> + <cleanup>true</cleanup> + <tags> + <tag>${docker.tag}</tag> + <tag>${docker.latest.tag}</tag> + </tags> + <dockerFileDir>${project.basedir}/distribution/cassandra</dockerFileDir> + </build> + </image> + <!-- Cassandra Job --> + <image> + <name>onap/music/cassandra_job</name> + <alias>docker_cassandra_job</alias> + <build> + <cleanup>true</cleanup> + <tags> + <tag>${docker.tag}</tag> + <tag>${docker.latest.tag}</tag> + </tags> + <dockerFileDir>${project.basedir}/distribution/cassandra_job</dockerFileDir> + </build> + </image> + </images> + </configuration> + <executions> + <execution> + <id>clean-images</id> + <phase>pre-clean</phase> + <goals> + <goal>remove</goal> + </goals> + <configuration> + <removeAll>true</removeAll> + <image>music</image> + </configuration> + </execution> + <execution> + <id>generate-images</id> + <phase>package</phase> + <goals> + <goal>build</goal> + </goals> + </execution> + <execution> + <id>push-images</id> + <phase>deploy</phase> + <goals> + <goal>push</goal> + </goals> + <configuration> + <image>onap/music/music</image> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>default</id> + </profile> + </profiles> +</project> diff --git a/music-rest/src/main/java/LICENSE.txt b/music-rest/src/main/java/LICENSE.txt new file mode 100644 index 00000000..cc6cdea5 --- /dev/null +++ b/music-rest/src/main/java/LICENSE.txt @@ -0,0 +1,24 @@ + +The following license applies to all files in this and sub-directories. Licenses +are included in individual source files where appropriate, and if it differs +from this text, it supersedes this. Any file that does not have license text +defaults to being covered by this text; not all files support the addition of +licenses. +# +# ------------------------------------------------------------------------- +# Copyright (c) 2017 AT&T Intellectual Property +# +# Licensed 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. +# +# ------------------------------------------------------------------------- +#
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/JerseyConfig.java b/music-rest/src/main/java/org/onap/music/JerseyConfig.java new file mode 100755 index 00000000..b64e7044 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/JerseyConfig.java @@ -0,0 +1,87 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music; + +import io.swagger.jaxrs.config.BeanConfig; +import io.swagger.jaxrs.listing.ApiListingResource; +import io.swagger.jaxrs.listing.SwaggerSerializers; + +import javax.annotation.PostConstruct; + +import org.glassfish.jersey.server.ResourceConfig; +import org.onap.music.conductor.conditionals.RestMusicConditionalAPI; +import org.onap.music.exceptions.MusicExceptionMapper; +import org.onap.music.rest.RestMusicDataAPI; +import org.onap.music.rest.RestMusicHealthCheckAPI; +import org.onap.music.rest.RestMusicLocksAPI; +import org.onap.music.rest.RestMusicQAPI; +import org.onap.music.rest.RestMusicTestAPI; +import org.onap.music.rest.RestMusicVersionAPI; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JerseyConfig extends ResourceConfig { + + @Value("${spring.jersey.application-path:/}") + private String apiPath; + + public JerseyConfig() { + this.registerEndpoints(); + register(MusicExceptionMapper.class); + } + + @PostConstruct + public void init() { + this.configureSwagger(); + } + + private void registerEndpoints() { + register(RestMusicDataAPI.class); + register(RestMusicLocksAPI.class); + register(RestMusicConditionalAPI.class); + register(RestMusicQAPI.class); + register(RestMusicTestAPI.class); + register(RestMusicVersionAPI.class); + register(RestMusicHealthCheckAPI.class); + + } + + private void configureSwagger() { + // Available at localhost:port/swagger.json + this.register(ApiListingResource.class); + this.register(SwaggerSerializers.class); + + BeanConfig config = new BeanConfig(); + config.setConfigId("MUSIC"); + config.setTitle("MUSIC"); + config.setVersion("v2"); + config.setContact("Thomas Nelson"); + config.setSchemes(new String[] {"http", "https"}); + config.setBasePath("/MUSIC/rest"); + config.setResourcePackage("org.onap.music"); + config.setPrettyPrint(true); + config.setScan(true); + } + +} diff --git a/music-rest/src/main/java/org/onap/music/MusicApplication.java b/music-rest/src/main/java/org/onap/music/MusicApplication.java new file mode 100755 index 00000000..0fe354d9 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/MusicApplication.java @@ -0,0 +1,208 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.onap.aaf.cadi.PropAccess; +import org.onap.music.authentication.CadiAuthFilter; +import org.onap.music.authentication.MusicAuthorizationFilter; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.MusicLoggingServletFilter; +import org.onap.music.lockingservice.cassandra.LockCleanUpDaemon; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.PropertiesLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.DependsOn; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.context.request.RequestContextListener; + +@SpringBootApplication(scanBasePackages = { "org.onap.music.rest"}) +@EnableAutoConfiguration(exclude = { CassandraDataAutoConfiguration.class }) +@ComponentScan(value = { "org.onap.music" }) +@EnableScheduling +public class MusicApplication extends SpringBootServletInitializer { + + private static final String KEYSPACE_PATTERN = "/v2/keyspaces/*"; + private static final String LOCKS_PATTERN = "/v2/locks/*"; + private static final String Q_PATTERN = "/v2/priorityq/*"; + + @Autowired + private PropertiesLoader propertyLoader; + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicApplication.class); + + + public static void main(String[] args) { + new MusicApplication().configure(new SpringApplicationBuilder(MusicApplication.class)).run(args); + + LockCleanUpDaemon daemon = new LockCleanUpDaemon(); + daemon.setDaemon(true); + daemon.start(); + } + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + + return application.sources(MusicApplication.class); + } + + @Bean("loadProperties") + public void loadProperties() { + propertyLoader.loadProperties(); + } + + + @Bean + @DependsOn("loadProperties") + public PropAccess propAccess() { + if (MusicUtil.getIsCadi()) { + return new PropAccess(new String[] { + "cadi_prop_files=/opt/app/music/etc/cadi.properties" }); + } else { + return null; + } + } + + @Bean(name = "cadiFilter") + @DependsOn("loadProperties") + public Filter cadiFilter() throws ServletException { + propertyLoader.loadProperties(); + if (MusicUtil.getIsCadi()) { + PropAccess propAccess = propAccess(); + return new CadiAuthFilter(propAccess); + } else { + return (ServletRequest request, ServletResponse response, FilterChain chain) -> { + // do nothing for now. + }; + } + } + + /** + * Added for capturing custom header values from client. + * + * order is set to 1 for this filter + * + * sp931a + * + * @return + * @throws ServletException + */ + @Bean(name="logFilter") + @DependsOn("loadProperties") + public FilterRegistrationBean<Filter> loggingFilterRegistration() throws ServletException { + logger.info("loggingFilterRegistration called for log filter.."); + propertyLoader.loadProperties(); + FilterRegistrationBean<Filter> frb = new FilterRegistrationBean<>(); + frb.setFilter(new MusicLoggingServletFilter()); + frb.addUrlPatterns( + KEYSPACE_PATTERN, + LOCKS_PATTERN, + Q_PATTERN + ); + frb.setName("logFilter"); + frb.setOrder(1); + return frb; + } + + @Bean + @DependsOn("loadProperties") + public FilterRegistrationBean<Filter> cadiFilterRegistration() throws ServletException { + logger.info("cadiFilterRegistration called for cadi filter.."); + FilterRegistrationBean<Filter> frb = new FilterRegistrationBean<>(); + frb.setFilter(cadiFilter()); + if (MusicUtil.getIsCadi()) { + frb.addUrlPatterns( + KEYSPACE_PATTERN, + LOCKS_PATTERN, + Q_PATTERN + ); + } else { + frb.addUrlPatterns("/v0/test"); + } + frb.setName("cadiFilter"); + frb.setOrder(2); + return frb; + } + + + /** + * Added for Authorization using CADI + * + * sp931a + * + * @return + * @throws ServletException + */ + @Bean + @DependsOn("loadProperties") + public FilterRegistrationBean<Filter> cadiFilterRegistrationForAuth() throws ServletException { + logger.info("cadiFilterRegistrationForAuth called for cadi auth filter.."); + FilterRegistrationBean<Filter> frb = new FilterRegistrationBean<>(); + frb.setFilter(cadiMusicAuthFilter()); + + if (MusicUtil.getIsCadi()) { + frb.addUrlPatterns( + KEYSPACE_PATTERN, + LOCKS_PATTERN, + Q_PATTERN + ); + } else { + frb.addUrlPatterns("/v0/test"); + } + frb.setName("cadiMusicAuthFilter"); + frb.setOrder(3); + return frb; + } + + @Bean(name = "cadiMusicAuthFilter") + @DependsOn("loadProperties") + public Filter cadiMusicAuthFilter() throws ServletException { + propertyLoader.loadProperties(); + if (MusicUtil.getIsCadi()) { + return new MusicAuthorizationFilter(); + } else { + return (ServletRequest request, ServletResponse response, FilterChain chain) -> { + // do nothing for now. + }; + } + } + + @Bean + @ConditionalOnMissingBean(RequestContextListener.class) + public RequestContextListener requestContextListener() { + return new RequestContextListener(); + } +} diff --git a/music-rest/src/main/java/org/onap/music/authentication/AuthUtil.java b/music-rest/src/main/java/org/onap/music/authentication/AuthUtil.java new file mode 100644 index 00000000..ee3b77a4 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/authentication/AuthUtil.java @@ -0,0 +1,276 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * + * Modifications Copyright (C) 2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.authentication; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Pattern; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.onap.aaf.cadi.CadiWrap; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.exceptions.MusicAuthenticationException; + +public class AuthUtil { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(AuthUtil.class); + + private AuthUtil() { + throw new IllegalStateException("Utility class"); + } + + /** + * Get the list of permissions from the Request object. + * + * + * @param request servlet request object + * @return returns list of AAFPermission of the requested MechId for all the + * namespaces + */ + public static List<AAFPermission> getAAFPermissions(ServletRequest request) { + CadiWrap wrapReq = (CadiWrap) request; + + List<Permission> perms = wrapReq.getPermissions(wrapReq.getUserPrincipal()); + List<AAFPermission> aafPermsList = new ArrayList<>(); + for (Permission perm : perms) { + AAFPermission aafPerm = (AAFPermission) perm; + aafPermsList.add(aafPerm); + } + return aafPermsList; + } + + /** + * Here is a sample of a permission object in AAI. The key attribute will have + * Type|Instance|Action. + * AAFPermission: + * NS: null + * Type: org.onap.music.cadi.keyspace ( Permission Type ) + * Instance: tomtest ( Cassandra Keyspace ) + * Action: *|GET|ALL ( Access Level [*|ALL] for full access and [GET] for Read only) + * Key: org.onap.music.cadi.keyspace|tomtest|* + * + * This method will filter all permissions whose key starts with the requested namespace. + * The nsamespace here is the music namespace which is defined in music.property file. + * i;e is the type contains in key is org.onap.music.cadi.keyspace and the namespace + * value is org.onap.music.cadi.keyspace, it will add to list + * otherwise reject. + * + * @param nameSpace + * @param allPermissionsList + * @return + */ + private static List<AAFPermission> filterNameSpacesAAFPermissions(String nameSpace, + List<AAFPermission> allPermissionsList) { + List<AAFPermission> list = new ArrayList<>(); + for (Iterator<AAFPermission> iterator = allPermissionsList.iterator(); iterator.hasNext();) { + AAFPermission aafPermission = iterator.next(); + if(aafPermission.getType().indexOf(nameSpace) == 0) { + list.add(aafPermission); + } + } + return list; + } + + /** + * Decode certian characters from url encoded to normal. + * + * @param str - String being decoded. + * @return returns the decoded string. + * @throws Exception throws excpetion + */ + public static String decodeFunctionCode(String str) throws MusicAuthenticationException { + final String DECODEVALUE_FORWARDSLASH = "2f"; + final String DECODEVALUE_HYPHEN = "2d"; + final String DECODEVALUE_ASTERISK = "2a"; + String decodedString = str; + List<Pattern> decodingList = new ArrayList<>(); + decodingList.add(Pattern.compile(DECODEVALUE_FORWARDSLASH)); + decodingList.add(Pattern.compile(DECODEVALUE_HYPHEN)); + decodingList.add(Pattern.compile(DECODEVALUE_ASTERISK)); + for (Pattern xssInputPattern : decodingList) { + try { + decodedString = decodedString.replaceAll("%" + xssInputPattern, + new String(Hex.decodeHex(xssInputPattern.toString().toCharArray()))); + } catch (DecoderException e) { + logger.error(EELFLoggerDelegate.securityLogger, + "AuthUtil Decode Failed! for instance: " + str); + throw new MusicAuthenticationException("Decode failed", e); + } + } + + return decodedString; + } + + /** + * + * + * @param request servlet request object + * @param nameSpace application namespace + * @return boolean value if the access is allowed + * @throws Exception throws exception + */ + public static boolean isAccessAllowed(ServletRequest request, String nameSpace) throws MusicAuthenticationException { + + if (request==null) { + throw new MusicAuthenticationException("Request cannot be null"); + } + + if (nameSpace==null || nameSpace.isEmpty()) { + throw new MusicAuthenticationException("NameSpace not Declared!"); + } + + boolean isauthorized = false; + List<AAFPermission> aafPermsList = getAAFPermissions(request); + logger.info(EELFLoggerDelegate.securityLogger, + "AAFPermission of the requested MechId for all the namespaces: " + aafPermsList); + logger.debug(EELFLoggerDelegate.securityLogger, "Requested nameSpace: " + nameSpace); + + List<AAFPermission> aafPermsFinalList = filterNameSpacesAAFPermissions(nameSpace, aafPermsList); + + logger.debug(EELFLoggerDelegate.securityLogger, + "AuthUtil list of AAFPermission for the specific namespace :::" + + aafPermsFinalList); + + HttpServletRequest httpRequest = (HttpServletRequest) request; + String requestUri = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length() + 1); + + logger.debug(EELFLoggerDelegate.securityLogger, + "AuthUtil requestUri :::" + requestUri); + + for (Iterator<AAFPermission> iterator = aafPermsFinalList.iterator(); iterator.hasNext();) { + AAFPermission aafPermission = iterator.next(); + if(!isauthorized) { + isauthorized = isMatchPattern(aafPermission, requestUri, httpRequest.getMethod()); + } + } + + logger.debug(EELFLoggerDelegate.securityLogger, + "isAccessAllowed for the request uri: " + requestUri + "is :" + isauthorized); + return isauthorized; + } + + /** + * + * This method will check, if the requested URI matches any of the instance + * found with the AAF permission list. + * i;e if the request URI is; /v2/keyspaces/tomtest/tables/emp15 and in the + * AAF permission table, we have an instance + * defined as "tomtest" mapped the logged in user, it will allow else error. + * + * User trying to create or aquire a lock + * Here is the requested URI /v2/locks/create/tomtest.MyTable.Field1 + * Here the keyspace name i;e tomtest will be test throught out the URL if it + * matches, it will allow the user to create a lock. + * "tomtest" here is the key, which is mapped as an instance in permission object. + * Instance can be delimited with ":" i;e ":music-cassandra-1908-dev:admin". In this case, + * each delimited + * token will be matched with that of request URI. + * + * Example Permission: + * org.onap.music.api.user.access|tomtest|* or ALL + * org.onap.music.api.user.access|tomtest|GET + * In case of the action field is ALL and *, user will be allowed else it will + * be matched with the requested http method type. + * + * + * + * @param aafPermission - AAfpermission obtained by cadi. + * @param requestUri - Rest URL client is calling. + * @param method - REST Method being used (GET,POST,PUT,DELETE) + * @return returns a boolean + * @throws Exception - throws an exception + */ + private static boolean isMatchPattern( + AAFPermission aafPermission, + String requestUri, + String method) throws MusicAuthenticationException { + if (null == aafPermission || null == requestUri || null == method) { + return false; + } + + String permKey = aafPermission.getKey(); + + logger.debug(EELFLoggerDelegate.securityLogger, "isMatchPattern permKey: " + + permKey + ", requestUri " + requestUri + " ," + method); + + String[] keyArray = permKey.split("\\|"); + String[] subPath = null; + String instance = keyArray[1]; + String action = keyArray[2]; + + //if the instance & action both are * , then allow + if ("*".equalsIgnoreCase(instance) && "*".equalsIgnoreCase(action)) { + return true; + } + //Decode string like %2f, %2d and %2a + if (!"*".equals(instance)) { + instance = decodeFunctionCode(instance); + } + if (!"*".equals(action)) { + action = decodeFunctionCode(action); + } + //Instance: :music-cassandra-1908-dev:admin + List<String> instanceList = Arrays.asList(instance.split(":")); + + String[] path = requestUri.split("/"); + + for (int i = 0; i < path.length; i++) { + // Sometimes the value will begin with "$", so we need to remove it + if (path[i].startsWith("$")) { + path[i] = path[i].replace("$",""); + } + // Each path element can again delemited by ".";i;e + // tomtest.tables.emp. We have scenarios like lock aquire URL + subPath = path[i].split("\\."); + for (int j = 0; j < subPath.length; j++) { + if (instanceList.contains(subPath[j])) { + return checkAction(method,action); + } else { + continue; + } + } + } + return false; + } + + private static boolean checkAction(String method, String action) { + if ("*".equals(action) || "ALL".equalsIgnoreCase(action)) { + return true; + } else { + return (method.equalsIgnoreCase(action)); + } + } + + + +}
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/authentication/AuthorizationError.java b/music-rest/src/main/java/org/onap/music/authentication/AuthorizationError.java new file mode 100644 index 00000000..7015b550 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/authentication/AuthorizationError.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.authentication; + + +/** + * Authorization error class used while setting error code and description back to client. + * + * + * @author sp931a + * + */ +public class AuthorizationError { + + private int responseCode; + + private String responseMessage; + + public int getResponseCode() { + return responseCode; + } + + public void setResponseCode(int responseCode) { + this.responseCode = responseCode; + } + + public String getResponseMessage() { + return responseMessage; + } + + public void setResponseMessage(String responseMessage) { + this.responseMessage = responseMessage; + } + +}
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/authentication/CadiAuthFilter.java b/music-rest/src/main/java/org/onap/music/authentication/CadiAuthFilter.java new file mode 100644 index 00000000..d043e6d6 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/authentication/CadiAuthFilter.java @@ -0,0 +1,65 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.authentication; + + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; + +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.music.eelf.logging.EELFLoggerDelegate; + +@WebFilter(urlPatterns = { "/*" }) +public class CadiAuthFilter extends CadiFilter { + + private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(CadiAuthFilter.class); + + public CadiAuthFilter(PropAccess access) throws ServletException { + super(true, access); + } + + public CadiAuthFilter() throws ServletException { + super(); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + super.init(filterConfig); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + logger.info(EELFLoggerDelegate.securityLogger, "Request is entering cadifilter"); + long startTime = System.currentTimeMillis(); + request.setAttribute("startTime", startTime); + super.doFilter(request, response, chain); + } +}
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/authentication/MusicAuthorizationFilter.java b/music-rest/src/main/java/org/onap/music/authentication/MusicAuthorizationFilter.java new file mode 100644 index 00000000..bde3e205 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/authentication/MusicAuthorizationFilter.java @@ -0,0 +1,122 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.authentication; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.exceptions.MusicAuthenticationException; +import org.onap.music.main.MusicUtil; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * This filter class does authorization from AAF + * + * @author sp931a + * + */ +//@PropertySource(value = {"file:/opt/app/music/etc/music.properties"}) +public class MusicAuthorizationFilter implements Filter { + + private String musicNS = MusicUtil.getMusicAafNs(); + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicAuthorizationFilter.class); + + public MusicAuthorizationFilter() throws ServletException { + super(); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // Do Nothing + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletResponse httpResponse = null; + + boolean isAuthAllowed = false; + + if (null != servletRequest && null != servletResponse) { + httpResponse = (HttpServletResponse) servletResponse; + long startTime = 0; + if( null != servletRequest.getAttribute("startTime")) { + startTime = ((Long)servletRequest.getAttribute("startTime")).longValue(); + } else { + startTime = System.currentTimeMillis(); // this will set only incase the request attribute not found + } + + try { + isAuthAllowed = AuthUtil.isAccessAllowed(servletRequest, musicNS); + } catch (MusicAuthenticationException e) { + logger.error(EELFLoggerDelegate.securityLogger, + "Error while checking authorization Music Namespace: " + musicNS + " : " + e.getMessage(),e); + } catch ( Exception e) { + logger.error(EELFLoggerDelegate.securityLogger, + "Error while checking authorization Music Namespace: " + musicNS + " : " + e.getMessage(),e); + } + + long endTime = System.currentTimeMillis(); + + //startTime set in <code>CadiAuthFilter</code> doFilter + logger.debug(EELFLoggerDelegate.securityLogger, + "Time took for authentication & authorization : " + + (endTime - startTime) + " milliseconds"); + + if (!isAuthAllowed) { + logger.info(EELFLoggerDelegate.securityLogger, + "Unauthorized Access"); + AuthorizationError authError = new AuthorizationError(); + authError.setResponseCode(HttpServletResponse.SC_UNAUTHORIZED); + authError.setResponseMessage("Unauthorized Access - Please make sure you are " + + "onboarded and have proper access to MUSIC. "); + + byte[] responseToSend = restResponseBytes(authError); + httpResponse.setHeader("Content-Type", "application/json"); + + httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + servletResponse.getOutputStream().write(responseToSend); + return; + } else { + filterChain.doFilter(servletRequest, servletResponse); + } + } + } + + private byte[] restResponseBytes(AuthorizationError eErrorResponse) throws IOException { + String serialized = new ObjectMapper().writeValueAsString(eErrorResponse); + return serialized.getBytes(); + } +} + diff --git a/music-rest/src/main/java/org/onap/music/conductor/conditionals/JsonConditional.java b/music-rest/src/main/java/org/onap/music/conductor/conditionals/JsonConditional.java new file mode 100644 index 00000000..4efcabea --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/conductor/conditionals/JsonConditional.java @@ -0,0 +1,90 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.conductor.conditionals; + +import java.io.Serializable; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import io.swagger.annotations.ApiModel; + +@ApiModel(value = "JsonConditional", description = "Json model for insert or update into table based on some conditions") +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonConditional implements Serializable { + + private String primaryKey; + private String primaryKeyValue; + private String casscadeColumnName; + private Map<String,Object> tableValues; + private Map<String,Object> casscadeColumnData; + private Map<String,Map<String,String>> conditions; + + public Map<String, Object> getTableValues() { + return tableValues; + } + public void setTableValues(Map<String, Object> tableValues) { + this.tableValues = tableValues; + } + + public String getPrimaryKey() { + return primaryKey; + } + public String getPrimaryKeyValue() { + return primaryKeyValue; + } + public String getCasscadeColumnName() { + return casscadeColumnName; + } + + public Map<String, Object> getCasscadeColumnData() { + return casscadeColumnData; + } + + + + public void setPrimaryKey(String primaryKey) { + this.primaryKey = primaryKey; + } + public void setPrimaryKeyValue(String primaryKeyValue) { + this.primaryKeyValue = primaryKeyValue; + } + public Map<String, Map<String, String>> getConditions() { + return conditions; + } + public void setConditions(Map<String, Map<String, String>> conditions) { + this.conditions = conditions; + } + public void setCasscadeColumnName(String casscadeColumnName) { + this.casscadeColumnName = casscadeColumnName; + } + + public void setCasscadeColumnData(Map<String, Object> casscadeColumnData) { + this.casscadeColumnData = casscadeColumnData; + } + + + + + +}
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/conductor/conditionals/MusicConditional.java b/music-rest/src/main/java/org/onap/music/conductor/conditionals/MusicConditional.java new file mode 100644 index 00000000..2c69c435 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/conductor/conditionals/MusicConditional.java @@ -0,0 +1,391 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (C) 2019 IBM. + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.conductor.conditionals; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +import org.codehaus.jettison.json.JSONObject; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.main.ReturnType; +import org.onap.music.rest.RestMusicDataAPI; + +import com.datastax.driver.core.ColumnDefinitions; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.TableMetadata; + +public class MusicConditional { + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicDataAPI.class); + + public static ReturnType conditionalInsert(String keyspace, String tablename, String casscadeColumnName, + Map<String, Object> casscadeColumnData, String primaryKey, Map<String, Object> valuesMap, + Map<String, String> status) throws Exception { + + Map<String, PreparedQueryObject> queryBank = new HashMap<>(); + TableMetadata tableInfo = null; + tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename); + DataType primaryIdType = tableInfo.getPrimaryKey().get(0).getType(); + String primaryId = tableInfo.getPrimaryKey().get(0).getName(); + DataType casscadeColumnType = tableInfo.getColumn(casscadeColumnName).getType(); + String vector = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + + PreparedQueryObject select = new PreparedQueryObject(); + select.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + " where " + primaryId + " = ?"); + select.addValue(MusicUtil.convertToActualDataType(primaryIdType, primaryKey)); + queryBank.put(MusicUtil.SELECT, select); + + PreparedQueryObject update = new PreparedQueryObject(); + //casscade column values + Map<String, String> updateColumnvalues = getValues(true, casscadeColumnData, status); + Object formatedValues = MusicUtil.convertToActualDataType(casscadeColumnType, updateColumnvalues); + update.appendQueryString("UPDATE " + keyspace + "." + tablename + " SET " + casscadeColumnName + " =" + + casscadeColumnName + " + ? , vector_ts = ?" + " WHERE " + primaryId + " = ? "); + update.addValue(formatedValues); + update.addValue(MusicUtil.convertToActualDataType(DataType.text(), vector)); + update.addValue(MusicUtil.convertToActualDataType(primaryIdType, primaryKey)); + queryBank.put(MusicUtil.UPDATE, update); + + + //casscade column values + Map<String, String> insertColumnvalues = getValues(false, casscadeColumnData, status); + formatedValues = MusicUtil.convertToActualDataType(casscadeColumnType, insertColumnvalues); + PreparedQueryObject insert = extractQuery(valuesMap, tableInfo, tablename, keyspace, primaryId, primaryKey,casscadeColumnName,formatedValues); + queryBank.put(MusicUtil.INSERT, insert); + + + String key = keyspace + "." + tablename + "." + primaryKey; + String lockId; + try { + lockId = MusicCore.createLockReferenceAtomic(key); + } catch (MusicLockingException e) { + return new ReturnType(ResultType.FAILURE, e.getMessage()); + } + long leasePeriod = MusicUtil.getDefaultLockLeasePeriod(); + ReturnType lockAcqResult = MusicCore.acquireLockWithLease(key, lockId, leasePeriod); + + try { + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + ReturnType criticalPutResult = conditionalInsertAtomic(lockId, keyspace, tablename, primaryKey, + queryBank); + MusicCore.destroyLockRef(lockId); + if (criticalPutResult.getMessage().contains("insert")) + criticalPutResult + .setMessage("Insert values: "); + else if (criticalPutResult.getMessage().contains("update")) + criticalPutResult + .setMessage("Update values: " + updateColumnvalues); + return criticalPutResult; + + } else { + MusicCore.destroyLockRef(lockId); + return lockAcqResult; + } + } catch (Exception e) { + logger.error(EELFLoggerDelegate.applicationLogger, e); + MusicCore.destroyLockRef(lockId); + return new ReturnType(ResultType.FAILURE, e.getMessage()); + } + + } + + public static ReturnType conditionalInsertAtomic(String lockId, String keyspace, String tableName, + String primaryKey, Map<String, PreparedQueryObject> queryBank) { + + ResultSet results = null; + + try { + String fullyQualifiedKey = keyspace + "." + tableName + "." + primaryKey; + ReturnType lockAcqResult = MusicCore.acquireLock(fullyQualifiedKey, lockId); + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + try { + results = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(queryBank.get(MusicUtil.SELECT)); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.applicationLogger, e); + return new ReturnType(ResultType.FAILURE, e.getMessage()); + } + if (results.all().isEmpty()) { + PreparedQueryObject qObject = queryBank.get(MusicUtil.INSERT); + qObject.setOperation(MusicUtil.INSERT); + logger.info(EELFLoggerDelegate.debugLogger,"### Conditional Insert"); + MusicCore.criticalPut(keyspace, tableName, primaryKey, qObject, lockId, null); + //MusicDataStoreHandle.getDSHandle().executePut(queryBank.get(MusicUtil.INSERT), "critical"); + return new ReturnType(ResultType.SUCCESS, MusicUtil.INSERT); + + } else { + PreparedQueryObject qObject = queryBank.get(MusicUtil.UPDATE); + qObject.setOperation(MusicUtil.UPDATE); + logger.info(EELFLoggerDelegate.debugLogger,"### Condition Update"); + MusicCore.criticalPut(keyspace, tableName, primaryKey, qObject, lockId, null); + //MusicDataStoreHandle.getDSHandle().executePut(queryBank.get(MusicUtil.UPDATE), "critical"); + return new ReturnType(ResultType.SUCCESS, MusicUtil.UPDATE); + } + } else { + return new ReturnType(ResultType.FAILURE, + "Cannot perform operation since you are the not the lock holder"); + } + + } catch (Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + String exceptionAsString = sw.toString(); + logger.error(EELFLoggerDelegate.applicationLogger, e); + return new ReturnType(ResultType.FAILURE, + "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n" + + exceptionAsString); + } + + } + + public static ReturnType update(UpdateDataObject dataObj) + throws MusicLockingException, MusicQueryException, MusicServiceException { + + String key = dataObj.getKeyspace() + "." + dataObj.getTableName() + "." + dataObj.getPrimaryKeyValue(); + String lockId = MusicCore.createLockReferenceAtomic(key); + long leasePeriod = MusicUtil.getDefaultLockLeasePeriod(); + ReturnType lockAcqResult = MusicCore.acquireLockWithLease(key, lockId, leasePeriod); + + try { + + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + ReturnType criticalPutResult = updateAtomic(new UpdateDataObject().setLockId(lockId) + .setKeyspace(dataObj.getKeyspace()) + .setTableName( dataObj.getTableName()) + .setPrimaryKey(dataObj.getPrimaryKey()) + .setPrimaryKeyValue(dataObj.getPrimaryKeyValue()) + .setQueryBank(dataObj.getQueryBank()) + .setPlanId(dataObj.getPlanId()) + .setCascadeColumnValues(dataObj.getCascadeColumnValues()) + .setCascadeColumnName(dataObj.getCascadeColumnName())); + + MusicCore.destroyLockRef(lockId); + return criticalPutResult; + } else { + MusicCore.destroyLockRef(lockId); + return lockAcqResult; + } + + } catch (Exception e) { + MusicCore.destroyLockRef(lockId); + logger.error(EELFLoggerDelegate.applicationLogger, e); + return new ReturnType(ResultType.FAILURE, e.getMessage()); + + } + } + + public static ReturnType updateAtomic(UpdateDataObject dataObj) { + try { + String fullyQualifiedKey = dataObj.getKeyspace() + "." + dataObj.getTableName() + "." + dataObj.getPrimaryKeyValue(); + ReturnType lockAcqResult = MusicCore.acquireLock(fullyQualifiedKey, dataObj.getLockId()); + + if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) { + Row row = MusicDataStoreHandle.getDSHandle().executeQuorumConsistencyGet(dataObj.getQueryBank().get(MusicUtil.SELECT)).one(); + + if(row != null) { + Map<String, String> updatedValues = cascadeColumnUpdateSpecific(row, dataObj.getCascadeColumnValues(), dataObj.getCascadeColumnName(), dataObj.getPlanId()); + JSONObject json = new JSONObject(updatedValues); + PreparedQueryObject update = new PreparedQueryObject(); + String vector_ts = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + update.appendQueryString("UPDATE " + dataObj.getKeyspace() + "." + dataObj.getTableName() + " SET " + + dataObj.getCascadeColumnName() + "['" + dataObj.getPlanId() + + "'] = ?, vector_ts = ? WHERE " + dataObj.getPrimaryKey() + " = ?"); + update.addValue(MusicUtil.convertToActualDataType(DataType.text(), json.toString())); + update.addValue(MusicUtil.convertToActualDataType(DataType.text(), vector_ts)); + update.addValue(MusicUtil.convertToActualDataType(DataType.text(), dataObj.getPrimaryKeyValue())); + try { + update.setOperation(MusicUtil.UPDATE); + MusicCore.criticalPut(dataObj.keyspace, dataObj.tableName, dataObj.primaryKeyValue, update, dataObj.lockId, null); + } catch (Exception ex) { + logger.error(EELFLoggerDelegate.applicationLogger, ex); + return new ReturnType(ResultType.FAILURE, ex.getMessage()); + } + }else { + return new ReturnType(ResultType.FAILURE,"Cannot find data related to key: "+dataObj.getPrimaryKey()); + } + PreparedQueryObject qObject = dataObj.getQueryBank().get(MusicUtil.UPSERT); + qObject.setOperation(MusicUtil.INSERT); + MusicCore.criticalPut(dataObj.keyspace, dataObj.tableName, dataObj.primaryKeyValue, qObject, dataObj.lockId, null); + return new ReturnType(ResultType.SUCCESS, "update success"); + } else { + return new ReturnType(ResultType.FAILURE, + "Cannot perform operation since you are the not the lock holder"); + } + + } catch (Exception e) { + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + String exceptionAsString = sw.toString(); + logger.error(EELFLoggerDelegate.applicationLogger, e); + return new ReturnType(ResultType.FAILURE, + "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n" + + exceptionAsString); + } + + } + + @SuppressWarnings("unchecked") + public static Map<String, String> getValues(boolean isExists, Map<String, Object> casscadeColumnData, + Map<String, String> status) { + + Map<String, String> returnMap = new HashMap<>(); + Object key = casscadeColumnData.get("key"); + String setStatus = ""; + Map<String, String> value = (Map<String, String>) casscadeColumnData.get("value"); + + if (isExists) + setStatus = status.get("exists"); + else + setStatus = status.get("nonexists"); + + value.put("status", setStatus); + JSONObject valueJson = new JSONObject(value); + returnMap.put(key.toString(), valueJson.toString()); + return returnMap; + + } + + public static PreparedQueryObject extractQuery(Map<String, Object> valuesMap, TableMetadata tableInfo, String tableName, + String keySpaceName,String primaryKeyName,String primaryKey,String casscadeColumn,Object casscadeColumnValues) throws Exception { + + PreparedQueryObject queryObject = new PreparedQueryObject(); + StringBuilder fieldsString = new StringBuilder("(vector_ts"+","); + StringBuilder valueString = new StringBuilder("(" + "?" + ","); + String vector = String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + String localPrimaryKey; + queryObject.addValue(vector); + if(casscadeColumn!=null && casscadeColumnValues!=null) { + fieldsString.append(casscadeColumn).append(" ,"); + valueString.append("?,"); + queryObject.addValue(casscadeColumnValues); + } + + int counter = 0; + for (Map.Entry<String, Object> entry : valuesMap.entrySet()) { + + fieldsString.append(entry.getKey()); + Object valueObj = entry.getValue(); + if (primaryKeyName.equals(entry.getKey())) { + localPrimaryKey = entry.getValue() + ""; + localPrimaryKey = localPrimaryKey.replace("'", "''"); + } + DataType colType = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + } catch(NullPointerException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage() +" Invalid column name : "+entry.getKey(), + AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR, ex); + } + + Object formattedValue = null; + try { + formattedValue = MusicUtil.convertToActualDataType(colType, valueObj); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e.getMessage(), e); + } + + valueString.append("?"); + queryObject.addValue(formattedValue); + + + if (counter == valuesMap.size() - 1) { + fieldsString.append(")"); + valueString.append(")"); + } else { + fieldsString.append(","); + valueString.append(","); + } + counter = counter + 1; + } + queryObject.appendQueryString("INSERT INTO " + keySpaceName + "." + tableName + " " + + fieldsString + " VALUES " + valueString + ";"); + return queryObject; + } + + public static Object getColValue(Row row, String colName, DataType colType) { + switch (colType.getName()) { + case VARCHAR: + return row.getString(colName); + case UUID: + return row.getUUID(colName); + case VARINT: + return row.getVarint(colName); + case BIGINT: + return row.getLong(colName); + case INT: + return row.getInt(colName); + case FLOAT: + return row.getFloat(colName); + case DOUBLE: + return row.getDouble(colName); + case BOOLEAN: + return row.getBool(colName); + case MAP: + return row.getMap(colName, String.class, String.class); + default: + return null; + } + } + + @SuppressWarnings("unchecked") + public static Map<String, String> cascadeColumnUpdateSpecific(Row row, Map<String, String> changeOfStatus, + String cascadeColumnName, String planId) { + + ColumnDefinitions colInfo = row.getColumnDefinitions(); + DataType colType = colInfo.getType(cascadeColumnName); + Object columnValue = getColValue(row, cascadeColumnName, colType); + + Map<String, String> finalValues = new HashMap<>(); + Map<String, String> values = (Map<String, String>) columnValue; + if (values != null && values.keySet().contains(planId)) { + String valueString = values.get(planId); + String tempValueString = valueString.replaceAll("\\{", "").replaceAll("\"", "").replaceAll("\\}", ""); + String[] elements = tempValueString.split(","); + for (String str : elements) { + String[] keyValue = str.split(":"); + if ((changeOfStatus.keySet().contains(keyValue[0].replaceAll("\\s", "")))) + keyValue[1] = changeOfStatus.get(keyValue[0].replaceAll("\\s", "")); + finalValues.put(keyValue[0], keyValue[1]); + } + } + return finalValues; + + } + +} diff --git a/music-rest/src/main/java/org/onap/music/conductor/conditionals/RestMusicConditionalAPI.java b/music-rest/src/main/java/org/onap/music/conductor/conditionals/RestMusicConditionalAPI.java new file mode 100644 index 00000000..584a9e47 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/conductor/conditionals/RestMusicConditionalAPI.java @@ -0,0 +1,205 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2018 IBM + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.conductor.conditionals; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.main.ReturnType; +import org.onap.music.response.jsonobjects.JsonResponse; +import org.onap.music.conductor.*; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.TableMetadata; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiParam; + +@Path("/v2/conditional") +@Api(value = "Conditional Api", hidden = true) +public class RestMusicConditionalAPI { + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicConditionalAPI.class); + private static final String XMINORVERSION = "X-minorVersion"; + private static final String XPATCHVERSION = "X-patchVersion"; + private static final String NS = "ns"; + private static final String VERSION = "v2"; + + @POST + @Path("/insert/keyspaces/{keyspace}/tables/{tablename}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response insertConditional( + @ApiParam(value = "Major Version", required = true) + @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) + @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version", required = false) + @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = true) + @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) + @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) + @HeaderParam("Authorization") String authorization, + @ApiParam(value = "Keyspace Name", required = true) + @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) + @PathParam("tablename") String tablename, + JsonConditional jsonObj) throws Exception { + ResponseBuilder response = + MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + String primaryKey = jsonObj.getPrimaryKey(); + String primaryKeyValue = jsonObj.getPrimaryKeyValue(); + String casscadeColumnName = jsonObj.getCasscadeColumnName(); + Map<String, Object> tableValues = jsonObj.getTableValues(); + Map<String, Object> casscadeColumnData = jsonObj.getCasscadeColumnData(); + Map<String, Map<String, String>> conditions = jsonObj.getConditions(); + + if (primaryKey == null || primaryKeyValue == null || casscadeColumnName == null + || tableValues.isEmpty() || casscadeColumnData.isEmpty() || conditions.isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO, ErrorSeverity.CRITICAL, + ErrorTypes.AUTHENTICATIONERROR); + return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE) + .setError(String.valueOf("One or more input values missing")).toMap()).build(); + } + Map<String, Object> authMap = null; + Map<String, Object> valuesMap = new LinkedHashMap<>(); + for (Map.Entry<String, Object> entry : tableValues.entrySet()) { + valuesMap.put(entry.getKey(), entry.getValue()); + } + + Map<String, String> status = new HashMap<>(); + status.put("exists", conditions.get("exists").get("status")); + status.put("nonexists", conditions.get("nonexists").get("status")); + ReturnType out = null; + + out = MusicConditional.conditionalInsert(keyspace, tablename, + casscadeColumnName, casscadeColumnData,primaryKeyValue, valuesMap, status); + return response.status(Status.OK).entity(new JsonResponse( + out.getResult()).setMessage(out.getMessage()).toMap()) + .build(); + + } + + @SuppressWarnings("unchecked") + @PUT + @Path("/update/keyspaces/{keyspace}/tables/{tablename}") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateConditional( + @ApiParam(value = "Major Version", required = true) + @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) + @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version", required = false) + @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = true) + @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) + @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) + @HeaderParam("Authorization") String authorization, + @ApiParam(value = "Major Version", required = true) + @PathParam("keyspace") String keyspace, + @ApiParam(value = "Major Version", required = true) + @PathParam("tablename") String tablename, + JsonConditional upObj) throws Exception { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + + String primaryKey = upObj.getPrimaryKey(); + String primaryKeyValue = upObj.getPrimaryKeyValue(); + String casscadeColumnName = upObj.getCasscadeColumnName(); + Map<String, Object> casscadeColumnData = upObj.getCasscadeColumnData(); + Map<String, Object> tableValues = upObj.getTableValues(); + + if (primaryKey == null || primaryKeyValue == null || casscadeColumnName == null + || casscadeColumnData.isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGINFO, ErrorSeverity.CRITICAL, + ErrorTypes.AUTHENTICATIONERROR); + return response.status(Status.UNAUTHORIZED).entity(new JsonResponse(ResultType.FAILURE) + .setError(String.valueOf("One or more input values missing")).toMap()).build(); + + } + + Map<String,String> casscadeColumnValueMap = + (Map<String, String>) casscadeColumnData.get("value"); + TableMetadata tableInfo = null; + tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename); + DataType primaryIdType = tableInfo.getPrimaryKey().get(0).getType(); + String primaryId = tableInfo.getPrimaryKey().get(0).getName(); + + PreparedQueryObject select = new PreparedQueryObject(); + select.appendQueryString("SELECT * FROM " + keyspace + "." + + tablename + " where " + primaryId + " = ?"); + select.addValue(MusicUtil.convertToActualDataType(primaryIdType, primaryKeyValue)); + + PreparedQueryObject upsert = + MusicConditional.extractQuery(tableValues, tableInfo, tablename, + keyspace, primaryKey, primaryKeyValue, null, null); + Map<String,PreparedQueryObject> queryBank = new HashMap<>(); + queryBank.put(MusicUtil.SELECT, select); + queryBank.put(MusicUtil.UPSERT, upsert); + String planId = casscadeColumnData.get("key").toString(); + ReturnType result = MusicConditional.update(new UpdateDataObject().setQueryBank(queryBank) + .setKeyspace(keyspace) + .setTableName(tablename) + .setPrimaryKey(primaryKey) + .setPrimaryKeyValue(primaryKeyValue) + .setPlanId(planId) + .setCascadeColumnName(casscadeColumnName) + .setCascadeColumnValues(casscadeColumnValueMap)); + if (result.getResult() == ResultType.SUCCESS) { + return response.status(Status.OK) + .entity(new JsonResponse(result.getResult()) + .setMessage(result.getMessage()).toMap()).build(); + } + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(result.getResult()) + .setMessage(result.getMessage()).toMap()).build(); + + } + +}
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/conductor/conditionals/UpdateDataObject.java b/music-rest/src/main/java/org/onap/music/conductor/conditionals/UpdateDataObject.java new file mode 100644 index 00000000..1ea8994e --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/conductor/conditionals/UpdateDataObject.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Samsung Electronics Co., Ltd. All rights reserved. + * ================================================================================ + * Licensed 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.music.conductor.conditionals; + +import java.util.Map; +import org.onap.music.datastore.PreparedQueryObject; + +public class UpdateDataObject { + + Map<String, PreparedQueryObject> queryBank; + String keyspace; + String tableName; + String primaryKey; + String primaryKeyValue; + String planId; + String cascadeColumnName; + Map<String, String> cascadeColumnValues; + String lockId; + + public Map<String, PreparedQueryObject> getQueryBank() { + return queryBank; + } + + public UpdateDataObject setQueryBank(Map<String, PreparedQueryObject> queryBank) { + this.queryBank = queryBank; + return this; + } + + public String getKeyspace() { + return keyspace; + } + + public UpdateDataObject setKeyspace(String keyspace) { + this.keyspace = keyspace; + return this; + } + + public String getTableName() { + return tableName; + } + + public UpdateDataObject setTableName(String tableName) { + this.tableName = tableName; + return this; + } + + public String getPrimaryKey() { + return primaryKey; + } + + public UpdateDataObject setPrimaryKey(String primaryKey) { + this.primaryKey = primaryKey; + return this; + } + + public String getPrimaryKeyValue() { + return primaryKeyValue; + } + + public UpdateDataObject setPrimaryKeyValue(String primaryKeyValue) { + this.primaryKeyValue = primaryKeyValue; + return this; + } + + public String getPlanId() { + return planId; + } + + public UpdateDataObject setPlanId(String planId) { + this.planId = planId; + return this; + } + + public String getCascadeColumnName() { + return cascadeColumnName; + } + + public UpdateDataObject setCascadeColumnName(String cascadeColumnName) { + this.cascadeColumnName = cascadeColumnName; + return this; + } + + public Map<String, String> getCascadeColumnValues() { + return cascadeColumnValues; + } + + public UpdateDataObject setLockId(String lockId) { + this.lockId=lockId; + return this; + } + + public String getLockId() { + return lockId; + } + + public UpdateDataObject setCascadeColumnValues(Map<String, String> cascadeColumnValues) { + this.cascadeColumnValues = cascadeColumnValues; + return this; + } + + +} diff --git a/music-rest/src/main/java/org/onap/music/eelf/healthcheck/MusicHealthCheck.java b/music-rest/src/main/java/org/onap/music/eelf/healthcheck/MusicHealthCheck.java new file mode 100644 index 00000000..acbbdd18 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/eelf/healthcheck/MusicHealthCheck.java @@ -0,0 +1,138 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * + * Modifications Copyright (C) 2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.eelf.healthcheck; + +import java.util.UUID; + +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.main.MusicCore; + +import com.datastax.driver.core.ConsistencyLevel; + +/** + * @author inam + * + */ +public class MusicHealthCheck { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicUtil.class); + + private String cassandrHost; + + public String getCassandraStatus(String consistency) { + logger.info(EELFLoggerDelegate.applicationLogger, "Getting Status for Cassandra"); + + boolean result = false; + UUID randomUUID = UUID.randomUUID(); + try { + result = getAdminKeySpace(consistency, randomUUID); + } catch( Exception e) { + if(e.getMessage().toLowerCase().contains("unconfigured table healthcheck")) { + logger.error("Error", e); + logger.debug("Creating table...."); + try { + boolean ksresult = createKeyspace(); + if(ksresult) { + result = getAdminKeySpace(consistency, randomUUID); + } + } catch (MusicServiceException e1) { + logger.error(EELFLoggerDelegate.errorLogger, e1.getMessage(), AppMessages.UNKNOWNERROR, ErrorSeverity.ERROR, ErrorTypes.UNKNOWN, e1); + } catch (MusicQueryException e1) { + logger.error(EELFLoggerDelegate.errorLogger, e1.getMessage(), AppMessages.UNKNOWNERROR, ErrorSeverity.ERROR, ErrorTypes.UNKNOWN,e1); + } + } else { + logger.error("Error", e); + return "One or more nodes are down or not responding."; + } + } + try { + cleanHealthCheckId(randomUUID); + } catch (MusicServiceException | MusicQueryException e) { + logger.error("Error while cleaning healthcheck record id...", e); + } + if (result) { + return "ACTIVE"; + } else { + logger.info(EELFLoggerDelegate.applicationLogger, "Cassandra Service is not responding"); + return "INACTIVE"; + } + } + + private Boolean getAdminKeySpace(String consistency, UUID randomUUID) throws MusicServiceException,MusicQueryException { + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString("insert into admin.healthcheck (id) values (?)"); + pQuery.addValue(randomUUID); + ResultType rs = null; + rs = nonKeyRelatedPut(pQuery, consistency); + logger.info(rs.toString()); + return null != rs; + + } + + /*For unit testing purpose only*/ + public ResultType nonKeyRelatedPut(PreparedQueryObject pQuery, String consistency) throws MusicServiceException, MusicQueryException { + return MusicCore.nonKeyRelatedPut(pQuery, consistency); + } + + private void cleanHealthCheckId(UUID randomUUID) throws MusicServiceException, MusicQueryException { + String cleanQuery = "delete from admin.healthcheck where id = ?"; + PreparedQueryObject deleteQueryObject = new PreparedQueryObject(); + deleteQueryObject.appendQueryString(cleanQuery); + deleteQueryObject.addValue(randomUUID); + executeEventualPut(deleteQueryObject); + logger.info(EELFLoggerDelegate.applicationLogger, "Cassandra healthcheck responded and cleaned up."); + } + + /*For unit testing purpose only*/ + public void executeEventualPut(PreparedQueryObject deleteQueryObject) throws MusicServiceException, MusicQueryException { + MusicDataStoreHandle.getDSHandle().executePut(deleteQueryObject, "eventual"); + } + + private boolean createKeyspace() throws MusicServiceException,MusicQueryException { + PreparedQueryObject pQuery = new PreparedQueryObject(); + pQuery.appendQueryString("CREATE TABLE admin.healthcheck (id uuid PRIMARY KEY)"); + ResultType rs = null ; + rs = MusicCore.nonKeyRelatedPut(pQuery, ConsistencyLevel.ONE.toString()); + return rs != null && rs.getResult().toLowerCase().contains("success"); + } + + public String getCassandrHost() { + return cassandrHost; + } + + public void setCassandrHost(String cassandrHost) { + this.cassandrHost = cassandrHost; + } + +}
\ No newline at end of file diff --git a/music-rest/src/main/java/org/onap/music/eelf/logging/MusicContainerFilter.java b/music-rest/src/main/java/org/onap/music/eelf/logging/MusicContainerFilter.java new file mode 100644 index 00000000..bac02afa --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/eelf/logging/MusicContainerFilter.java @@ -0,0 +1,68 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.eelf.logging; + +import java.io.IOException; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; + +import org.springframework.stereotype.Component; + + +/** + * This filter filter/modifies outbound http responses just before sending back to client. + * + * @author sp931a + * + */ +@Component +public class MusicContainerFilter implements ContainerResponseFilter { + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicContainerFilter.class); + + public MusicContainerFilter() { + + } + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + if (null != EELFLoggerDelegate.mdcGet("transactionId")) { + EELFLoggerDelegate.mdcRemove("transactionId"); + } + + if (null != EELFLoggerDelegate.mdcGet("conversationId")) { + EELFLoggerDelegate.mdcRemove("conversationId"); + } + + if (null != EELFLoggerDelegate.mdcGet("clientId")) { + EELFLoggerDelegate.mdcRemove("clientId"); + } + + if (null != EELFLoggerDelegate.mdcGet("messageId")) { + EELFLoggerDelegate.mdcRemove("messageId"); + } + } + +} diff --git a/music-rest/src/main/java/org/onap/music/eelf/logging/MusicLoggingServletFilter.java b/music-rest/src/main/java/org/onap/music/eelf/logging/MusicLoggingServletFilter.java new file mode 100644 index 00000000..cda5b659 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/eelf/logging/MusicLoggingServletFilter.java @@ -0,0 +1,207 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.eelf.logging; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.onap.music.authentication.AuthorizationError; +import org.onap.music.main.MusicUtil; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * + * This is the first filter in the chain to be executed before cadi + * authentication. The priority has been set in <code>MusicApplication</code> + * through filter registration bean + * + * The responsibility of this filter is to validate header values as per + * contract and write it to MDC and http response header back. + * + * + * @author sp931a + * + */ + +public class MusicLoggingServletFilter implements Filter { + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicLoggingServletFilter.class); + // client transaction id, specific to client system, set in properties + public static final String CONVERSATION_ID = MusicUtil.getConversationIdPrefix() + "ConversationId"; + + // can be used as correlation-id in case of callback, also this can be passed to + // other services for tracking. + public static final String MESSAGE_ID = MusicUtil.getMessageIdPrefix() + "MessageId"; + + // client id would be the unique client source-system-id, i;e VALET or CONDUCTOR + // etc + public static final String CLIENT_ID = MusicUtil.getClientIdPrefix() + "ClientId"; + + // unique transaction of the source system + private static final String TRANSACTION_ID = MusicUtil.getTransIdPrefix() + "Transaction-Id"; + + public MusicLoggingServletFilter() throws ServletException { + super(); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + logger.info(EELFLoggerDelegate.securityLogger, + "In MusicLogginServletFilter doFilter start() :: [\"+MusicUtil.getTransIdRequired()+\",\"+MusicUtil.getConversationIdRequired()+\",\"+MusicUtil.getClientIdRequired()+\",\"+MusicUtil.getMessageIdRequired()"); + + HttpServletRequest httpRequest = null; + HttpServletResponse httpResponse = null; + Map<String, String> headerMap = null; + Map<String, String> upperCaseHeaderMap = null; + + if (null != request && null != response) { + httpRequest = (HttpServletRequest) request; + httpResponse = (HttpServletResponse) response; + + headerMap = getHeadersInfo(httpRequest); + + // The custom header values automatically converted into lower case, not sure + // why ? So i had to covert all keys to upper case + // The response header back to client will have all custom header values as + // upper case. + upperCaseHeaderMap = headerMap.entrySet().stream() + .collect(Collectors.toMap(entry -> entry.getKey().toUpperCase(), entry -> entry.getValue())); + // Enable/disable keys are present in /opt/app/music/etc/music.properties + + if (MusicUtil.getTransIdRequired() + && !upperCaseHeaderMap.containsKey(TRANSACTION_ID.toUpperCase())) { + populateError(httpResponse, "Transaction id '" + TRANSACTION_ID + + "' required on http header"); + return; + } else { + populateMDCAndResponseHeader(upperCaseHeaderMap, TRANSACTION_ID, "transactionId", + MusicUtil.getTransIdRequired(), httpResponse); + } + + if (MusicUtil.getConversationIdRequired() + && !upperCaseHeaderMap.containsKey(CONVERSATION_ID.toUpperCase())) { + populateError(httpResponse, "Conversation Id '" + CONVERSATION_ID + + "' required on http header"); + return; + } else { + populateMDCAndResponseHeader(upperCaseHeaderMap, CONVERSATION_ID, "conversationId", + MusicUtil.getConversationIdRequired(), httpResponse); + } + + if (MusicUtil.getMessageIdRequired() + && !upperCaseHeaderMap.containsKey(MESSAGE_ID.toUpperCase())) { + populateError(httpResponse, "Message Id '" + MESSAGE_ID + + "' required on http header"); + return; + } else { + populateMDCAndResponseHeader(upperCaseHeaderMap, MESSAGE_ID, "messageId", + MusicUtil.getMessageIdRequired(), httpResponse); + } + + if (MusicUtil.getClientIdRequired() + && !upperCaseHeaderMap.containsKey(CLIENT_ID.toUpperCase())) { + populateError(httpResponse, "Client Id '" + CLIENT_ID + + "' required on http header"); + return; + } else { + populateMDCAndResponseHeader(upperCaseHeaderMap, CLIENT_ID, "clientId", + MusicUtil.getClientIdRequired(), httpResponse); + } + + } + + logger.info(EELFLoggerDelegate.securityLogger, + "In MusicLogginServletFilter doFilter. Header values validated sucessfully"); + + chain.doFilter(request, response); + } + + private void populateError(HttpServletResponse httpResponse, String errMsg) throws IOException { + AuthorizationError authError = new AuthorizationError(); + authError.setResponseCode(HttpServletResponse.SC_BAD_REQUEST); + authError.setResponseMessage(errMsg); + + byte[] responseToSend = restResponseBytes(authError); + httpResponse.setHeader("Content-Type", "application/json"); + + // ideally the http response code should be 200, as this is a biz validation + // failure. For now, keeping it consistent with other places. + httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); + httpResponse.getOutputStream().write(responseToSend); + } + + private void populateMDCAndResponseHeader(Map<String, String> headerMap, String idKey, String mdcKey, + boolean isRequired, HttpServletResponse httpResponse) { + + idKey = idKey.trim().toUpperCase(); + + // 1. setting the keys & value in MDC for future use 2.setting the values in + // http response header back to client. + if (isRequired && (headerMap.containsKey(idKey))) { + EELFLoggerDelegate.mdcPut(mdcKey, headerMap.get(idKey)); + httpResponse.addHeader(idKey, headerMap.get(idKey)); + } else { + // do nothing + } + } + + private Map<String, String> getHeadersInfo(HttpServletRequest request) { + + Map<String, String> map = new HashMap<String, String>(); + + Enumeration<String> headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String key = (String) headerNames.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + + return map; + } + + private byte[] restResponseBytes(AuthorizationError eErrorResponse) throws IOException { + String serialized = new ObjectMapper().writeValueAsString(eErrorResponse); + return serialized.getBytes(); + } +} diff --git a/music-rest/src/main/java/org/onap/music/exceptions/MusicAuthenticationException.java b/music-rest/src/main/java/org/onap/music/exceptions/MusicAuthenticationException.java new file mode 100644 index 00000000..ab44fd6e --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/exceptions/MusicAuthenticationException.java @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.exceptions; + +/** + * @author inam + * + */ +public class MusicAuthenticationException extends Exception { + + /** + * + */ + public MusicAuthenticationException() { + + } + + /** + * @param message + */ + public MusicAuthenticationException(String message) { + super(message); + + } + + /** + * @param cause + */ + public MusicAuthenticationException(Throwable cause) { + super(cause); + + } + + /** + * @param message + * @param cause + */ + public MusicAuthenticationException(String message, Throwable cause) { + super(message, cause); + + } + + /** + * @param message + * @param cause + * @param enableSuppression + * @param writableStackTrace + */ + public MusicAuthenticationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + + } + +} diff --git a/music-rest/src/main/java/org/onap/music/exceptions/MusicExceptionMapper.java b/music-rest/src/main/java/org/onap/music/exceptions/MusicExceptionMapper.java new file mode 100644 index 00000000..c31fcf73 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/exceptions/MusicExceptionMapper.java @@ -0,0 +1,56 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.exceptions; + +import java.io.EOFException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import org.codehaus.jackson.map.exc.UnrecognizedPropertyException; +import org.onap.music.main.ResultType; +import org.onap.music.response.jsonobjects.JsonResponse; + +@Provider +public class MusicExceptionMapper implements ExceptionMapper<Exception> { + @Override + public Response toResponse(Exception exception) { + if(exception instanceof UnrecognizedPropertyException) { + return Response.status(Response.Status.BAD_REQUEST). + entity(new JsonResponse(ResultType.FAILURE).setError("Unknown field :"+((UnrecognizedPropertyException) exception).getUnrecognizedPropertyName()).toMap()). + build(); + } else if(exception instanceof EOFException) { + return Response.status(Response.Status.BAD_REQUEST). + entity(new JsonResponse(ResultType.FAILURE).setError("Request body cannot be empty").toMap()). + build(); + } else if(exception instanceof NullPointerException) { + return Response.status(Response.Status.BAD_REQUEST). + entity(new JsonResponse(ResultType.FAILURE).setError("NullPointerException - Please check to make sure all inputs are valid.").toMap()). + build(); + } else { + return Response.status(Response.Status.BAD_REQUEST). + entity(new JsonResponse(ResultType.FAILURE).setError(exception.getMessage()).toMap()). + build(); + } + } +} diff --git a/music-rest/src/main/java/org/onap/music/main/PropertiesLoader.java b/music-rest/src/main/java/org/onap/music/main/PropertiesLoader.java new file mode 100644 index 00000000..11dc51dd --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/main/PropertiesLoader.java @@ -0,0 +1,373 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.main; + +import java.util.HashSet; +import java.util.Properties; + +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.stereotype.Component; + +@PropertySource(value = {"file:/opt/app/music/etc/music.properties", "classpath:/project.properties"}) +//"file:/opt/app/music/etc/key.properties" +@Component +public class PropertiesLoader implements InitializingBean { + + @Value("${cassandra.host}") + public String cassandraHost; + + @Value("${debug}") + public String debug; + + @Value("${version}") + public String version; + + @Value("${build}") + public String build; + + @Value("${music.properties}") + public String musicProperties; + + @Value("${lock.lease.period}") + public String lockLeasePeriod; + + @Value("${cassandra.user}") + public String cassandraUser; + + @Value("${cassandra.password}") + public String cassandraPassword; + + @Value("${cassandra.port}") + public String cassandraPort; + + @Value("${cassandra.connecttimeoutms}") + public String cassandraConnectTimeOutMS; + + @Value("${cassandra.readtimeoutms}") + public String cassandraReadTimeOutMS; + + @Value("${cadi}") + public String isCadi; + + @Value("${keyspace.active}") + public String isKeyspaceActive; + + @Value("${retry.count}") + public String rertryCount; + + @Value("${lock.daemon.sleeptime.ms}") + public String lockDaemonSleeptimems; + + @Value("${keyspaces.for.lock.cleanup}") + public String keyspacesForLockCleanup; + + @Value("${create.lock.wait.period.ms}") + private long createLockWaitPeriod; + + @Value("${create.lock.wait.increment.ms}") + private int createLockWaitIncrement; + + @Value("${transId.header.prefix}") + private String transIdPrefix; + + @Value("${conversation.header.prefix}") + private String conversationIdPrefix; + + @Value("${clientId.header.prefix}") + private String clientIdPrefix; + + @Value("${messageId.header.prefix}") + private String messageIdPrefix; + + @Value("${transId.header.required}") + private Boolean transIdRequired; + + @Value("${conversation.header.required}") + private Boolean conversationIdRequired; + + @Value("${clientId.header.required}") + private Boolean clientIdRequired; + + @Value("${messageId.header.required}") + private Boolean messageIdRequired; + + @Value("${music.aaf.ns}") + private String musicAafNs; + + @Value("${cipher.enc.key:}") + private String cipherEncKey; + + @SuppressWarnings("unused") + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(PropertiesLoader.class); + + @Bean + public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() { + + PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); + pspc.setIgnoreResourceNotFound(true); + pspc.setIgnoreUnresolvablePlaceholders(true); + return pspc; + } + + /** + * . + */ + public void loadProperties() { + if(cipherEncKey != null) { + MusicUtil.setCipherEncKey(cipherEncKey); + } + if (musicAafNs != null) { + MusicUtil.setMusicAafNs(musicAafNs); + } + if (cassandraPort != null && !cassandraPort.equals("${cassandra.port}")) { + MusicUtil.setCassandraPort(Integer.parseInt(cassandraPort)); + } + if (cassandraUser != null && !cassandraUser.equals("${cassandra.user}")) { + MusicUtil.setCassName(cassandraUser); + } + if (cassandraPassword != null && !cassandraPassword.equals("${cassandra.password}")) { + MusicUtil.setCassPwd(cassandraPassword); + } + if (cassandraConnectTimeOutMS != null && !cassandraConnectTimeOutMS.equals("${cassandra.connecttimeoutms}")) { + MusicUtil.setCassandraConnectTimeOutMS(Integer.parseInt(cassandraConnectTimeOutMS)); + } + if (cassandraReadTimeOutMS != null && !cassandraReadTimeOutMS.equals("${cassandra.readtimeoutms}")) { + MusicUtil.setCassandraReadTimeOutMS(Integer.parseInt(cassandraReadTimeOutMS)); + } + if (debug != null && !debug.equals("${debug}")) { + MusicUtil.setDebug(Boolean.parseBoolean(debug)); + } + if (lockLeasePeriod != null && !lockLeasePeriod.equals("${lock.lease.period}")) { + MusicUtil.setDefaultLockLeasePeriod(Long.parseLong(lockLeasePeriod)); + } + if (musicProperties != null && !musicProperties.equals("${music.properties}")) { + MusicUtil.setMusicPropertiesFilePath(musicProperties); + } + if (cassandraHost != null && !cassandraHost.equals("${cassandra.host}")) { + MusicUtil.setMyCassaHost(cassandraHost); + } + if (version != null && !version.equals("${version}")) { + MusicUtil.setVersion(version); + } + if (build != null && !version.equals("${build}")) { + MusicUtil.setBuild(build); + } + if (isCadi != null && !isCadi.equals("${cadi}")) { + MusicUtil.setIsCadi(Boolean.parseBoolean(isCadi)); + } + if (rertryCount != null && !rertryCount.equals("${retry.count}")) { + MusicUtil.setRetryCount(Integer.parseInt(rertryCount)); + } + if (isKeyspaceActive != null && !isKeyspaceActive.equals("${keyspace.active}")) { + MusicUtil.setKeyspaceActive(Boolean.parseBoolean(isKeyspaceActive)); + } + if (lockDaemonSleeptimems != null && !lockDaemonSleeptimems.equals("${lock.daemon.sleeptime.ms}")) { + MusicUtil.setLockDaemonSleepTimeMs(Long.parseLong(lockDaemonSleeptimems)); + } + if (keyspacesForLockCleanup !=null && !keyspacesForLockCleanup.equals("${keyspaces.for.lock.cleanup}")) { + HashSet<String> keyspaces = new HashSet<>(); + for (String keyspace: keyspacesForLockCleanup.split(",")) { + keyspaces.add(keyspace); + } + MusicUtil.setKeyspacesToCleanLocks(keyspaces); + } + if(transIdPrefix!=null) { + MusicUtil.setTransIdPrefix(transIdPrefix); + } + + if(conversationIdPrefix!=null) { + MusicUtil.setConversationIdPrefix(conversationIdPrefix); + } + + if(clientIdPrefix!=null) { + MusicUtil.setClientIdPrefix(clientIdPrefix); + } + + if(messageIdPrefix!=null) { + MusicUtil.setMessageIdPrefix(messageIdPrefix); + } + + if(transIdRequired!=null) { + MusicUtil.setTransIdRequired(transIdRequired); + } + + if(conversationIdRequired!=null) { + MusicUtil.setConversationIdRequired(conversationIdRequired); + } + + if(clientIdRequired!=null) { + MusicUtil.setClientIdRequired(clientIdRequired); + } + + if(messageIdRequired!=null) { + MusicUtil.setMessageIdRequired(messageIdRequired); + } + + if(createLockWaitPeriod!=0) { + MusicUtil.setCreateLockWaitPeriod(createLockWaitPeriod); + } + + if(createLockWaitIncrement!=0) { + MusicUtil.setCreateLockWaitIncrement(createLockWaitIncrement); + } + } + + public static void loadProperties(Properties properties) { + if (properties.getProperty("cassandra.host")!=null) { + MusicUtil.setMyCassaHost(properties.getProperty("cassandra.host")); + } + + if (properties.getProperty("cassandra.port")!=null) { + MusicUtil.setCassandraPort(Integer.parseInt(properties.getProperty("cassandra.port"))); + } + + if (properties.getProperty("cassandra.user")!=null) { + MusicUtil.setCassName(properties.getProperty("cassandra.user")); + } + + if (properties.getProperty("cassandra.password")!=null) { + MusicUtil.setCassPwd(properties.getProperty("cassandra.password")); + } + + if(properties.getProperty("cassandra.connectTimeOutMS")!=null) { + MusicUtil.setCassandraConnectTimeOutMS(Integer.parseInt(properties.getProperty("cassandra.connecttimeoutms"))); + } + + if(properties.getProperty("cassandra.readTimeOutMS")!=null) { + MusicUtil.setCassandraReadTimeOutMS(Integer.parseInt(properties.getProperty("cassandra.readtimeoutms"))); + } + + if (properties.getProperty("music.properties")!=null) { + MusicUtil.setMusicPropertiesFilePath(properties.getProperty("music.properties")); + } + + if (properties.getProperty("debug")!=null) { + MusicUtil.setDebug(Boolean.parseBoolean(properties.getProperty("debug"))); + } + + if (properties.getProperty("version")!=null) { + MusicUtil.setVersion(properties.getProperty("version")); + } + + if (properties.getProperty("build")!=null) { + MusicUtil.setBuild(properties.getProperty("build")); + } + + if (properties.getProperty("lock.lease.period")!=null) { + MusicUtil.setDefaultLockLeasePeriod(Long.parseLong(properties.getProperty("lock.lease.period"))); + } + + if (properties.getProperty("cadi")!=null) { + MusicUtil.setIsCadi(Boolean.parseBoolean(properties.getProperty("cadi"))); + } + + if (properties.getProperty("keyspace.active")!=null) { + MusicUtil.setKeyspaceActive(Boolean.parseBoolean(properties.getProperty("keyspace.active"))); + } + + if (properties.getProperty("retry.count")!=null) { + MusicUtil.setRetryCount(Integer.parseInt(properties.getProperty("retry.count"))); + } + + if (properties.getProperty("transId.header.prefix")!=null) { + MusicUtil.setTransIdPrefix(properties.getProperty("transId.header.prefix")); + } + + if (properties.getProperty("conversation.header.prefix")!=null) { + MusicUtil.setConversationIdPrefix(properties.getProperty("conversation.header.prefix")); + } + + if (properties.getProperty("clientId.header.prefix")!=null) { + MusicUtil.setClientIdPrefix(properties.getProperty("clientId.header.prefix")); + } + + if (properties.getProperty("messageId.header.prefix")!=null) { + MusicUtil.setMessageIdPrefix(properties.getProperty("messageId.header.prefix")); + } + + if (properties.getProperty("transId.header.required")!=null) { + MusicUtil.setTransIdRequired(Boolean.parseBoolean(properties.getProperty("transId.header.required"))); + } + + if (properties.getProperty("conversation.header.required")!=null) { + MusicUtil.setConversationIdRequired(Boolean.parseBoolean(properties.getProperty("conversation.header.required"))); + } + + if (properties.getProperty("clientId.header.required")!=null) { + MusicUtil.setClientIdRequired(Boolean.parseBoolean(properties.getProperty("clientId.header.required"))); + } + + if (properties.getProperty("messageId.header.required")!=null) { + MusicUtil.setMessageIdRequired(Boolean.parseBoolean(properties.getProperty("messageId.header.required"))); + } + + if (properties.getProperty("music.aaf.ns")!=null) { + MusicUtil.setMusicAafNs(properties.getProperty("music.aaf.ns")); + } + + if (properties.getProperty("cipher.enc.key")!=null) { + MusicUtil.setCipherEncKey(properties.getProperty("cipher.enc.key")); + } + + } + + @Override + public void afterPropertiesSet() throws Exception { + // TODO Auto-generated method stub + + } + + /* For unit testing purpose only*/ + protected void setProperties() { + cassandraHost = "127.0.0.1"; + debug = "true"; + version = "x.x.x"; + build = "y.y"; + musicProperties = "property"; + lockLeasePeriod = "5000"; + cassandraUser = "user"; + cassandraPassword = "password"; + cassandraPort = "8007"; + cassandraConnectTimeOutMS = "1000"; + cassandraReadTimeOutMS = "1000"; + isCadi = "true"; + isKeyspaceActive = "true"; + rertryCount = "20"; + transIdPrefix = "transId-"; + conversationIdPrefix = "conversation-"; + clientIdPrefix = "clientId-"; + messageIdPrefix = "messageId-"; + transIdRequired = true; + conversationIdRequired = true; + clientIdRequired = true; + messageIdRequired = true; + musicAafNs = "ns"; + cipherEncKey = "key"; + } + +} diff --git a/music-rest/src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java b/music-rest/src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java new file mode 100644 index 00000000..5ae49f5d --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java @@ -0,0 +1,322 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * + * Modifications Copyright (C) 2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.response.jsonobjects; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.onap.music.lockingservice.cassandra.MusicLockState.LockStatus; +import org.onap.music.main.ResultType; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@ApiModel(value = "JsonResponse", description = "General Response JSON") +public class JsonResponse { + + /* Status is required */ + private ResultType status; + + /* Standard informational fields */ + private String error; + private String message; + + /* versioning */ + private String musicVersion; + private String musicBuild; + + /* Data Fields */ + private Map<String, HashMap<String, Object>> dataResult; + + /* Locking fields */ + private String lock; + private LockStatus lockStatus; + private List<String> lockHolders; + private String lockLease; + private boolean isLockHolders=false; + + /** + * Create a JSONLock Response + * Use setters to provide more information as in + * JsonLockResponse(ResultType.SUCCESS).setMessage("We did it").setLock(mylockname) + * @param status + */ + public JsonResponse(ResultType status) { + this.status = status; + } + + public boolean isLockHolders() { + return isLockHolders; + } + + public JsonResponse setisLockHolders(boolean isLockHolders) { + this.isLockHolders = isLockHolders; + return this; + } + + /** + * + * @return + */ + @ApiModelProperty(value = "Overall status of the response.", + allowableValues = "Success,Failure") + public ResultType getStatus() { + return status; + } + + /** + * + * @param status + */ + public JsonResponse setStatus(ResultType status) { + this.status = status; + return this; + } + + /** + * + * @return the error + */ + @ApiModelProperty(value = "Error value") + public String getError() { + return error; + } + + /** + * + * @param error + */ + public JsonResponse setError(String error) { + this.error = error; + return this; + } + + /** + * + * @return the message + */ + @ApiModelProperty(value = "Message value") + public String getMessage() { + return message; + } + + /** + * + * @param message + */ + public JsonResponse setMessage(String message) { + this.message = message; + return this; + } + + + /** + * . + * @return the music version + */ + public String getMusicVersion() { + return this.musicVersion; + } + + /** + * . + * @param version of music + * @return + */ + public JsonResponse setMusicVersion(String version) { + this.musicVersion = version; + return this; + } + + /** + * . + * @return the music version + */ + public String getMusicBuild() { + return this.musicBuild; + } + + /** + * . + * @param build of music + * @return + */ + public JsonResponse setMusicBuild(String build) { + this.musicBuild = build; + return this; + } + + + public Map<String, HashMap<String, Object>> getDataResult() { + return this.dataResult; + } + + public JsonResponse setDataResult(Map<String, HashMap<String, Object>> map) { + this.dataResult = map; + return this; + } + + /** + * + * @return + */ + public String getLock() { + return lock; + } + + /** + * + * @param lock + */ + public JsonResponse setLock(String lock) { + this.lock = lock; + return this; + } + + /** + * + * @return the lockStatus + */ + @ApiModelProperty(value = "Status of the lock") + public LockStatus getLockStatus() { + return lockStatus; + } + + /** + * + * @param lockStatus + */ + public JsonResponse setLockStatus(LockStatus lockStatus) { + this.lockStatus = lockStatus; + return this; + } + + /** + * + * + * @return the lockHolder + */ + @ApiModelProperty(value = "Holder of the Lock") + public List<String> getLockHolder() { + return lockHolders; + } + + /** + * + * @param lockHolder + */ + public JsonResponse setLockHolder(String lockHolder) { + this.lockHolders = new ArrayList<String>(); + this.lockHolders.add(lockHolder); + return this; + } + + public JsonResponse setLockHolder(List<String> lockHolders) { + this.lockHolders = lockHolders; + return this; + } + + + /** + * @return the lockLease + */ + public String getLockLease() { + return lockLease; + } + + /** + * @param lockLease the lockLease to set + */ + public JsonResponse setLockLease(String lockLease) { + this.lockLease = lockLease; + return this; + } + + /** + * Convert to Map + * + * @return + */ + public Map<String, Object> toMap() { + Map<String, Object> fullMap = new HashMap<>(); + fullMap.put("status", status); + if (error != null && !"".equals(error)) { + fullMap.put("error", error); + } + if (message != null) { + fullMap.put("message", message); + } + + if (musicVersion != null) { + fullMap.put("version", musicVersion); + } + + if (musicBuild != null) { + fullMap.put("build", musicBuild); + } + + if (dataResult != null) { + fullMap.put("result", dataResult); + } + + if (lock != null) { + Map<String, Object> lockMap = new HashMap<>(); + if (lock != null) { + lockMap.put("lock", lock); + } + if (lockStatus != null) { + lockMap.put("lock-status", lockStatus); + } + if (lockHolders != null && !lockHolders.isEmpty()) { + if (lockHolders.size()==1 && !isLockHolders) { + //for backwards compatability + lockMap.put("lock-holder", lockHolders.get(0)); + } else { + lockMap.put("lock-holder", lockHolders); + } + } + if (lockLease != null) { + lockMap.put("lock-lease", lockLease); + } + fullMap.put("lock", lockMap); + } + + return fullMap; + } + + /** + * Convert to String + */ + @Override + public String toString() { + return "JsonLockResponse [status=" + status + ", error=" + error + ", message=" + message + + ", lock=" + lock + ", lockStatus=" + lockStatus + ", lockHolder=" + + lockHolders + "]"; + } + +} diff --git a/music-rest/src/main/java/org/onap/music/rest/Application.java b/music-rest/src/main/java/org/onap/music/rest/Application.java new file mode 100644 index 00000000..5375155b --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/Application.java @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +public class Application { + + private String application_name; + private String username; + private String password; + private String keyspace_name; + private boolean is_aaf; + private String uuid; + private boolean is_api; + + public String getApplication_name() { + return application_name; + } + public void setApplication_name(String application_name) { + this.application_name = application_name; + } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public String getKeyspace_name() { + return keyspace_name; + } + public void setKeyspace_name(String keyspace_name) { + this.keyspace_name = keyspace_name; + } + public boolean isIs_aaf() { + return is_aaf; + } + public void setIs_aaf(boolean is_aaf) { + this.is_aaf = is_aaf; + } + public String getUuid() { + return uuid; + } + public void setUuid(String uuid) { + this.uuid = uuid; + } + public boolean getIs_api() { + return is_api; + } + public void setIs_api(boolean is_api) { + this.is_api = is_api; + } + + +} diff --git a/music-rest/src/main/java/org/onap/music/rest/RestMusicDataAPI.java b/music-rest/src/main/java/org/onap/music/rest/RestMusicDataAPI.java new file mode 100755 index 00000000..756856d0 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/RestMusicDataAPI.java @@ -0,0 +1,1052 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * Modifications Copyright (C) 2019 IBM + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.datastore.jsonobjects.JsonDelete; +import org.onap.music.datastore.jsonobjects.JsonIndex; +import org.onap.music.datastore.jsonobjects.JsonInsert; +import org.onap.music.datastore.jsonobjects.JsonKeySpace; +import org.onap.music.datastore.jsonobjects.JsonSelect; +import org.onap.music.datastore.jsonobjects.JsonTable; +import org.onap.music.datastore.jsonobjects.JsonUpdate; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.main.ReturnType; +import org.onap.music.response.jsonobjects.JsonResponse; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.TableMetadata; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Example; +import io.swagger.annotations.ExampleProperty; + +/* Version 2 Class */ +//@Path("/v{version: [0-9]+}/keyspaces") +@Path("/v2/keyspaces") +@Api(value = "Data Api") +public class RestMusicDataAPI { + /* + * Header values for Versioning X-minorVersion *** - Used to request or communicate a MINOR + * version back from the client to the server, and from the server back to the client - This + * will be the MINOR version requested by the client, or the MINOR version of the last MAJOR + * version (if not specified by the client on the request) - Contains a single position value + * (e.g. if the full version is 1.24.5, X-minorVersion = "24") - Is optional for the client on + * request; however, this header should be provided if the client needs to take advantage of + * MINOR incremented version functionality - Is mandatory for the server on response + * + *** X-patchVersion *** - Used only to communicate a PATCH version in a response for + * troubleshooting purposes only, and will not be provided by the client on request - This will + * be the latest PATCH version of the MINOR requested by the client, or the latest PATCH version + * of the MAJOR (if not specified by the client on the request) - Contains a single position + * value (e.g. if the full version is 1.24.5, X-patchVersion = "5") - Is mandatory for the + * server on response (CURRENTLY NOT USED) + * + *** X-latestVersion *** - Used only to communicate an API's latest version - Is mandatory for the + * server on response, and shall include the entire version of the API (e.g. if the full version + * is 1.24.5, X-latestVersion = "1.24.5") - Used in the response to inform clients that they are + * not using the latest version of the API (CURRENTLY NOT USED) + * + */ + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicDataAPI.class); + private static final String XMINORVERSION = "X-minorVersion"; + private static final String XPATCHVERSION = "X-patchVersion"; + private static final String NS = "ns"; + private static final String VERSION = "v2"; + private static final String PARAMETER_ERROR = "Missing Row Identifier. Please provide the parameter of key=value for the row being selected."; + + + private class RowIdentifier { + public String primarKeyValue; + public StringBuilder rowIdString; + @SuppressWarnings("unused") + public PreparedQueryObject queryObject; // the string with all the row + // identifiers separated by AND + + public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString, + PreparedQueryObject queryObject) { + this.primarKeyValue = primaryKeyValue; + this.rowIdString = rowIdString; + this.queryObject = queryObject; + } + } + + + /** + * Create Keyspace REST + * + * @param kspObject + * @param keyspaceName + * @return + * @throws Exception + */ + @POST + @Path("/{name}") + @ApiOperation(value = "Create Keyspace", response = String.class, + notes = "This API will not work if MUSIC properties has keyspace.active=false ") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"message\" : \"Keysapce <keyspace> Created\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response createKeySpace( + @ApiParam(value = "Major Version",required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns, + JsonKeySpace kspObject, + @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) "); + logger.info(EELFLoggerDelegate.applicationLogger,"In Create Keyspace " + keyspaceName); + if (MusicUtil.isKeyspaceActive() ) { + logger.info(EELFLoggerDelegate.applicationLogger,"Creating Keyspace " + keyspaceName); + + if(kspObject == null || kspObject.getReplicationInfo() == null) { + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult()).toMap()).build(); + } + ResultType result = ResultType.FAILURE; + try { + kspObject.setKeyspaceName(keyspaceName); + result = MusicCore.createKeyspace(kspObject, MusicUtil.EVENTUAL); + logger.info(EELFLoggerDelegate.applicationLogger, "result = " + result); + } catch ( MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.QUERYERROR + ,ErrorSeverity.WARN, ErrorTypes.QUERYERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } catch ( MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Created").toMap()).build(); + } else { + String vError = "Keyspace Creation has been turned off. Contact DBA to create the keyspace or set keyspace.active to true."; + logger.info(EELFLoggerDelegate.applicationLogger,vError); + logger.error(EELFLoggerDelegate.errorLogger,vError, AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR); + return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(vError).toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + + } + + /** + * + * @param kspObject + * @param keyspaceName + * @return + * @throws Exception + */ + @DELETE + @Path("/{name}") + @ApiOperation(value = "Delete Keyspace", response = String.class, + notes = "This API will not work if MUSIC properties has keyspace.active=false ") + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"message\" : \"Keysapce <keyspace> Deleted\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response dropKeySpace( + @ApiParam(value = "Major Version",required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Keyspace Name",required = true) @PathParam("name") String keyspaceName) throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + logger.info(EELFLoggerDelegate.applicationLogger,"In Drop Keyspace " + keyspaceName); + if (MusicUtil.isKeyspaceActive()) { + String consistency = MusicUtil.EVENTUAL;// for now this needs only + String droperror = "Error Deleteing Keyspace " + keyspaceName; + JsonKeySpace kspObject = new JsonKeySpace(); + kspObject.setKeyspaceName(keyspaceName); + try{ + ResultType result = MusicCore.dropKeyspace(kspObject, consistency); + if ( result.equals(ResultType.FAILURE) ) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError(droperror).toMap()).build(); + } + } catch ( MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.QUERYERROR + ,ErrorSeverity.WARN, ErrorTypes.QUERYERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(droperror + " " + ex.getMessage()).toMap()).build(); + } catch ( MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR + ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(droperror + " " + ex.getMessage()).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("Keyspace " + keyspaceName + " Deleted").toMap()).build(); + } else { + String vError = "Keyspace deletion has been turned off. Contact DBA to delete the keyspace or set keyspace.active to true."; + logger.info(EELFLoggerDelegate.applicationLogger,vError); + logger.error(EELFLoggerDelegate.errorLogger,vError, AppMessages.UNKNOWNERROR,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR); + return response.status(Response.Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(vError).toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param tableObj + * @param version + * @param keyspace + * @param tablename + * @param headers + * @return + * @throws Exception - + */ + @POST + @Path("/{keyspace: .*}/tables/{tablename: .*}") + @ApiOperation(value = "Create Table", response = String.class, + notes = "Create a table with the required json in the body.") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"message\" : \"Tablename <tablename> Created under keyspace <keyspace>\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response createTable( + @ApiParam(value = "Major Version",required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonTable tableObj, + @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename) throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if ( null == tableObj ) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError(ResultType.BODYMISSING.getResult()).toMap()).build(); + } + if(keyspace == null || keyspace.isEmpty() || tablename == null || tablename.isEmpty()){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("One or more path parameters are not set, please check and try again." + + "Parameter values: keyspace='" + keyspace + "' tablename='" + tablename + "'") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) "); + String consistency = MusicUtil.EVENTUAL; + // for now this needs only eventual consistency + ResultType result = ResultType.FAILURE; + try { + tableObj.setKeyspaceName(keyspace); + tableObj.setTableName(tablename); + result = MusicCore.createTable(tableObj, consistency); + } catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), ex.getMessage() ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.MUSICSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + if ( result.equals(ResultType.FAILURE) ) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Error Creating Table " + tablename).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setMessage("TableName " + tablename.trim() + " Created under keyspace " + keyspace.trim()).toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param keyspace + * @param tablename + * @param fieldName + * @param info + * @throws Exception + */ + @POST + @Path("/{keyspace: .*}/tables/{tablename: .*}/index/{field: .*}") + @ApiOperation(value = "Create Index", response = String.class, + notes = "An index provides a means to access data using attributes " + + "other than the partition key. The benefit is fast, efficient lookup " + + "of data matching a given condition.") + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"message\" : \"Index Created on <keyspace>.<table>.<field>\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unknown Error in create index.\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response createIndex( + @ApiParam(value = "Major Version",required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Keyspace Name",required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name",required = true) @PathParam("tablename") String tablename, + @ApiParam(value = "Field Name",required = true) @PathParam("field") String fieldName, + @Context UriInfo info) throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if ((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty()) || (fieldName == null || fieldName.isEmpty())){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) "); + MultivaluedMap<String, String> rowParams = info.getQueryParameters(); + String indexName = ""; + if (rowParams.getFirst("index_name") != null) + indexName = rowParams.getFirst("index_name"); + + JsonIndex jsonIndexObject = new JsonIndex(indexName, keyspace, tablename, fieldName); + + ResultType result = ResultType.FAILURE; + try { + result = MusicCore.createIndex(jsonIndexObject, MusicUtil.EVENTUAL); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity + .CRITICAL, ErrorTypes.GENERALSERVICEERROR, ex); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + if ( result.equals(ResultType.SUCCESS) ) { + return response.status(Status.OK).entity(new JsonResponse(result).setMessage("Index Created on " + keyspace+"."+tablename+"."+fieldName).toMap()).build(); + } else { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result).setError("Unknown Error in create index.").toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param insObj + * @param keyspace + * @param tablename + * @return + * @throws Exception + */ + @POST + @Path("/{keyspace: .*}/tables/{tablename: .*}/rows") + @ApiOperation(value = "Insert Into Table", response = String.class, + notes = "Insert into table with data in json body.") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"message\" : \"Insert Successful\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure - Generic",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response insertIntoTable( + @ApiParam(value = "Major Version",required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonInsert insObj, + @ApiParam(value = "Keyspace Name", + required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", + required = true) @PathParam("tablename") String tablename) { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if ( null == insObj ) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError(ResultType.BODYMISSING.getResult()).toMap()).build(); + } + if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace","(" + keyspace + ")"); + ReturnType result = null; + String consistency = insObj.getConsistencyInfo().get("type"); + try { + insObj.setKeyspaceName(keyspace); + insObj.setTableName(tablename); + if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) { + String lockId = insObj.getConsistencyInfo().get("lockId"); + if(lockId == null) { + logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or" + + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock " + + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build(); + } + } + result = MusicCore.insertIntoTable(insObj); + }catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), ex.getMessage() ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + }catch (Exception ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + if (result==null) { + logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.MUSICSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build(); + }else if(result.getResult() == ResultType.FAILURE) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(result.getResult()).setError(result.getMessage()).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(result.getResult()).setMessage("Insert Successful").toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param insObj + * @param keyspace + * @param tablename + * @param info + * @return + * @throws MusicServiceException + * @throws MusicQueryException + * @throws Exception + */ + @PUT + @Path("/{keyspace: .*}/tables/{tablename: .*}/rows") + @ApiOperation(value = "Update Table", response = String.class, + notes = "Update the table with the data in the JSON body.") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateTable( + @ApiParam(value = "Major Version", + required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", + required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version", + required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonUpdate updateObj, + @ApiParam(value = "Keyspace Name", + required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", + required = true) @PathParam("tablename") String tablename, + @Context UriInfo info) throws MusicQueryException, MusicServiceException { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if ( null == updateObj ) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError(ResultType.BODYMISSING.getResult()).toMap()).build(); + } + if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) "); + long startTime = System.currentTimeMillis(); + String operationId = UUID.randomUUID().toString(); // just for infoging + // purposes. + String consistency = updateObj.getConsistencyInfo().get("type"); + ReturnType operationResult = null; + logger.info(EELFLoggerDelegate.applicationLogger, "--------------Music " + consistency + + " update-" + operationId + "-------------------------"); + + updateObj.setKeyspaceName(keyspace); + updateObj.setTableName(tablename); + + try { + if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) { + String lockId = updateObj.getConsistencyInfo().get("lockId"); + if(lockId == null) { + logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or" + + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock " + + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build(); + } + } + operationResult = MusicCore.updateTable(updateObj,info.getQueryParameters()); + }catch (MusicLockingException e) { + logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, + ErrorTypes.GENERALSERVICEERROR, e); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build(); + }catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), ex.getMessage() ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + }catch (Exception ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + long actualUpdateCompletionTime = System.currentTimeMillis(); + + long endTime = System.currentTimeMillis(); + long jsonParseCompletionTime = System.currentTimeMillis(); + String timingString = "Time taken in ms for Music " + consistency + " update-" + operationId + + ":" + "|total operation time:" + (endTime - startTime) + + "|json parsing time:" + (jsonParseCompletionTime - startTime) + + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime) + + "|"; + + if (operationResult != null && operationResult.getTimingInfo() != null) { + String lockManagementTime = operationResult.getTimingInfo(); + timingString = timingString + lockManagementTime; + } + logger.info(EELFLoggerDelegate.applicationLogger, timingString); + + if (operationResult==null) { + logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build(); + } + if ( operationResult.getResult() == ResultType.SUCCESS ) { + return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build(); + } else { + logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(operationResult.getResult()).setError(operationResult.getMessage()).toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param delObj + * @param keyspace + * @param tablename + * @param info + * @return + * @throws MusicServiceException + * @throws MusicQueryException + * @throws Exception + */ + @DELETE + @Path("/{keyspace: .*}/tables/{tablename: .*}/rows") + @ApiOperation(value = "Delete From table", response = String.class, + notes = "Delete from a table, the row or parts of a row. Based on JSON body.") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response deleteFromTable( + @ApiParam(value = "Major Version", + required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", + required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version", + required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonDelete delObj, + @ApiParam(value = "Keyspace Name", + required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", + required = true) @PathParam("tablename") String tablename, + @Context UriInfo info) throws MusicQueryException, MusicServiceException { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) "); + if(delObj == null) { + logger.error(EELFLoggerDelegate.errorLogger,ResultType.BODYMISSING.getResult(), AppMessages.MISSINGDATA ,ErrorSeverity.WARN, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult()).toMap()).build(); + } + ReturnType operationResult = null; + String consistency = delObj.getConsistencyInfo().get("type"); + delObj.setKeyspaceName(keyspace); + delObj.setTableName(tablename); + try { + if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) { + String lockId = delObj.getConsistencyInfo().get("lockId"); + if(lockId == null) { + logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or" + + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock " + + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build(); + } + } + + operationResult = MusicCore.deleteFromTable(delObj,info.getQueryParameters()); + } catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), ex.getMessage() ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + + } catch (MusicLockingException e) { + logger.error(EELFLoggerDelegate.errorLogger,e, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, e); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("Unable to perform Delete operation. Exception from music").toMap()).build(); + } + if (operationResult==null) { + logger.error(EELFLoggerDelegate.errorLogger,"Null result - Please Contact admin", AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Null result - Please Contact admin").toMap()).build(); + } + if (operationResult.getResult().equals(ResultType.SUCCESS)) { + return response.status(Status.OK).entity(new JsonResponse(operationResult.getResult()).setMessage(operationResult.getMessage()).toMap()).build(); + } else { + logger.error(EELFLoggerDelegate.errorLogger,operationResult.getMessage(), AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(operationResult.getMessage()).toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param tabObj + * @param keyspace + * @param tablename + * @throws Exception + */ + @DELETE + @Path("/{keyspace: .*}/tables/{tablename: .*}") + @ApiOperation(value = "Drop Table", response = String.class) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response dropTable( + @ApiParam(value = "Major Version", + required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", + required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version", + required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Keyspace Name", + required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", + required = true) @PathParam("tablename") String tablename) throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspace+" ) "); + JsonTable jsonTable = new JsonTable(); + jsonTable.setKeyspaceName(keyspace); + jsonTable.setTableName(tablename); + try { + return response.status(Status.OK).entity(new JsonResponse(MusicCore.dropTable(jsonTable, MusicUtil.EVENTUAL)).toMap()).build(); + } catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger, ex.getMessage(), AppMessages.QUERYERROR,ErrorSeverity.WARN + , ErrorTypes.QUERYERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger, ex.getMessage(), AppMessages.MISSINGINFO ,ErrorSeverity.WARN + , ErrorTypes.GENERALSERVICEERROR,ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param selObj + * @param keyspace + * @param tablename + * @param info + * @return + */ + @PUT + @Path("/{keyspace: .*}/tables/{tablename: .*}/rows/criticalget") + @ApiOperation(value = "** Depreciated ** - Select Critical", response = Map.class, + notes = "This API is depreciated in favor of the regular select api.\n" + + "Avaliable to use with the select api by providing a minorVersion of 1 " + + "and patchVersion of 0.\n" + + "Critical Get requires parameter rowId=value and consistency in order to work.\n" + + "It will fail if either are missing.") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"result\":{\"row 0\":{\"address\":" + + "{\"city\":\"Someplace\",\"street\":\"1 Some way\"}," + + "\"emp_salary\":50,\"emp_name\":\"tom\",\"emp_id\":" + + "\"cfd66ccc-d857-4e90-b1e5-df98a3d40cd6\"}},\"status\":\"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response selectCritical( + @ApiParam(value = "Major Version", + required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",example = "0", + required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",example = "0", + required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonInsert selObj, + @ApiParam(value = "Keyspace Name", + required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", + required = true) @PathParam("tablename") String tablename, + @Context UriInfo info) throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspace + " )"); + if (info.getQueryParameters().isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger,RestMusicDataAPI.PARAMETER_ERROR, AppMessages.UNKNOWNERROR ,ErrorSeverity.WARN, ErrorTypes + .GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(RestMusicDataAPI.PARAMETER_ERROR).toMap()).build(); + } + if (selObj == null || selObj.getConsistencyInfo().isEmpty()) { + String error = " Missing Body or Consistency type."; + logger.error(EELFLoggerDelegate.errorLogger,ResultType.BODYMISSING.getResult() + error, AppMessages.MISSINGDATA ,ErrorSeverity.WARN, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ResultType.BODYMISSING.getResult() + error).toMap()).build(); + } + ResultSet results = null; + String consistency = selObj.getConsistencyInfo().get("type"); + String lockId = selObj.getConsistencyInfo().get("lockId"); + selObj.setKeyspaceName(keyspace); + selObj.setTableName(tablename); + try { + if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) { + if(lockId == null) { + logger.error(EELFLoggerDelegate.errorLogger,"LockId cannot be null. Create lock reference or" + + " use ATOMIC instead of CRITICAL", ErrorSeverity.FATAL, ErrorTypes.MUSICSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("LockId cannot be null. Create lock " + + "and acquire lock or use ATOMIC instead of CRITICAL").toMap()).build(); + } + } + results = MusicCore.selectCritical(selObj, info.getQueryParameters()); + }catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), ex.getMessage() ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + + }catch(Exception ex) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + + if(results!=null && results.getAvailableWithoutFetching() >0) { + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setError("No data found").toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * This API will replace the original select and provide a single API fro select and critical. + * The idea is to depreciate the older api of criticalGet and use a single API. + * + * @param selObj + * @param keyspace + * @param tablename + * @param info + * @return + */ + @GET + @Path("/{keyspace: .*}/tables/{tablename: .*}/rows") + @ApiOperation(value = "Select", response = Map.class, + notes = "This has 2 versions: if minorVersion and patchVersion is null or 0, this will be a Eventual Select only.\n" + + "If minorVersion is 1 and patchVersion is 0, this will act like the Critical Select \n" + + "Critical Get requires parameter rowId=value and consistency in order to work.\n" + + "If parameters are missing or consistency information is missing. An eventual select will be preformed.") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"result\":{\"row 0\":{\"address\":" + + "{\"city\":\"Someplace\",\"street\":\"1 Some way\"}," + + "\"emp_salary\":50,\"emp_name\":\"tom\",\"emp_id\":" + + "\"cfd66ccc-d857-4e90-b1e5-df98a3d40cd6\"}},\"status\":\"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"<errorMessage>\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response selectWithCritical( + @ApiParam(value = "Major Version",example = "v2", + required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version",example = "1", + required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",example = "0", + required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false,hidden = true) @HeaderParam(NS) String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonInsert selObj, + @ApiParam(value = "Keyspace Name", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("tablename") String tablename, + @Context UriInfo info) throws Exception { + if ((minorVersion != null && patchVersion != null) && + (Integer.parseInt(minorVersion) == 1 && Integer.parseInt(patchVersion) == 0) && + (!(null == selObj) && !selObj.getConsistencyInfo().isEmpty())) { + return selectCritical(version, minorVersion, patchVersion, aid, ns, authorization, selObj, keyspace, tablename, info); + } else { + return select(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename, info); + } + } + + /** + * + * @param keyspace + * @param tablename + * @param info + * @return + * @throws Exception + */ + private Response select( + String version,String minorVersion,String patchVersion, + String aid,String ns,String authorization,String keyspace, + String tablename,UriInfo info) throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + if((keyspace == null || keyspace.isEmpty()) || (tablename == null || tablename.isEmpty())){ + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("one or more path parameters are not set, please check and try again") + .toMap()).build(); + } + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspace + " ) "); + try { + JsonSelect jsonSelect = new JsonSelect(); + jsonSelect.setKeyspaceName(keyspace); + jsonSelect.setTableName(tablename); + ResultSet results = MusicCore.select(jsonSelect, info.getQueryParameters()); + if(results.getAvailableWithoutFetching() >0) { + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setDataResult(MusicDataStoreHandle.marshallResults(results)).setError("No data found").toMap()).build(); + } catch (MusicQueryException ex) { + logger.error(EELFLoggerDelegate.errorLogger,ex.getMessage(), ex.getMessage() ,ErrorSeverity + .WARN, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger, ex, AppMessages.UNKNOWNERROR ,ErrorSeverity.ERROR, + ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param keyspace + * @param tablename + * @param info + * @param limit + * @return + * @throws MusicServiceException + */ + public PreparedQueryObject selectSpecificQuery(String keyspace, + String tablename, UriInfo info, int limit) + throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + StringBuilder rowIdString = getRowIdentifier(keyspace, + tablename,info.getQueryParameters(),queryObject).rowIdString; + queryObject.appendQueryString( + "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowIdString); + if (limit != -1) { + queryObject.appendQueryString(" LIMIT " + limit); + } + queryObject.appendQueryString(";"); + return queryObject; + } + + /** + * + * @param keyspace + * @param tablename + * @param rowParams + * @param queryObject + * @return + * @throws MusicServiceException + */ + private RowIdentifier getRowIdentifier(String keyspace, String tablename, + MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject) + throws MusicServiceException { + StringBuilder rowSpec = new StringBuilder(); + int counter = 0; + TableMetadata tableInfo = MusicDataStoreHandle.returnColumnMetadata(keyspace, tablename); + if (tableInfo == null) { + logger.error(EELFLoggerDelegate.errorLogger, + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + throw new MusicServiceException( + "Table information not found. Please check input for table name= " + + keyspace + "." + tablename); + } + StringBuilder primaryKey = new StringBuilder(); + for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) { + String keyName = entry.getKey(); + List<String> valueList = entry.getValue(); + String indValue = valueList.get(0); + DataType colType = null; + Object formattedValue = null; + try { + colType = tableInfo.getColumn(entry.getKey()).getType(); + formattedValue = MusicUtil.convertToActualDataType(colType, indValue); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,e); + } + if(tableInfo.getPrimaryKey().get(0).getName().equals(entry.getKey())) { + primaryKey.append(indValue); + } + rowSpec.append(keyName + "= ?"); + queryObject.addValue(formattedValue); + if (counter != rowParams.size() - 1) { + rowSpec.append(" AND "); + } + counter = counter + 1; + } + return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject); + } +} diff --git a/music-rest/src/main/java/org/onap/music/rest/RestMusicHealthCheckAPI.java b/music-rest/src/main/java/org/onap/music/rest/RestMusicHealthCheckAPI.java new file mode 100644 index 00000000..eef3aa3a --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/RestMusicHealthCheckAPI.java @@ -0,0 +1,124 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * + * Modifications Copyright (C) 2018 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import java.util.HashMap; +/** + * @author inam + * + */ +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + + +import org.onap.music.eelf.healthcheck.MusicHealthCheck; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.main.MusicUtil; + +import com.datastax.driver.core.ConsistencyLevel; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; + + + + +@Path("/v2/service") +@Api(value="Healthcheck Api") +public class RestMusicHealthCheckAPI { + + + private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicUtil.class); + private static final String ACTIVE_STATUS = "ACTIVE"; + private static final String INVALID_STATUS = "INVALID"; + private static final String INACTIVE_STATUS = "INACTIVE"; + private static final String INVALID_MESSAGE = "Consistency level is invalid..."; + private static final String INACTIVE_MESSAGE = "One or more nodes in the Cluster is/are down or not responding."; + private static final String ACTIVE_MESSAGE = "Cassandra Running and Listening to requests"; + private static final String STATUS_KEY = "status"; + private static final String MESSAGE_KEY = "message"; + + @GET + @Path("/pingCassandra/{consistency}") + @ApiOperation(value = "Get Health Status", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + public Response cassandraStatus( + @Context HttpServletResponse response, + @ApiParam(value = "Consistency level",required = true) + @PathParam("consistency") String consistency) { + logger.info(EELFLoggerDelegate.applicationLogger,"Replying to request for MUSIC Health Check status for Cassandra"); + + Map<String, Object> resultMap = new HashMap<>(); + if(ConsistencyLevel.valueOf(consistency) == null) { + resultMap.put(STATUS_KEY,INVALID_STATUS); + resultMap.put(MESSAGE_KEY, INVALID_MESSAGE); + resultMap.put(INVALID_STATUS, INVALID_STATUS); + return Response.status(Status.BAD_REQUEST).entity(resultMap).build(); + } + MusicHealthCheck cassHealthCheck = new MusicHealthCheck(); + String status = cassHealthCheck.getCassandraStatus(consistency); + if(status.equals(ACTIVE_STATUS)) { + resultMap.put(STATUS_KEY,ACTIVE_STATUS); + resultMap.put(MESSAGE_KEY, ACTIVE_MESSAGE); + resultMap.put(ACTIVE_STATUS, ACTIVE_MESSAGE); + return Response.status(Status.OK).entity(resultMap).build(); + } else { + resultMap.put(STATUS_KEY,INACTIVE_STATUS); + resultMap.put(MESSAGE_KEY, INACTIVE_MESSAGE); + resultMap.put(INACTIVE_STATUS, INACTIVE_MESSAGE); + return Response.status(Status.BAD_REQUEST).entity(resultMap).build(); + } + } + + @GET + @Path("/musicHealthCheck") + @ApiOperation(value = "Get Health Status", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + public Response musicHealthCheck() { + logger.info(EELFLoggerDelegate.applicationLogger,"Replying to request for Health Check status for MUSIC"); + Map<String, Object> resultMap = new HashMap<>(); + MusicHealthCheck healthCheck = new MusicHealthCheck(); + + String status = healthCheck.getCassandraStatus(ConsistencyLevel.ANY.toString()); + if(status.equals(ACTIVE_STATUS)) { + resultMap.put("Cassandra", "Active"); + } else { + resultMap.put("Cassandra", "Inactive"); + } + resultMap.put("MUSIC", "Active"); + return Response.status(Status.OK).entity(resultMap).build(); + } + +} diff --git a/music-rest/src/main/java/org/onap/music/rest/RestMusicLocksAPI.java b/music-rest/src/main/java/org/onap/music/rest/RestMusicLocksAPI.java new file mode 100644 index 00000000..321e2561 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/RestMusicLocksAPI.java @@ -0,0 +1,632 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; + +import org.onap.music.datastore.jsonobjects.JsonLeasedLock; +import org.onap.music.datastore.jsonobjects.JsonLock; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.lockingservice.cassandra.LockType; +import org.onap.music.lockingservice.cassandra.MusicLockState; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.main.ReturnType; +import org.onap.music.response.jsonobjects.JsonResponse; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Example; +import io.swagger.annotations.ExampleProperty; + + +@Path("/v2/locks/") +@Api(value="Locking Api") +public class RestMusicLocksAPI { + + private EELFLoggerDelegate logger =EELFLoggerDelegate.getLogger(RestMusicLocksAPI.class); + private static final String XMINORVERSION = "X-minorVersion"; + private static final String XPATCHVERSION = "X-patchVersion"; + private static final String VERSION = "v2"; + + /** + * Puts the requesting process in the q for this lock. The corresponding + * node will be created if it did not already exist + * + * @param lockName + * @return + * @throws Exception + */ + @POST + @Path("/create/{lockname}") + @ApiOperation(value = "Create and Acquire a Lock Id for a single row.", + notes = "Creates and Acquires a Lock Id for a specific Row in a table based on the key of that row.\n" + + " The corresponding lock will be created if it did not already exist." + + " Lock Name also the Lock is in the form of keyspaceName.tableName.rowId.\n" + + " The Response will be in the form of \"$kesypaceName.tableName.rowId$lockRef\" " + + " where the lockRef is a integer representing the Lock Name buffered by \"$\" " + + " followed by the lock number. This term for " + + " this response is a lockId and it will be used in other /locks API calls where a " + + " lockId is required. If just a lock is required then the form that would be " + + " the original lockname(without the buffered \"$\").", + response = Map.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"}," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unable to aquire lock\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response createLockReference( + @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + JsonLock lockObject, + @ApiParam(value = "Lock Owner", required = false) @HeaderParam("owner") String owner, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{ + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockName); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.MISSINGINFO ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + + //default lock type is write, as this is always semantically safe + LockType locktype = LockType.WRITE; + if (lockObject!=null && lockObject.getLocktype()!=null) { + locktype = lockObject.getLocktype(); + } + String lockId; + try { + lockId= MusicCore.createLockReference(lockName, locktype, owner); + } catch (MusicLockingException e) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build(); + } + + if (lockId == null) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.LOCKINGERROR ,ErrorSeverity.CRITICAL, ErrorTypes.LOCKINGERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Lock Id is null").toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).setLock(lockId).toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * Checks if the node is in the top of the queue and hence acquires the lock + * + * @param lockId + * @return + * @throws Exception + */ + @GET + @Path("/acquire/{lockId}") + @ApiOperation(value = "Aquire Lock Id ", + notes = "Checks if the node is in the top of the queue and hence acquires the lock", + response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"}," + + "\"message\" : \"<integer> is the lock holder for the key\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unable to aquire lock\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response accquireLock( + @ApiParam(value="Lock Id",required=true) @PathParam("lockId") String lockId, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{ + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockId); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + try { + String lockName = lockId.substring(lockId.indexOf('$')+1, lockId.lastIndexOf('$')); + ReturnType lockStatus = MusicCore.acquireLock(lockName,lockId); + if ( lockStatus.getResult().equals(ResultType.SUCCESS)) { + response.status(Status.OK); + } else { + response.status(Status.BAD_REQUEST); + } + return response.entity(new JsonResponse(lockStatus.getResult()).setLock(lockId).setMessage(lockStatus.getMessage()).toMap()).build(); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,AppMessages.INVALIDLOCK + lockId, ErrorSeverity.CRITICAL, + ErrorTypes.LOCKINGERROR, e); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Unable to aquire lock").toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + + @POST + @Path("/acquire-with-lease/{lockId}") + @ApiOperation( + hidden = false, + value = " ** DEPRECATED ** - Aquire Lock with Lease", + notes = "Acquire the lock with a lease, where lease period is in Milliseconds.\n" + + "This will ensure that a lock will expire in set milliseconds.\n" + + "This is no longer available after v3.2.0", + response = Map.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"," + + "\"lock-lease\" : \"6000\"}," + + "\"message\" : \"<integer> is the lock holder for the key\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unable to aquire lock\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + @Deprecated + public Response accquireLockWithLease( + JsonLeasedLock lockObj, + @ApiParam(value="Lock Id",required=true) @PathParam("lockId") String lockId, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace",required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{ + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockId); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + String lockName = lockId.substring(lockId.indexOf('$')+1, lockId.lastIndexOf('$')); + ReturnType lockLeaseStatus = MusicCore.acquireLockWithLease(lockName, lockId, lockObj.getLeasePeriod()); + if ( lockLeaseStatus.getResult().equals(ResultType.SUCCESS)) { + response.status(Status.OK); + } else { + response.status(Status.BAD_REQUEST); + } + return response.entity(new JsonResponse(lockLeaseStatus.getResult()).setLock(lockName) + .setMessage(lockLeaseStatus.getMessage()) + .setLockLease(String.valueOf(lockObj.getLeasePeriod())).toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + + + } + + + @GET + @Path("/enquire/{lockname}") + @ApiOperation(value = "Get the top of the lock queue", + notes = "Gets the current single lockholder at top of lock queue", + response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"keyspace.table.rowId\"," + + "\"lock-holder\" : \"$tomtest.employees.tom$<integer>\"}}," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Error Message\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response enquireLock( + @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{ + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockName); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + String who = MusicCore.whoseTurnIsIt(lockName); + ResultType status = ResultType.SUCCESS; + String error = ""; + if ( who == null ) { + status = ResultType.FAILURE; + error = "There was a problem getting the lock holder"; + logger.error(EELFLoggerDelegate.errorLogger,"There was a problem getting the lock holder", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + @GET + @Path("/holders/{lockname}") + @ApiOperation(value = "Get Lock Holders", + notes = "Gets the current Lock Holders.\n" + + "Will return an array of READ Lock References.", + response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"keyspace.table.rowId\"," + + "\"lock-holder\" : [\"$keyspace.table.rowId$<integer1>\",\"$keyspace.table.rowId$<integer2>\"]}}," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Error message\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response currentLockHolder(@ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockName); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.INCORRECTDATA, ErrorSeverity.CRITICAL, + ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity( + new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()) + .build(); + } + String keyspaceName = (String) resultMap.get("keyspace"); + List<String> who = MusicCore.getCurrentLockHolders(lockName); + ResultType status = ResultType.SUCCESS; + String error = ""; + if (who == null || who.isEmpty()) { + status = ResultType.FAILURE; + error = (who !=null && who.isEmpty()) ? "No lock holders for the key":"There was a problem getting the lock holder"; + logger.error(EELFLoggerDelegate.errorLogger, "There was a problem getting the lock holder", + AppMessages.INCORRECTDATA, ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()) + .build(); + } + return response.status(Status.OK) + .entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).setisLockHolders(true).toMap()) + .build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + + @GET + @Path("/{lockname}") + @ApiOperation(value = "Lock State", + notes = "Returns current Lock State and Holder.", + response = Map.class,hidden = true) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"}," + + "\"message\" : \"<integer> is the lock holder for the key\"," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unable to aquire lock\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response currentLockState( + @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockName); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) "); + String who = MusicCore.whoseTurnIsIt(lockName); + ResultType status = ResultType.SUCCESS; + String error = ""; + if ( who == null ) { + status = ResultType.FAILURE; + error = "There was a problem getting the lock holder"; + logger.error(EELFLoggerDelegate.errorLogger,"There was a problem getting the lock holder", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(status).setError(error).setLock(lockName).setLockHolder(who).toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + + } + + /** + * + * deletes the process from the lock queue + * + * @param lockId + * @throws Exception + */ + @DELETE + @Path("/release/{lockreference}") + @ApiOperation(value = "Release Lock", + notes = "Releases the lock from the lock queue.", + response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success - UNLOCKED = Lock Removed.",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"lock\" : {\"lock\" : \"$keyspace.table.rowId$<integer>\"}," + + "\"lock-status\" : \"UNLOCKED\"}," + + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unable to aquire lock\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response unLock(@PathParam("lockreference") String lockId, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{ + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockId); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( "+keyspaceName+" ) "); + boolean voluntaryRelease = true; + MusicLockState mls = MusicCore.releaseLock(lockId,voluntaryRelease); + if(mls.getErrorMessage() != null) { + resultMap.put(ResultType.EXCEPTION.getResult(), mls.getErrorMessage()); + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + return response.status(Status.BAD_REQUEST).entity(resultMap).build(); + } + Map<String,Object> returnMap = null; + if (mls.getLockStatus() == MusicLockState.LockStatus.UNLOCKED) { + returnMap = new JsonResponse(ResultType.SUCCESS).setLock(lockId) + .setLockStatus(mls.getLockStatus()).toMap(); + response.status(Status.OK); + } + if (mls.getLockStatus() == MusicLockState.LockStatus.LOCKED) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.LOCKINGERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + returnMap = new JsonResponse(ResultType.FAILURE).setLock(lockId) + .setLockStatus(mls.getLockStatus()).toMap(); + response.status(Status.BAD_REQUEST); + } + return response.entity(returnMap).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + /** + * + * @param lockName + * @throws Exception + */ + @Deprecated + @DELETE + @Path("/delete/{lockname}") + @ApiOperation( + hidden = true, + value = "-DEPRECATED- Delete Lock", response = Map.class, + notes = "-DEPRECATED- Delete the lock.") + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Error Message if any\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response deleteLock(@PathParam("lockname") String lockName, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "AID", required = false, hidden = true) @HeaderParam("aid") String aid, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Application namespace", + required = false, hidden = true) @HeaderParam("ns") String ns) throws Exception{ + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockName); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.UNKNOWNERROR ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + try{ + MusicCore.destroyLockRef(lockName); + }catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger, e); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError(e.getMessage()).toMap()).build(); + } + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS).toMap()).build(); + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } + + + /** + * Puts the requesting process in the q for this lock. The corresponding + * node will be created if it did not already exist + * + * @param lockName + * @return + * @throws Exception + */ + @POST + @Path("/promote/{lockname}") + @ApiOperation(value = "Attempt to promote the lock for a single row.", + response = Map.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiResponses(value={ + @ApiResponse(code=200, message = "Success",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "\"status\" : \"SUCCESS\"}") + })), + @ApiResponse(code=400, message = "Failure",examples = @Example( value = { + @ExampleProperty(mediaType="application/json",value = + "{\"error\" : \"Unable to promote lock\"," + + "\"status\" : \"FAILURE\"}") + })) + }) + public Response promoteLock( + @ApiParam(value="Lock Id",required=true) @PathParam("lockId") String lockId, + @ApiParam(value = "Minor Version",required = false) @HeaderParam(XMINORVERSION) String minorVersion, + @ApiParam(value = "Patch Version",required = false) @HeaderParam(XPATCHVERSION) String patchVersion, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization) + throws Exception { + try { + ResponseBuilder response = MusicUtil.buildVersionResponse(VERSION, minorVersion, patchVersion); + Map<String, Object> resultMap = MusicCore.validateLock(lockId); + if (resultMap.containsKey("Error")) { + logger.error(EELFLoggerDelegate.errorLogger,"", AppMessages.INCORRECTDATA ,ErrorSeverity.CRITICAL, ErrorTypes.GENERALSERVICEERROR); + response.status(Status.BAD_REQUEST); + return response.entity(new JsonResponse(ResultType.FAILURE).setError(String.valueOf(resultMap.get("Error"))).toMap()).build(); + } + + String keyspaceName = (String) resultMap.get("keyspace"); + EELFLoggerDelegate.mdcPut("keyspace", "( " + keyspaceName + " ) "); + + try { + ReturnType lockStatus = MusicCore.promoteLock(lockId); + if ( lockStatus.getResult().equals(ResultType.SUCCESS)) { + response.status(Status.OK); + } else { + response.status(Status.BAD_REQUEST); + } + return response.entity(new JsonResponse(lockStatus.getResult()).setLock(lockId).setMessage(lockStatus.getMessage()).toMap()).build(); + } catch (Exception e) { + logger.error(EELFLoggerDelegate.errorLogger,AppMessages.INVALIDLOCK + lockId, ErrorSeverity.CRITICAL, + ErrorTypes.LOCKINGERROR, e); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE).setError("Unable to promote lock").toMap()).build(); + } + } finally { + EELFLoggerDelegate.mdcRemove("keyspace"); + } + } +} diff --git a/music-rest/src/main/java/org/onap/music/rest/RestMusicQAPI.java b/music-rest/src/main/java/org/onap/music/rest/RestMusicQAPI.java new file mode 100755 index 00000000..63b72cda --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/RestMusicQAPI.java @@ -0,0 +1,443 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (C) 2019 IBM. + * Modifications Copyright (c) 2019 Samsung + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import java.util.Map; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.Response.Status; +import org.onap.music.datastore.jsonobjects.JsonDelete; +import org.onap.music.datastore.jsonobjects.JsonInsert; +import org.onap.music.datastore.jsonobjects.JsonTable; +import org.onap.music.datastore.jsonobjects.JsonUpdate; +import org.onap.music.eelf.logging.EELFLoggerDelegate; + +import org.onap.music.eelf.logging.format.AppMessages; +import org.onap.music.eelf.logging.format.ErrorSeverity; +import org.onap.music.eelf.logging.format.ErrorTypes; +import org.apache.commons.lang3.StringUtils; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import com.datastax.driver.core.ResultSet; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.response.jsonobjects.JsonResponse; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; + +@Path("/v2/priorityq/") +@Api(value = "Q Api",hidden = true) +public class RestMusicQAPI { + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicQAPI.class); + + + /** + * + * @param tableObj + * @param keyspace + * @param tablename + * @throws Exception + */ + + @POST + @Path("/keyspaces/{keyspace}/{qname}") // qname same as tablename + @ApiOperation(value = "Create Q", response = String.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response createQ( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonTable tableObj, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) throws Exception { + ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion); + + Map<String, String> fields = tableObj.getFields(); + if (fields == null) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ/Required table fields are empty or not set").toMap()) + .build(); + } + + String primaryKey = tableObj.getPrimaryKey(); + String partitionKey = tableObj.getPartitionKey(); + String clusteringKey = tableObj.getClusteringKey(); + String filteringKey = tableObj.getFilteringKey(); + String clusteringOrder = tableObj.getClusteringOrder(); + + if(primaryKey == null) { + primaryKey = tableObj.getFields().get("PRIMARY KEY"); + } + + if ((primaryKey == null) && (partitionKey == null)) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ: Partition key cannot be empty").toMap()) + .build(); + } + + if ((primaryKey == null) && (clusteringKey == null)) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ: Clustering key cannot be empty").toMap()) + .build(); + } + + if (clusteringOrder == null) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ: Clustering Order cannot be empty").toMap()) + .build(); + } + + if ((primaryKey!=null) && (partitionKey == null)) { + primaryKey = primaryKey.trim(); + int count1 = StringUtils.countMatches(primaryKey,')'); + int count2 = StringUtils.countMatches(primaryKey,'('); + if (count1 != count2) { + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ Error: primary key '(' and ')' do not match, primary key=" + primaryKey) + .toMap()).build(); + } + + if ( primaryKey.indexOf('(') == -1 || ( count2 == 1 && (primaryKey.lastIndexOf(')') +1) == primaryKey.length() ) ) { + if (primaryKey.contains(",") ) { + partitionKey= primaryKey.substring(0,primaryKey.indexOf(',')); + partitionKey=partitionKey.replaceAll("[\\(]+",""); + clusteringKey=primaryKey.substring(primaryKey.indexOf(',')+1); // make sure index + clusteringKey=clusteringKey.replaceAll("[)]+", ""); + } else { + partitionKey=primaryKey; + partitionKey=partitionKey.replaceAll("[\\)]+",""); + partitionKey=partitionKey.replaceAll("[\\(]+",""); + clusteringKey=""; + } + } else { + partitionKey= primaryKey.substring(0,primaryKey.indexOf(')')); + partitionKey=partitionKey.replaceAll("[\\(]+",""); + partitionKey = partitionKey.trim(); + clusteringKey= primaryKey.substring(primaryKey.indexOf(')')); + clusteringKey=clusteringKey.replaceAll("[\\(]+",""); + clusteringKey=clusteringKey.replaceAll("[\\)]+",""); + clusteringKey = clusteringKey.trim(); + if (clusteringKey.indexOf(',') == 0) + clusteringKey=clusteringKey.substring(1); + clusteringKey = clusteringKey.trim(); + if (clusteringKey.equals(",") ) + clusteringKey=""; // print error if needed ( ... ),) + } + } + + if (partitionKey.trim().isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ: Partition key cannot be empty").toMap()) + .build(); + } + + if (clusteringKey.trim().isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ: Clustering key cannot be empty").toMap()) + .build(); + } + + if((filteringKey != null) && (filteringKey.equalsIgnoreCase(partitionKey))) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("CreateQ: Filtering key cannot be same as Partition Key").toMap()) + .build(); + } + + return new RestMusicDataAPI().createTable(version, minorVersion, patchVersion, aid, ns, authorization, tableObj, keyspace, tablename); + } + + /** + * + * @param insObj + * @param keyspace + * @param tablename + * @throws Exception + */ + @POST + @Path("/keyspaces/{keyspace}/{qname}/rows") + @ApiOperation(value = "", response = Void.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + // public Map<String, Object> insertIntoQ( + public Response insertIntoQ( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonInsert insObj, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) { + + ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion); + if (insObj.getValues().isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("Required HTTP Request body is missing.").toMap()).build(); + } + return new RestMusicDataAPI().insertIntoTable(version, minorVersion, patchVersion, aid, ns, + authorization, insObj, keyspace, tablename); + } + + /** + * + * @param updateObj + * @param keyspace + * @param tablename + * @param info + * @return + * @throws Exception + */ + @PUT + @Path("/keyspaces/{keyspace}/{qname}/rows") + @ApiOperation(value = "updateQ", response = String.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response updateQ( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonUpdate updateObj, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename, + @Context UriInfo info) throws MusicServiceException, MusicQueryException { + + ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion); + if (updateObj.getValues().isEmpty()) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE) + .setError("Required HTTP Request body is missing. JsonUpdate updateObj.getValues() is empty. ") + .toMap()) + .build(); + } + return new RestMusicDataAPI().updateTable(version, minorVersion, patchVersion, aid, ns, + authorization,updateObj, keyspace, tablename, info); + } + + /** + * + * @param delObj + * @param keyspace + * @param tablename + * @param info + * + * @return + * @throws Exception + */ + + @DELETE + @Path("/keyspaces/{keyspace}/{qname}/rows") + @ApiOperation(value = "deleteQ", response = String.class) + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public Response deleteFromQ( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + JsonDelete delObj, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename, + @Context UriInfo info) throws MusicServiceException, MusicQueryException { + // added checking as per RestMusicDataAPI + ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion); + if (delObj == null) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.MISSINGDATA, + ErrorSeverity.CRITICAL, ErrorTypes.DATAERROR); + return response.status(Status.BAD_REQUEST).entity(new JsonResponse(ResultType.FAILURE) + .setError("deleteFromQ JsonDelete delObjis empty").toMap()).build(); + } + + return new RestMusicDataAPI().deleteFromTable(version, minorVersion, patchVersion, aid, ns, + authorization, delObj, keyspace, tablename, info); + } + + /** + * + * @param keyspace + * @param tablename + * @param info + * @return + * @throws Exception + */ + @GET + @Path("/keyspaces/{keyspace}/{qname}/peek") + @ApiOperation(value = "", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + //public Map<String, HashMap<String, Object>> peek( + public Response peek( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename, + @Context UriInfo info) { + int limit =1; //peek must return just the top row + // Map<String ,String> auth = new HashMap<>(); + // String userId =auth.get(MusicUtil.USERID); + // String password =auth.get(MusicUtil.PASSWORD); + ResponseBuilder response = MusicUtil.buildVersionResponse(version, minorVersion, patchVersion); + + PreparedQueryObject queryObject = new PreparedQueryObject(); + if (info.getQueryParameters() == null ) { //|| info.getQueryParameters().isEmpty()) + queryObject.appendQueryString( + "SELECT * FROM " + keyspace + "." + tablename + " LIMIT " + limit + ";"); + } else { + try { + queryObject = new RestMusicDataAPI().selectSpecificQuery(keyspace, tablename, info, limit); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR, + ErrorSeverity.WARN, ErrorTypes.GENERALSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()) + .build(); + } + } + + try { + ResultSet results = MusicCore.get(queryObject); + return response.status(Status.OK).entity(new JsonResponse(ResultType.SUCCESS) + .setDataResult(MusicDataStoreHandle.marshallResults(results)).toMap()).build(); + } catch (MusicServiceException ex) { + logger.error(EELFLoggerDelegate.errorLogger, "", AppMessages.UNKNOWNERROR, + ErrorSeverity.ERROR, ErrorTypes.MUSICSERVICEERROR, ex); + return response.status(Status.BAD_REQUEST) + .entity(new JsonResponse(ResultType.FAILURE).setError(ex.getMessage()).toMap()) + .build(); + } + } + + /** + * + * + * @param keyspace + * @param tablename + * @param info + * @return + * @throws Exception + */ + @GET + @Path("/keyspaces/{keyspace}/{qname}/filter") + @ApiOperation(value = "filter", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + // public Map<String, HashMap<String, Object>> filter( + public Response filter( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename, + @Context UriInfo info) throws Exception { + + return new RestMusicDataAPI().selectWithCritical(version, minorVersion, patchVersion, aid, ns, authorization,null, keyspace, tablename, info);// , limit) + + } + + /** + * + * @param tabObj + * @param keyspace + * @param tablename + * @throws Exception + */ + @DELETE + @ApiOperation(value = "DropQ", response = String.class) + @Path("/keyspaces/{keyspace}/{qname}") + @Produces(MediaType.APPLICATION_JSON) + public Response dropQ( + @ApiParam(value = "Major Version", required = true) @PathParam("version") String version, + @ApiParam(value = "Minor Version", + required = false) @HeaderParam("X-minorVersion") String minorVersion, + @ApiParam(value = "Patch Version", + required = false) @HeaderParam("X-patchVersion") String patchVersion, + @ApiParam(value = "AID", required = false) @HeaderParam("aid") String aid, + @ApiParam(value = "Application namespace", required = true) @HeaderParam("ns") String ns, + @ApiParam(value = "Authorization", required = true) @HeaderParam(MusicUtil.AUTHORIZATION) String authorization, + @ApiParam(value = "Key Space", required = true) @PathParam("keyspace") String keyspace, + @ApiParam(value = "Table Name", required = true) @PathParam("qname") String tablename) throws Exception { + + return new RestMusicDataAPI().dropTable(version, minorVersion, patchVersion, aid, ns, authorization, keyspace, tablename); + + } +} diff --git a/music-rest/src/main/java/org/onap/music/rest/RestMusicTestAPI.java b/music-rest/src/main/java/org/onap/music/rest/RestMusicTestAPI.java new file mode 100644 index 00000000..c1c04b09 --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/RestMusicTestAPI.java @@ -0,0 +1,70 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.main.MusicUtil; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + + +@Path("/v{version: [0-9]+}/test") +@Api(value="Test Api") +public class RestMusicTestAPI { + + @SuppressWarnings("unused") + private EELFLoggerDelegate logger =EELFLoggerDelegate.getLogger(RestMusicTestAPI.class); + + /** + * Returns a test JSON. This will confirm that REST is working. + * @return + */ + @GET + @Path("/") + @ApiOperation(value = "Get Test", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + public Map<String, HashMap<String, String>> simpleTests( + @Context HttpServletResponse response) { + response.addHeader("X-latestVersion",MusicUtil.getVersion()); + Map<String, HashMap<String, String>> testMap = new HashMap<>(); + for(int i=0; i < 3; i++){ + HashMap<String, String> innerMap = new HashMap<>(); + innerMap.put("Music Version",MusicUtil.getVersion()); + innerMap.put("Music Build",MusicUtil.getBuild()); + innerMap.put(i+1+"", i+2+""); + testMap.put(i+"", innerMap); + } + return testMap; + } +} diff --git a/music-rest/src/main/java/org/onap/music/rest/RestMusicVersionAPI.java b/music-rest/src/main/java/org/onap/music/rest/RestMusicVersionAPI.java new file mode 100644 index 00000000..8c86152e --- /dev/null +++ b/music-rest/src/main/java/org/onap/music/rest/RestMusicVersionAPI.java @@ -0,0 +1,82 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * + * Modifications Copyright (C) 2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; + +import org.onap.music.response.jsonobjects.JsonResponse; +import org.onap.music.eelf.logging.EELFLoggerDelegate; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + + +@Path("/v{version: [0-9]+}/version") +@Api(value="Version Api") +public class RestMusicVersionAPI { + + private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMusicVersionAPI.class); + private static final String MUSIC_KEY = "MUSIC:"; + /** + * Get the version of MUSIC. + * @return + */ + @GET + @ApiOperation(value = "Get Version", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + public Map<String,Object> version(@Context HttpServletResponse response) { + logger.info("Replying to request for MUSIC version with MUSIC:" + MusicUtil.getVersion()); + response.addHeader("X-latestVersion",MusicUtil.getVersion()); + return new JsonResponse(ResultType.SUCCESS). + setMusicVersion(MUSIC_KEY + MusicUtil.getVersion()).toMap(); + } + + /** + * Get the version of MUSIC. + * @return + */ + @GET + @Path("/build") + @ApiOperation(value = "Get Version", response = Map.class) + @Produces(MediaType.APPLICATION_JSON) + public Map<String,Object> build(@Context HttpServletResponse response) { + logger.info("Replying to request for MUSIC build with MUSIC:" + MusicUtil.getBuild()); + response.addHeader("X-latestVersion",MusicUtil.getVersion()); + return new JsonResponse(ResultType.SUCCESS) + .setMusicBuild(MUSIC_KEY + MusicUtil.getBuild()) + .setMusicVersion(MUSIC_KEY + MusicUtil.getVersion()).toMap(); + } + + +}
\ No newline at end of file diff --git a/music-rest/src/main/resources/application.properties b/music-rest/src/main/resources/application.properties new file mode 100755 index 00000000..6fbe6326 --- /dev/null +++ b/music-rest/src/main/resources/application.properties @@ -0,0 +1,9 @@ +server.port=8080 +server.servlet.context-path=/MUSIC/rest +security.require-ssl=true +server.ssl.key-store=/opt/app/aafcertman/keystore.jks +server.ssl.key-store-password=changeit +server.ssl.key-store-provider=SUN +server.ssl.key-store-type=JKS +httpPort=8081 +spring.jackson.mapper.ACCEPT_CASE_INSENSITIVE_ENUMS=true diff --git a/music-rest/src/main/resources/key.properties b/music-rest/src/main/resources/key.properties new file mode 100644 index 00000000..5ce266fa --- /dev/null +++ b/music-rest/src/main/resources/key.properties @@ -0,0 +1 @@ +cipher.enc.key= nothing to see here diff --git a/music-rest/src/test/java/LICENSE.txt b/music-rest/src/test/java/LICENSE.txt new file mode 100644 index 00000000..cc6cdea5 --- /dev/null +++ b/music-rest/src/test/java/LICENSE.txt @@ -0,0 +1,24 @@ + +The following license applies to all files in this and sub-directories. Licenses +are included in individual source files where appropriate, and if it differs +from this text, it supersedes this. Any file that does not have license text +defaults to being covered by this text; not all files support the addition of +licenses. +# +# ------------------------------------------------------------------------- +# Copyright (c) 2017 AT&T Intellectual Property +# +# Licensed 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. +# +# ------------------------------------------------------------------------- +#
\ No newline at end of file diff --git a/music-rest/src/test/java/org/onap/music/JerseyConfigTest.java b/music-rest/src/test/java/org/onap/music/JerseyConfigTest.java new file mode 100644 index 00000000..d7475a9d --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/JerseyConfigTest.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ +package org.onap.music; + +import org.junit.Before; +import org.junit.Test; + +public class JerseyConfigTest { + JerseyConfig jerseyConfig; + + @Before + public void setup() { + jerseyConfig = new JerseyConfig(); + } + + @Test + public void testInitJerseyConfig() { + jerseyConfig.init(); + } +} diff --git a/music-rest/src/test/java/org/onap/music/conductor/conditionals/JsonConditionalTest.java b/music-rest/src/test/java/org/onap/music/conductor/conditionals/JsonConditionalTest.java new file mode 100644 index 00000000..07c43114 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/conductor/conditionals/JsonConditionalTest.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ + +package org.onap.music.conductor.conditionals; + +import static org.junit.Assert.assertEquals; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class JsonConditionalTest { + + Map<String,Object> tableValues; + Map<String,Object> casscadeColumnData; + Map<String,Map<String,String>> conditions; + JsonConditional jsonConditional; + + @Before + public void setup() { + tableValues = Mockito.mock(Map.class); + casscadeColumnData = Mockito.mock(Map.class); + conditions = Mockito.mock(Map.class); + jsonConditional = new JsonConditional(); + } + + @Test + public void testSetTableValues() { + jsonConditional.setTableValues(tableValues); + assertEquals(tableValues, jsonConditional.getTableValues()); + } + + @Test + public void testSetPrimaryKey() { + jsonConditional.setPrimaryKey("primarykey"); + assertEquals("primarykey", jsonConditional.getPrimaryKey()); + } + + @Test + public void testSetPrimaryKeyValue() { + jsonConditional.setPrimaryKeyValue("primarykeyvalue"); + assertEquals("primarykeyvalue", jsonConditional.getPrimaryKeyValue()); + } + + @Test + public void testSetCasscadeColumnName() { + jsonConditional.setCasscadeColumnName("columnname"); + assertEquals("columnname", jsonConditional.getCasscadeColumnName()); + } + + @Test + public void testSetCasscadeColumnData() { + jsonConditional.setCasscadeColumnData(casscadeColumnData); + assertEquals(casscadeColumnData, jsonConditional.getCasscadeColumnData()); + } + + @Test + public void testSetConditions() { + jsonConditional.setConditions(conditions); + assertEquals(conditions, jsonConditional.getConditions()); + } + +} diff --git a/music-rest/src/test/java/org/onap/music/conductor/conditionals/UpdateDataObjectTest.java b/music-rest/src/test/java/org/onap/music/conductor/conditionals/UpdateDataObjectTest.java new file mode 100644 index 00000000..b651f5e9 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/conductor/conditionals/UpdateDataObjectTest.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ + +package org.onap.music.conductor.conditionals; + +import static org.junit.Assert.assertEquals; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.datastore.PreparedQueryObject; + +public class UpdateDataObjectTest { + + UpdateDataObject updateDataObject; + Map<String, PreparedQueryObject> queryBank; + Map<String, String> cascadeColumnValues; + + @Before + public void setup() { + updateDataObject = new UpdateDataObject(); + queryBank = Mockito.mock(Map.class); + cascadeColumnValues = Mockito.mock(Map.class); + } + + @Test + public void testSetQueryBank() { + updateDataObject.setQueryBank(queryBank); + assertEquals(queryBank, updateDataObject.getQueryBank()); + } + + @Test + public void testSetKeyspace() { + updateDataObject.setKeyspace("keyspace"); + assertEquals("keyspace", updateDataObject.getKeyspace()); + } + + @Test + public void testSetTableName() { + updateDataObject.setTableName("table"); + assertEquals("table", updateDataObject.getTableName()); + } + + @Test + public void testSetPrimaryKey() { + updateDataObject.setPrimaryKey("primarykey"); + assertEquals("primarykey", updateDataObject.getPrimaryKey()); + } + + @Test + public void testSetPrimaryKeyValue() { + updateDataObject.setPrimaryKeyValue("primarykeyvalue"); + assertEquals("primarykeyvalue", updateDataObject.getPrimaryKeyValue()); + } + + @Test + public void testSetPlanId() { + updateDataObject.setPlanId("planid"); + assertEquals("planid", updateDataObject.getPlanId()); + } + + @Test + public void testSetCascadeColumnName() { + updateDataObject.setCascadeColumnName("columnname"); + assertEquals("columnname", updateDataObject.getCascadeColumnName()); + } + + @Test + public void testSetCascadeColumnValues() { + updateDataObject.setCascadeColumnValues(cascadeColumnValues); + assertEquals(cascadeColumnValues, updateDataObject.getCascadeColumnValues()); + } + + @Test + public void testSetLockId() { + updateDataObject.setLockId("lockid"); + assertEquals("lockid", updateDataObject.getLockId()); + } +} diff --git a/music-rest/src/test/java/org/onap/music/eelf/healthcheck/MusicHealthCheckTest.java b/music-rest/src/test/java/org/onap/music/eelf/healthcheck/MusicHealthCheckTest.java new file mode 100644 index 00000000..66290630 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/eelf/healthcheck/MusicHealthCheckTest.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ + +package org.onap.music.eelf.healthcheck; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.datastore.MusicDataStore; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.ResultType; + +public class MusicHealthCheckTest { + + MusicHealthCheck musicHealthCheck; + + @Before + public void setup() { + musicHealthCheck = new MusicHealthCheck(); + } + + @Test + public void testSetCassandrHost() { + musicHealthCheck.setCassandrHost("127.0.0.1"); + assertEquals("127.0.0.1", musicHealthCheck.getCassandrHost()); + } + + @Test + public void testGetCassandraStatus() throws MusicServiceException, MusicQueryException { + MusicHealthCheck mHealthCheck = Mockito.spy(MusicHealthCheck.class); + doReturn(ResultType.SUCCESS).when(mHealthCheck).nonKeyRelatedPut(Mockito.any(), Mockito.anyString()); + doNothing().when(mHealthCheck).executeEventualPut(Mockito.any()); + assertEquals("ACTIVE", mHealthCheck.getCassandraStatus("consistency")); + } + +} diff --git a/music-rest/src/test/java/org/onap/music/eelf/logging/MusicContainerFilterTest.java b/music-rest/src/test/java/org/onap/music/eelf/logging/MusicContainerFilterTest.java new file mode 100644 index 00000000..cd7a9ca4 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/eelf/logging/MusicContainerFilterTest.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (C) 2020 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ +package org.onap.music.eelf.logging; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; + +import org.springframework.stereotype.Component; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.main.MusicUtil; + +public class MusicContainerFilterTest { + MusicContainerFilter filter; + + @Before + public void setup() throws IOException { + filter = new MusicContainerFilter(); + } + + @Test + public void testDoFilter() throws IOException { + ContainerResponseFilter fil=Mockito.mock(ContainerResponseFilter.class); + ContainerRequestContext req=Mockito.mock(ContainerRequestContext.class); + ContainerResponseContext res=Mockito.mock(ContainerResponseContext.class); + filter.filter(req,res); + } + +} diff --git a/music-rest/src/test/java/org/onap/music/eelf/logging/MusicLoggingServletFilterTest.java b/music-rest/src/test/java/org/onap/music/eelf/logging/MusicLoggingServletFilterTest.java new file mode 100644 index 00000000..8f5d4521 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/eelf/logging/MusicLoggingServletFilterTest.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ +package org.onap.music.eelf.logging; + +import static org.mockito.Mockito.doNothing; +import java.io.IOException; +import java.util.Enumeration; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.main.MusicUtil; + +public class MusicLoggingServletFilterTest { + MusicLoggingServletFilter filter; + + @Before + public void setup() throws ServletException { + filter = new MusicLoggingServletFilter(); + } + + @Test + public void testDoFilter() throws IOException, ServletException { + FilterChain chain = Mockito.mock(FilterChain.class); + Enumeration<String> headerNames = Mockito.mock(Enumeration.class); + HttpServletRequest httpRequest = Mockito.mock(HttpServletRequest.class); + HttpServletResponse httpResponse = Mockito.mock(HttpServletResponse.class); + Mockito.when(headerNames.hasMoreElements()).thenReturn(true).thenReturn(true).thenReturn(true).thenReturn(false); + Mockito.when(headerNames.nextElement()).thenReturn("element1").thenReturn("element2").thenReturn("element3"); + Mockito.when(httpRequest.getHeader(Mockito.anyString())).thenReturn("key1").thenReturn("key2").thenReturn("key3"); + Mockito.when(httpRequest.getHeaderNames()).thenReturn(headerNames); + MusicUtil.setTransIdRequired(false); + MusicUtil.setConversationIdRequired(false); + MusicUtil.setMessageIdRequired(false); + MusicUtil.setClientIdRequired(false); + doNothing().when(chain).doFilter(Mockito.any(), Mockito.any()); + filter.doFilter(httpRequest, httpResponse, chain); + } + +} diff --git a/music-rest/src/test/java/org/onap/music/exceptions/MusicExceptionMapperTest.java b/music-rest/src/test/java/org/onap/music/exceptions/MusicExceptionMapperTest.java new file mode 100644 index 00000000..58135551 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/exceptions/MusicExceptionMapperTest.java @@ -0,0 +1,61 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 IBM Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.exceptions; + +import org.codehaus.jackson.map.exc.UnrecognizedPropertyException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.ws.rs.core.Response; +import java.io.EOFException; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +@RunWith(SpringJUnit4ClassRunner.class) +public class MusicExceptionMapperTest { + + @Test + public void testToResponse() { + MusicExceptionMapper musicExceptionMapper = new MusicExceptionMapper(); + UnrecognizedPropertyException unrecognizedPropertyException = mock(UnrecognizedPropertyException.class); + Response response = musicExceptionMapper.toResponse(unrecognizedPropertyException); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(((Map)response.getEntity()).get("error").toString().startsWith("Unknown field :")); + + EOFException eofException = mock(EOFException.class); + response = musicExceptionMapper.toResponse(eofException); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(((Map)response.getEntity()).get("error").toString().equals("Request body cannot be empty".trim())); + + IllegalArgumentException illegalArgumentException = mock(IllegalArgumentException.class); + Mockito.when(illegalArgumentException.getMessage()).thenReturn("ERROR MSG"); + response = musicExceptionMapper.toResponse(illegalArgumentException); + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + assertTrue(((Map)response.getEntity()).get("error").toString().equals("ERROR MSG".trim())); + } +}
\ No newline at end of file diff --git a/music-rest/src/test/java/org/onap/music/main/PropertiesLoaderTest.java b/music-rest/src/test/java/org/onap/music/main/PropertiesLoaderTest.java new file mode 100644 index 00000000..7c10e8f1 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/main/PropertiesLoaderTest.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ +package org.onap.music.main; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.util.Properties; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.rest.RestMusicVersionAPI; + +public class PropertiesLoaderTest { + PropertiesLoader propertiesLoader; + + @Before + public void setup() { + propertiesLoader = new PropertiesLoader(); + } + + @Test + public void testLoadProperties() { + Properties properties = Mockito.mock(Properties.class); + Mockito.when(properties.getProperty("cassandra.host")).thenReturn("127.0.0.1"); + Mockito.when(properties.getProperty("cassandra.port")).thenReturn("8007"); + Mockito.when(properties.getProperty("cassandra.user")).thenReturn("user"); + Mockito.when(properties.getProperty("cassandra.password")).thenReturn("password"); + Mockito.when(properties.getProperty("music.properties")).thenReturn("property"); + Mockito.when(properties.getProperty("debug")).thenReturn("true"); + Mockito.when(properties.getProperty("version")).thenReturn("x.x.x"); + Mockito.when(properties.getProperty("build")).thenReturn("y.y"); + Mockito.when(properties.getProperty("lock.lease.period")).thenReturn("5000"); + Mockito.when(properties.getProperty("cadi")).thenReturn("true"); + Mockito.when(properties.getProperty("keyspace.active")).thenReturn("true"); + Mockito.when(properties.getProperty("retry.count")).thenReturn("20"); + Mockito.when(properties.getProperty("transId.header.prefix")).thenReturn("transId"); + Mockito.when(properties.getProperty("conversation.header.prefix")).thenReturn("conversation"); + Mockito.when(properties.getProperty("clientId.header.prefix")).thenReturn("clientId"); + Mockito.when(properties.getProperty("messageId.header.prefix")).thenReturn("messageId"); + Mockito.when(properties.getProperty("transId.header.required")).thenReturn("true"); + Mockito.when(properties.getProperty("conversation.header.required")).thenReturn("true"); + Mockito.when(properties.getProperty("clientId.header.required")).thenReturn("true"); + Mockito.when(properties.getProperty("messageId.header.required")).thenReturn("true"); + Mockito.when(properties.getProperty("music.aaf.ns")).thenReturn("ns"); + Mockito.when(properties.getProperty("cipher.enc.key")).thenReturn("key"); + CorePropertiesLoader.loadProperties(properties); + assertEquals("127.0.0.1", MusicUtil.getMyCassaHost()); + assertEquals(8007, MusicUtil.getCassandraPort()); + assertEquals("user", MusicUtil.getCassName()); + assertEquals("password", MusicUtil.getCassPwd()); + assertEquals("property", MusicUtil.getMusicPropertiesFilePath()); + assertEquals(true, MusicUtil.isDebug()); + assertEquals("x.x.x", MusicUtil.getVersion()); + assertEquals("y.y", MusicUtil.getBuild()); + assertEquals(5000L, MusicUtil.getDefaultLockLeasePeriod()); + assertEquals(true, MusicUtil.getIsCadi()); + assertEquals(true, MusicUtil.isKeyspaceActive()); + assertEquals(20, MusicUtil.getRetryCount()); + assertEquals("transId-", MusicUtil.getTransIdPrefix()); + assertEquals("conversation-", MusicUtil.getConversationIdPrefix()); + assertEquals("clientId-", MusicUtil.getClientIdPrefix()); + assertEquals("messageId-", MusicUtil.getMessageIdPrefix()); + assertEquals(true, MusicUtil.getTransIdRequired()); + assertEquals(true, MusicUtil.getConversationIdRequired()); + assertEquals(true, MusicUtil.getClientIdRequired()); + assertEquals(true, MusicUtil.getMessageIdRequired()); + assertEquals("ns", MusicUtil.getMusicAafNs()); + assertEquals("key", MusicUtil.getCipherEncKey()); + + Mockito.when(properties.getProperty("cassandra.connecttimeoutms")).thenReturn("1000"); + Mockito.when(properties.getProperty("cassandra.readtimeoutms")).thenReturn("1000"); + Mockito.when(properties.getProperty("cassandra.connectTimeOutMS")).thenReturn("1000"); + Mockito.when(properties.getProperty("cassandra.readTimeOutMS")).thenReturn("1000"); + PropertiesLoader.loadProperties(properties); + assertEquals("127.0.0.1", MusicUtil.getMyCassaHost()); + assertEquals(8007, MusicUtil.getCassandraPort()); + assertEquals("user", MusicUtil.getCassName()); + assertEquals("password", MusicUtil.getCassPwd()); + assertEquals(1000, MusicUtil.getCassandraConnectTimeOutMS()); + assertEquals(1000, MusicUtil.getCassandraReadTimeOutMS()); + assertEquals("property", MusicUtil.getMusicPropertiesFilePath()); + assertEquals(true, MusicUtil.isDebug()); + assertEquals("x.x.x", MusicUtil.getVersion()); + assertEquals("y.y", MusicUtil.getBuild()); + assertEquals(5000L, MusicUtil.getDefaultLockLeasePeriod()); + assertEquals(true, MusicUtil.getIsCadi()); + assertEquals(true, MusicUtil.isKeyspaceActive()); + assertEquals(20, MusicUtil.getRetryCount()); + assertEquals("transId-", MusicUtil.getTransIdPrefix()); + assertEquals("conversation-", MusicUtil.getConversationIdPrefix()); + assertEquals("clientId-", MusicUtil.getClientIdPrefix()); + assertEquals("messageId-", MusicUtil.getMessageIdPrefix()); + assertEquals(true, MusicUtil.getTransIdRequired()); + assertEquals(true, MusicUtil.getConversationIdRequired()); + assertEquals(true, MusicUtil.getClientIdRequired()); + assertEquals(true, MusicUtil.getMessageIdRequired()); + assertEquals("ns", MusicUtil.getMusicAafNs()); + assertEquals("key", MusicUtil.getCipherEncKey()); + + propertiesLoader.setProperties(); + propertiesLoader.loadProperties(); + assertEquals("127.0.0.1", MusicUtil.getMyCassaHost()); + assertEquals(8007, MusicUtil.getCassandraPort()); + assertEquals("user", MusicUtil.getCassName()); + assertEquals("password", MusicUtil.getCassPwd()); + assertEquals(1000, MusicUtil.getCassandraConnectTimeOutMS()); + assertEquals(1000, MusicUtil.getCassandraReadTimeOutMS()); + assertEquals("property", MusicUtil.getMusicPropertiesFilePath()); + assertEquals(true, MusicUtil.isDebug()); + assertEquals("x.x.x", MusicUtil.getVersion()); + assertEquals("y.y", MusicUtil.getBuild()); + assertEquals(5000L, MusicUtil.getDefaultLockLeasePeriod()); + assertEquals(true, MusicUtil.getIsCadi()); + assertEquals(true, MusicUtil.isKeyspaceActive()); + assertEquals(20, MusicUtil.getRetryCount()); + assertEquals("transId-", MusicUtil.getTransIdPrefix()); + assertEquals("conversation-", MusicUtil.getConversationIdPrefix()); + assertEquals("clientId-", MusicUtil.getClientIdPrefix()); + assertEquals("messageId-", MusicUtil.getMessageIdPrefix()); + assertEquals(true, MusicUtil.getTransIdRequired()); + assertEquals(true, MusicUtil.getConversationIdRequired()); + assertEquals(true, MusicUtil.getClientIdRequired()); + assertEquals(true, MusicUtil.getMessageIdRequired()); + assertEquals("ns", MusicUtil.getMusicAafNs()); + assertEquals("key", MusicUtil.getCipherEncKey()); + } +} diff --git a/music-rest/src/test/java/org/onap/music/rest/ApplicationTest.java b/music-rest/src/test/java/org/onap/music/rest/ApplicationTest.java new file mode 100644 index 00000000..66983312 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/rest/ApplicationTest.java @@ -0,0 +1,94 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * + * Modifications Copyright (C) 2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.rest; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class ApplicationTest { + + Application apl=new Application(); + private String application_name="music"; + private String username="music"; + private String password="music"; + private String keyspace_name="music"; + private boolean is_aaf=false; + private String uuid="123"; + private boolean is_api=true; + + @Test + public void testsetApplication_name() { + apl.setApplication_name(application_name); + assertEquals("music",apl.getApplication_name()); + } + + @Test + public void testsetUsername() + { + apl.setUsername(username); + assertEquals("music",apl.getUsername()); + } + + @Test + public void testsetPassword() + { + apl.setPassword(password); + assertEquals("music",apl.getPassword()); + } + + @Test + public void testsetKeyspace_name() + { + apl.setKeyspace_name(keyspace_name); + assertEquals("music",apl.getKeyspace_name()); + } + + @Test + public void testsetIs_aaf() + { + apl.setIs_aaf(is_aaf); + assertEquals(false,apl.isIs_aaf()); + } + + + @Test + public void testsetUuid() + { + apl.setUuid(uuid); + assertEquals("123",apl.getUuid()); + } + + @Test + public void testsetIs_api() + { + apl.setIs_api(is_api); + assertEquals(true,apl.getIs_api()); + + } + + + +} diff --git a/music-rest/src/test/java/org/onap/music/rest/RestMusicTestAPITest.java b/music-rest/src/test/java/org/onap/music/rest/RestMusicTestAPITest.java new file mode 100644 index 00000000..235367ce --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/rest/RestMusicTestAPITest.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ +package org.onap.music.rest; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.main.MusicUtil; + +public class RestMusicTestAPITest { + + RestMusicTestAPI restMusicTestAPI; + + @Before + public void setup() { + restMusicTestAPI = new RestMusicTestAPI(); + } + + @Test + public void testSimpleTests() { + HttpServletResponse httpServletResponse = Mockito.mock(HttpServletResponse.class); + doNothing().when(httpServletResponse).addHeader(Mockito.anyString(), Mockito.anyString()); + MusicUtil.setVersion("x.x.x"); + MusicUtil.setBuild("y.y"); + Map<String, HashMap<String, String>> map = restMusicTestAPI.simpleTests(httpServletResponse); + + Map<String, String> map1 = map.get("0"); + assertEquals("2", map1.get("1").toString()); + assertEquals("x.x.x", map1.get("Music Version").toString()); + assertEquals("y.y", map1.get("Music Build").toString()); + + Map<String, String> map2 = map.get("1"); + assertEquals("3", map2.get("2").toString()); + assertEquals("x.x.x", map2.get("Music Version").toString()); + assertEquals("y.y", map2.get("Music Build").toString()); + + Map<String, String> map3 = map.get("2"); + assertEquals("4", map3.get("3").toString()); + assertEquals("x.x.x", map3.get("Music Version").toString()); + assertEquals("y.y", map3.get("Music Build").toString()); + } +} diff --git a/music-rest/src/test/java/org/onap/music/rest/RestMusicVersionAPITest.java b/music-rest/src/test/java/org/onap/music/rest/RestMusicVersionAPITest.java new file mode 100644 index 00000000..6fc433e4 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/rest/RestMusicVersionAPITest.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + *******************************************************************************/ +package org.onap.music.rest; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doNothing; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.music.main.MusicUtil; + +public class RestMusicVersionAPITest { + + RestMusicVersionAPI restMusicVersionAPI; + + @Before + public void setup() { + restMusicVersionAPI = new RestMusicVersionAPI(); + } + + @Test + public void testVersion() { + MusicUtil.setVersion("x.x.x"); + HttpServletResponse httpServletResponse = Mockito.mock(HttpServletResponse.class); + doNothing().when(httpServletResponse).addHeader(Mockito.anyString(), Mockito.anyString()); + Map<String,Object> map = restMusicVersionAPI.version(httpServletResponse); + assertEquals("MUSIC:x.x.x", map.get("version").toString()); + assertEquals("SUCCESS", map.get("status").toString()); + } + + @Test + public void testBuild() { + MusicUtil.setBuild("y.y"); + MusicUtil.setVersion("x.x.x"); + HttpServletResponse httpServletResponse = Mockito.mock(HttpServletResponse.class); + doNothing().when(httpServletResponse).addHeader(Mockito.anyString(), Mockito.anyString()); + Map<String,Object> map = restMusicVersionAPI.build(httpServletResponse); + assertEquals("MUSIC:x.x.x", map.get("version").toString()); + assertEquals("SUCCESS", map.get("status").toString()); + assertEquals("MUSIC:y.y", map.get("build").toString()); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/CassandraCQL.java b/music-rest/src/test/java/org/onap/music/unittests/CassandraCQL.java new file mode 100644 index 00000000..7b116bc8 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/CassandraCQL.java @@ -0,0 +1,247 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +/** + * @author srupane + * + */ + +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +//import org.apache.thrift.transport.TTransportException; +import org.cassandraunit.utils.EmbeddedCassandraServerHelper; +import org.onap.music.datastore.MusicDataStore; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.lockingservice.cassandra.LockType; +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.Session; +import com.datastax.driver.extras.codecs.enums.EnumNameCodec; + +public class CassandraCQL { + public static final String createAdminKeyspace = "CREATE KEYSPACE admin WITH REPLICATION = " + + "{'class' : 'SimpleStrategy' , 'replication_factor': 1} AND DURABLE_WRITES = true"; + + public static final String createAdminTable = "CREATE TABLE admin.keyspace_master (" + " uuid uuid, keyspace_name text," + + " application_name text, is_api boolean," + + " password text, username text," + + " is_aaf boolean, PRIMARY KEY (uuid)\n" + ");"; + + public static final String createKeySpace = + "CREATE KEYSPACE IF NOT EXISTS testcassa WITH replication = " + +"{'class':'SimpleStrategy','replication_factor':1} AND durable_writes = true;"; + + public static final String dropKeyspace = "DROP KEYSPACE IF EXISTS testcassa"; + + public static final String createTableEmployees = + "CREATE TABLE IF NOT EXISTS testcassa.employees " + + "(vector_ts text,empid uuid,empname text,empsalary varint,address Map<text,text>,PRIMARY KEY (empname)) " + + "WITH comment='Financial Info of employees' " + + "AND compression={'sstable_compression':'DeflateCompressor','chunk_length_kb':64} " + + "AND compaction={'class':'SizeTieredCompactionStrategy','min_threshold':6};"; + + public static final String insertIntoTablePrepared1 = + "INSERT INTO testcassa.employees (vector_ts,empid,empname,empsalary) VALUES (?,?,?,?); "; + + public static final String insertIntoTablePrepared2 = + "INSERT INTO testcassa.employees (vector_ts,empid,empname,empsalary,address) VALUES (?,?,?,?,?);"; + + public static final String selectALL = "SELECT * FROM testcassa.employees;"; + + public static final String selectSpecific = + "SELECT * FROM testcassa.employees WHERE empname= ?;"; + + public static final String updatePreparedQuery = + "UPDATE testcassa.employees SET vector_ts=?,address= ? WHERE empname= ?;"; + + public static final String deleteFromTable = " "; + + public static final String deleteFromTablePrepared = " "; + + // Set Values for Prepared Query + + public static List<Object> setPreparedInsertValues1() { + + List<Object> preppreparedInsertValues1 = new ArrayList<>(); + String vectorTs = + String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + UUID empId = UUID.fromString("abc66ccc-d857-4e90-b1e5-df98a3d40cd6"); + BigInteger empSalary = BigInteger.valueOf(23443); + String empName = "Mr Test one"; + preppreparedInsertValues1.add(vectorTs); + preppreparedInsertValues1.add(empId); + preppreparedInsertValues1.add(empName); + preppreparedInsertValues1.add(empSalary); + return preppreparedInsertValues1; + } + + public static List<Object> setPreparedInsertValues2() { + + List<Object> preparedInsertValues2 = new ArrayList<>(); + String vectorTs = + String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + UUID empId = UUID.fromString("abc434cc-d657-4e90-b4e5-df4223d40cd6"); + BigInteger empSalary = BigInteger.valueOf(45655); + String empName = "Mr Test two"; + Map<String, String> address = new HashMap<>(); + preparedInsertValues2.add(vectorTs); + preparedInsertValues2.add(empId); + preparedInsertValues2.add(empName); + preparedInsertValues2.add(empSalary); + address.put("Street", "1 some way"); + address.put("City", "Some town"); + preparedInsertValues2.add(address); + return preparedInsertValues2; + } + + public static List<Object> setPreparedUpdateValues() { + + List<Object> preparedUpdateValues = new ArrayList<>(); + String vectorTs = + String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis()); + Map<String, String> address = new HashMap<>(); + preparedUpdateValues.add(vectorTs); + String empName = "Mr Test one"; + address.put("Street", "101 Some Way"); + address.put("City", "New York"); + preparedUpdateValues.add(address); + preparedUpdateValues.add(empName); + return preparedUpdateValues; + } + + // Generate Different Prepared Query Objects + /** + * Query Object for Get. + * + * @return + */ + public static PreparedQueryObject setPreparedGetQuery() { + + PreparedQueryObject queryObject = new PreparedQueryObject(); + String empName1 = "Mr Test one"; + queryObject.appendQueryString(selectSpecific); + queryObject.addValue(empName1); + return queryObject; + } + + /** + * Query Object 1 for Insert. + * + * @return {@link PreparedQueryObject} + */ + public static PreparedQueryObject setPreparedInsertQueryObject1() { + + PreparedQueryObject queryobject = new PreparedQueryObject(); + queryobject.appendQueryString(insertIntoTablePrepared1); + List<Object> values = setPreparedInsertValues1(); + if (!values.isEmpty() || values != null) { + for (Object o : values) { + queryobject.addValue(o); + } + } + return queryobject; + + } + + /** + * Query Object 2 for Insert. + * + * @return {@link PreparedQueryObject} + */ + public static PreparedQueryObject setPreparedInsertQueryObject2() { + + PreparedQueryObject queryobject = new PreparedQueryObject(); + queryobject.appendQueryString(insertIntoTablePrepared2); + List<Object> values = setPreparedInsertValues2(); + if (!values.isEmpty() || values != null) { + for (Object o : values) { + queryobject.addValue(o); + } + } + return queryobject; + + } + + /** + * Query Object for Update. + * + * @return {@link PreparedQueryObject} + */ + public static PreparedQueryObject setPreparedUpdateQueryObject() { + + PreparedQueryObject queryobject = new PreparedQueryObject(); + queryobject.appendQueryString(updatePreparedQuery); + List<Object> values = setPreparedUpdateValues(); + if (!values.isEmpty() || values != null) { + for (Object o : values) { + queryobject.addValue(o); + } + } + return queryobject; + + } + + private static ArrayList<String> getAllPossibleLocalIps() { + ArrayList<String> allPossibleIps = new ArrayList<String>(); + try { + Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); + while (en.hasMoreElements()) { + NetworkInterface ni = (NetworkInterface) en.nextElement(); + Enumeration<InetAddress> ee = ni.getInetAddresses(); + while (ee.hasMoreElements()) { + InetAddress ia = (InetAddress) ee.nextElement(); + allPossibleIps.add(ia.getHostAddress()); + } + } + } catch (SocketException e) { + System.out.println(e.getMessage()); + } + return allPossibleIps; + } + + public static MusicDataStore connectToEmbeddedCassandra() throws Exception { + System.setProperty("log4j.configuration", "log4j.properties"); + + String address = "localhost"; + + EmbeddedCassandraServerHelper.startEmbeddedCassandra(); + Cluster cluster = new Cluster.Builder().withoutJMXReporting().withoutMetrics().addContactPoint(address).withPort(9142).build(); + cluster.getConfiguration().getSocketOptions().setReadTimeoutMillis(5000); + EnumNameCodec<LockType> lockTypeCodec = new EnumNameCodec<LockType>(LockType.class); + cluster.getConfiguration().getCodecRegistry().register(lockTypeCodec); + + Session session = cluster.connect(); + + return new MusicDataStore(cluster, session); + } + +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/JsonResponseTest.java b/music-rest/src/test/java/org/onap/music/unittests/JsonResponseTest.java new file mode 100644 index 00000000..6af8c0d9 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/JsonResponseTest.java @@ -0,0 +1,167 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Modifications Copyright (c) 2018-2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.onap.music.lockingservice.cassandra.MusicLockState.LockStatus; +import org.onap.music.main.ResultType; +import org.onap.music.response.jsonobjects.JsonResponse; + +public class JsonResponseTest { + + JsonResponse result = null; + + @Test + public void testJsonResponseBooleanStringString() { + result = new JsonResponse(ResultType.SUCCESS).setError("error").setMusicVersion("version"); + assertEquals("error",result.getError()); + } + + @Test + public void testStatus() { + result = new JsonResponse(ResultType.SUCCESS); + result.setStatus(ResultType.SUCCESS); + assertEquals(ResultType.SUCCESS, result.getStatus()); + result = new JsonResponse(ResultType.FAILURE).setError("error").setMusicVersion("version"); + assertEquals(ResultType.FAILURE, result.getStatus()); + } + + @Test + public void testError() { + result = new JsonResponse(ResultType.FAILURE); + result.setError("error"); + assertTrue(result.getError().equals("error")); + result.setError(""); + assertFalse(result.getError().equals("error")); + } + + @Test + public void testVersion() { + result = new JsonResponse(ResultType.SUCCESS); + result.setMusicVersion("version"); + assertTrue(result.getMusicVersion().equals("version")); + result.setMusicVersion(""); + assertFalse(result.getMusicVersion().equals("version")); + } + + @Test + public void testToMap() { + result = new JsonResponse(ResultType.SUCCESS).setError("error").setMusicVersion("1.0"); + Map<String,Object> myMap = result.toMap(); + assertTrue(myMap.containsKey("status")); + assertEquals(ResultType.SUCCESS, myMap.get("status")); + assertEquals("error", myMap.get("error")); + assertEquals("1.0", myMap.get("version")); + + result = new JsonResponse(ResultType.FAILURE); + myMap = result.toMap(); + assertTrue(myMap.containsKey("status")); + assertEquals(ResultType.FAILURE, myMap.get("status")); + } + + @Test + public void testMessage() { + result = new JsonResponse(ResultType.SUCCESS); + result.setMessage("message"); + assertEquals("message", result.getMessage()); + + } + + @Test + public void testDataResult() { + result = new JsonResponse(ResultType.SUCCESS); + Map<String, HashMap<String, Object>> dataResult= new HashMap<>(); + result.setDataResult(dataResult); + assertEquals(dataResult, result.getDataResult()); + + } + + @Test + public void testLock() { + result = new JsonResponse(ResultType.SUCCESS); + result.setLock("lock"); + assertEquals("lock", result.getLock()); + + } + + @Test + public void testLockLease() { + result = new JsonResponse(ResultType.SUCCESS); + result.setLockLease("lockLease"); + assertEquals("lockLease", result.getLockLease()); + } + + @Test + public void testMusicBuild() { + result = new JsonResponse(ResultType.SUCCESS); + result.setMusicBuild("Build"); + assertEquals("Build", result.getMusicBuild()); + } + + @Test + public void testLockHolder() { + result = new JsonResponse(ResultType.SUCCESS); + List<String> lockHolders = new ArrayList<>(); + result.setLockHolder(lockHolders); + assertEquals(lockHolders, result.getLockHolder()); + } + + @Test + public void testLockStatus() { + result = new JsonResponse(ResultType.SUCCESS); + LockStatus status = LockStatus.LOCKED; + result.setLockStatus(status); + assertEquals(status, result.getLockStatus()); + + } + + @Test + public void testToString() { + result = new JsonResponse(ResultType.SUCCESS); + assertTrue(result.toString() instanceof String); + + } + + @Test + public void testLockHolders() { + result = new JsonResponse(ResultType.SUCCESS).setLock("lockName").setLockHolder("lockholder1"); + Map<String, Object> lockMap = (Map<String, Object>) result.toMap().get("lock"); + // assure that this is string for backwards compatibility + assertEquals("lockholder1", lockMap.get("lock-holder")); + + List<String> lockholders = new ArrayList<>(); + lockholders.add("lockholder1"); + lockholders.add("lockholder2"); + result.setLockHolder(lockholders); + lockMap = (Map<String, Object>) result.toMap().get("lock"); + assertEquals(lockMap.get("lock-holder"), lockholders); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/MusicDataStoreTest.java b/music-rest/src/test/java/org/onap/music/unittests/MusicDataStoreTest.java new file mode 100644 index 00000000..68e6f3dc --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/MusicDataStoreTest.java @@ -0,0 +1,170 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.Mock; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.onap.music.datastore.MusicDataStore; +import org.onap.music.datastore.PreparedQueryObject; + +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.TableMetadata; + +@RunWith(SpringJUnit4ClassRunner.class) +//@ActiveProfiles(profiles = "OrderRepositoryTest") +@ContextConfiguration +public class MusicDataStoreTest { + + static MusicDataStore dataStore; + static PreparedQueryObject testObject; + + @BeforeClass + public static void init()throws Exception { + dataStore = CassandraCQL.connectToEmbeddedCassandra(); + //CachingUtil.resetStatementBank(); + + } + + @AfterClass + public static void close() throws MusicServiceException, MusicQueryException { + + testObject = new PreparedQueryObject(); + testObject.appendQueryString(CassandraCQL.dropKeyspace); + dataStore.executePut(testObject, "eventual"); + //dataStore.close(); + //CachingUtil.resetStatementBank(); + } + + @Test + public void Test1_SetUp() throws MusicServiceException, MusicQueryException { + boolean result = false; + //CachingUtil.resetStatementBank(); + testObject = new PreparedQueryObject(); + testObject.appendQueryString(CassandraCQL.createKeySpace); + result = dataStore.executePut(testObject, "eventual");; + testObject = new PreparedQueryObject(); + testObject.appendQueryString(CassandraCQL.createTableEmployees); + result = dataStore.executePut(testObject, "eventual"); + assertEquals(true, result); + + } + + @Test + public void Test2_ExecutePut_eventual_insert() throws MusicServiceException, MusicQueryException { + testObject = CassandraCQL.setPreparedInsertQueryObject1(); + boolean result = dataStore.executePut(testObject, "eventual"); + assertEquals(true, result); + } + + @Test + public void Test3_ExecutePut_critical_insert() throws MusicServiceException, MusicQueryException { + testObject = CassandraCQL.setPreparedInsertQueryObject2(); + boolean result = dataStore.executePut(testObject, "Critical"); + assertEquals(true, result); + } + + @Test + public void Test4_ExecutePut_eventual_update() throws MusicServiceException, MusicQueryException { + testObject = CassandraCQL.setPreparedUpdateQueryObject(); + boolean result = false; + result = dataStore.executePut(testObject, "eventual"); + assertEquals(true, result); + } + + @Test + public void Test5_ExecuteEventualGet() throws MusicServiceException, MusicQueryException { + testObject = new PreparedQueryObject(); + testObject.appendQueryString(CassandraCQL.selectALL); + boolean result = false; + int count = 0; + ResultSet output = null; + output = dataStore.executeOneConsistencyGet(testObject); + System.out.println(output); + ; + for (Row row : output) { + count++; + System.out.println(row.toString()); + } + if (count == 2) { + result = true; + } + assertEquals(false, result); + } + + @Test + public void Test6_ExecuteCriticalGet() throws MusicServiceException, MusicQueryException { + testObject = CassandraCQL.setPreparedGetQuery(); + boolean result = false; + int count = 0; + ResultSet output = null; + output = dataStore.executeQuorumConsistencyGet(testObject); + System.out.println(output); + ; + for (Row row : output) { + count++; + System.out.println(row.toString()); + } + if (count == 1) { + result = true; + } + assertEquals(false, result); + } + + @Test(expected = NullPointerException.class) + public void Test7_exception() { + PreparedQueryObject queryObject = null; + try { + dataStore.executePut(queryObject, "critical"); + } catch (MusicQueryException | MusicServiceException e) { + System.out.println(e.getMessage()); + } + } + + @Test + public void Test8_columnDataType() { + DataType data = dataStore.returnColumnDataType("testCassa", "employees", "empName"); + String datatype = data.toString(); + assertEquals("text",datatype); + } + + @Test + public void Test8_columnMetdaData() { + TableMetadata data = dataStore.returnColumnMetadata("testCassa", "employees"); + assertNotNull(data); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/TestRestMusicQAPI.java b/music-rest/src/test/java/org/onap/music/unittests/TestRestMusicQAPI.java new file mode 100644 index 00000000..385a4698 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/TestRestMusicQAPI.java @@ -0,0 +1,975 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +//cjc import static org.junit.Assert.assertTrue; +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +//cjc import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mindrot.jbcrypt.BCrypt; +//cjcimport org.mindrot.jbcrypt.BCrypt; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.music.datastore.MusicDataStore; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.datastore.jsonobjects.JsonDelete; +import org.onap.music.datastore.jsonobjects.JsonInsert; +import org.onap.music.datastore.jsonobjects.JsonKeySpace; +//cjc import org.onap.music.datastore.jsonobjects.JsonKeySpace; +//import org.onap.music.datastore.jsonobjects.JsonOnboard; +import org.onap.music.datastore.jsonobjects.JsonSelect; +import org.onap.music.datastore.jsonobjects.JsonTable; +import org.onap.music.datastore.jsonobjects.JsonUpdate; +import org.onap.music.lockingservice.cassandra.CassaLockStore; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +//import org.onap.music.main.ResultType; +//import org.onap.music.rest.RestMusicAdminAPI; +import org.onap.music.rest.RestMusicDataAPI; +import org.onap.music.rest.RestMusicQAPI; +import org.springframework.test.util.ReflectionTestUtils; +import org.onap.music.rest.RestMusicLocksAPI; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.sun.jersey.core.util.Base64; +//import com.datastax.driver.core.DataType; +//import com.datastax.driver.core.ResultSet; +//import com.datastax.driver.core.Row; +import com.sun.jersey.core.util.MultivaluedMapImpl; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(MockitoJUnitRunner.class) +public class TestRestMusicQAPI { + + + //RestMusicAdminAPI admin = new RestMusicAdminAPI(); + RestMusicLocksAPI lock = new RestMusicLocksAPI(); + RestMusicQAPI qData = new RestMusicQAPI(); + static PreparedQueryObject testObject; + + @Mock + static HttpServletResponse http; + + @Mock + UriInfo info; + + static String appName = "TestApp"; + static String userId = "TestUser"; + static String password = "TestPassword"; + /* + static String appName = "com.att.ecomp.portal.demeter.aid";//"TestApp"; + static String userId = "m00468@portal.ecomp.att.com";//"TestUser"; + static String password = "happy123";//"TestPassword"; + */ + static String authData = userId+":"+password; + static String wrongAuthData = userId+":"+"pass"; + static String authorization = new String(Base64.encode(authData.getBytes())); + static String wrongAuthorization = new String(Base64.encode(wrongAuthData.getBytes())); + + static boolean isAAF = false; + static UUID uuid = UUID.fromString("abc66ccc-d857-4e90-b1e5-df98a3d40ce6"); + static String uuidS = "abc66ccc-d857-4e90-b1e5-df98a3d40ce6"; + static String keyspaceName = "testkscjc"; + static String tableName = "employees"; + static String xLatestVersion = "X-latestVersion"; + static String onboardUUID = null; + static String lockId = null; + static String lockName = "testkscjc.employees.sample3"; + static String majorV="3"; + static String minorV="0"; + static String patchV="1"; + static String aid=null; + static JsonKeySpace kspObject=null; + static RestMusicDataAPI data = new RestMusicDataAPI(); + static Response resp; + + @BeforeClass + public static void init() throws Exception { + try { + ReflectionTestUtils.setField(MusicDataStoreHandle.class, "mDstoreHandle", + CassandraCQL.connectToEmbeddedCassandra()); + MusicCore.setmLockHandle(new CassaLockStore(MusicDataStoreHandle.getDSHandle())); + + // System.out.println("before class keysp"); + //resp=data.createKeySpace(majorV,minorV,patchV,aid,appName,userId,password,kspObject,keyspaceName); + //System.out.println("after keyspace="+keyspaceName); + } catch (Exception e) { + System.out.println("before class exception "); + e.printStackTrace(); + } + // admin keyspace and table + testObject = new PreparedQueryObject(); + testObject.appendQueryString("CREATE KEYSPACE admin WITH REPLICATION = " + + "{'class' : 'SimpleStrategy' , " + + "'replication_factor': 1} AND DURABLE_WRITES = true"); + MusicCore.eventualPut(testObject); + testObject = new PreparedQueryObject(); + testObject.appendQueryString( + "CREATE TABLE admin.keyspace_master (" + " uuid uuid, keyspace_name text," + + " application_name text, is_api boolean," + + " password text, username text," + + " is_aaf boolean, PRIMARY KEY (uuid)\n" + ");"); + MusicCore.eventualPut(testObject); + + testObject = new PreparedQueryObject(); + testObject.appendQueryString( + "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)"); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), + MusicUtil.DEFAULTKEYSPACENAME)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt()))); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + MusicCore.eventualPut(testObject); + + testObject = new PreparedQueryObject(); + testObject.appendQueryString( + "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)"); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), + UUID.fromString("bbc66ccc-d857-4e90-b1e5-df98a3d40de6"))); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), + MusicUtil.DEFAULTKEYSPACENAME)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), "TestApp1")); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt()))); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), "TestUser1")); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + MusicCore.eventualPut(testObject); + + testObject = new PreparedQueryObject(); + testObject.appendQueryString( + "select uuid from admin.keyspace_master where application_name = ? allow filtering"); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + ResultSet rs = MusicCore.get(testObject); + List<Row> rows = rs.all(); + if (rows.size() > 0) { + System.out.println("#######UUID is:" + rows.get(0).getUUID("uuid")); + } + + JsonKeySpace jsonKeyspace = new JsonKeySpace(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> replicationInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + replicationInfo.put("class", "SimpleStrategy"); + replicationInfo.put("replication_factor", 1); + jsonKeyspace.setConsistencyInfo(consistencyInfo); + jsonKeyspace.setDurabilityOfWrites("true"); + jsonKeyspace.setKeyspaceName(keyspaceName); + jsonKeyspace.setReplicationInfo(replicationInfo); + Response response = data.createKeySpace(majorV, minorV, patchV, null, authorization, appName, + jsonKeyspace, keyspaceName); + System.out.println("#######status is " + response.getStatus()+" keyspace="+keyspaceName); + + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + System.out.println("After class"); + testObject = new PreparedQueryObject(); + testObject.appendQueryString("DROP KEYSPACE IF EXISTS " + keyspaceName); + MusicCore.eventualPut(testObject); + testObject = new PreparedQueryObject(); + testObject.appendQueryString("DROP KEYSPACE IF EXISTS admin"); + MusicCore.eventualPut(testObject); + MusicDataStore mds = (MusicDataStore) ReflectionTestUtils.getField(MusicDataStoreHandle.class, "mDstoreHandle"); + if (mds != null) + mds.close(); + } + + +/* @Test + public void Test1_createQ_good() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + jsonTable.setPartitionKey("emp_name"); + jsonTable.setClusteringKey("uuid"); + jsonTable.setClusteringOrder("uuid ASC"); + //System.out.println("cjc before print version, xLatestVersion="+xLatestVersion); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableName); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()); + System.out.println("Entity" + response.getEntity()); + assertEquals(200, response.getStatus()); + }*/ + + @Test + public void Test1_createQ_FieldsEmpty() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + /* + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + */ + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + //System.out.println("cjc before print version, xLatestVersion="+xLatestVersion); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableName); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("EmptyFields #######status is " + response.getStatus()); + System.out.println("Entity" + response.getEntity()); + assertNotEquals(200, response.getStatus()); + } +/* @Test + public void Test1_createQ_Clustergood() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPartitionKey("emp_name"); + jsonTable.setClusteringKey("emp_id"); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(200, response.getStatus()); + }*/ + +/* @Test + public void Test1_createQ_ClusterOrderGood1() throws Exception { + String tableNameC="testcjcO"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name,emp_id)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setFields(fields); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(200, response.getStatus()); + } */ + +/* @Test + public void Test1_createQ_PartitionKeygood() throws Exception { + String tableNameP="testcjcP"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name,emp_salary),emp_id)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setTableName(tableNameP); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setFields(fields); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameP); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameP); + System.out.println("Entity" + response.getEntity()); + assertEquals(200, response.getStatus()); + } */ + + @Test + public void Test1_createQ_PartitionKeybadclose() throws Exception { + String tableNameC="testcjcP1"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name,emp_salary),emp_id))"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name,emp_id"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setFields(fields); + //System.out.println("cjc before print version, xLatestVersion="+xLatestVersion); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + //assertEquals(400, response.getStatus()); + assertTrue(200 != response.getStatus()); + } + +/* @Test + public void Test1_createQ_ClusterOrderGood2() throws Exception { + String tableNameC="testcjcO1g"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name,emp_salary,emp_id)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name,emp_id"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC,emp_id DESC"); + jsonTable.setFields(fields); + //System.out.println("cjc before print version, xLatestVersion="+xLatestVersion); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(200, response.getStatus()); + } */ + + /* @Test + public void Test1_createQ_ColPkeyoverridesPrimaryKeyGood() throws Exception { + String tableNameC="testcjcPr"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name),emp_salary,emp_id)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name,emp_id"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC,emp_id DESC"); + jsonTable.setFields(fields); + //System.out.println("cjc before print version, xLatestVersion="+xLatestVersion); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(200, response.getStatus()); + //assertTrue(200 != response.getStatus()); + } */ + + @Test + public void Test1_createQ_ClusterOrderBad() throws Exception { + String tableNameC="testcjcO1b"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name,emp_id)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name,emp_id"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_id DESCx"); + jsonTable.setFields(fields); + //System.out.println("cjc before print version, xLatestVersion="+xLatestVersion); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + // "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, userId, password, + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + + @Test + public void Test3_createQ_0() throws Exception { + //duplicate testing ... + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + String tableNameDup=tableName+"X"; + jsonTable.setTableName(tableNameDup); + jsonTable.setFields(fields); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + jsonTable, keyspaceName, tableNameDup); + System.out.println("#######status for 1st time " + response.getStatus()); + System.out.println("Entity" + response.getEntity()); + + Response response0 = qData.createQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + jsonTable, keyspaceName, tableNameDup); + // 400 is the duplicate status found in response + // Music 113 duplicate testing + //import static org.junit.Assert.assertNotEquals; + System.out.println("#######status for 2nd time " + response0.getStatus()); + System.out.println("Entity" + response0.getEntity()); + + assertFalse("Duplicate table not created for "+tableNameDup, 200==response0.getStatus()); + //assertEquals(400, response0.getStatus()); + //assertNotEquals(200,response0.getStatus()); + } + + + // Improper keyspace + @Ignore + @Test + public void Test3_createQ2() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPartitionKey("emp_name"); + jsonTable.setTableName(tableName); + jsonTable.setClusteringKey("emp_salary"); + jsonTable.setClusteringOrder("emp_salary DESC"); + jsonTable.setFields(fields); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + jsonTable, "wrong", tableName); + System.out.println("#######status is " + response.getStatus()); + System.out.println("Entity" + response.getEntity()); + assertEquals(401, response.getStatus()); + } + + + +/* @Test + public void Test4_insertIntoQ() throws Exception { + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testName"); + values.put("emp_salary", 500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.insertIntoQ(majorV, minorV,patchV, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, tableName); + assertEquals(200, response.getStatus()); + }*/ + + + @Test + public void Test4_insertIntoQ_valuesEmpty() throws Exception { + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + /* + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testName"); + values.put("emp_salary", 500); + */ + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.insertIntoQ(majorV, minorV,patchV, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, tableName); + assertNotEquals(200, response.getStatus()); + } + +/* @Test + public void Test4_insertIntoQ2() throws Exception { + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "test1"); + values.put("emp_salary", 1500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.insertIntoQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + jsonInsert, keyspaceName, tableName); + assertEquals(200, response.getStatus()); + }*/ + + + +/* @Test + public void Test5_updateQ() throws Exception { + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + Map<String, Object> values = new HashMap<>(); + row.add("emp_name", "testName"); + row.add("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_salary", "2500"); + consistencyInfo.put("type", "atomic"); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.updateQ(majorV, minorV,patchV, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, tableName, info); + assertEquals(200, response.getStatus()); + }*/ + + @Test + public void Test5_updateQEmptyValues() throws Exception { + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + Map<String, Object> values = new HashMap<>(); + row.add("emp_name", "testName"); + //values.put("emp_salary", 2500); + consistencyInfo.put("type", "atomic"); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + //Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.updateQ(majorV, minorV,patchV, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, tableName, info); + assertNotEquals(200, response.getStatus()); + } + +/* @Test + public void Test6_filterQ() throws Exception { //select + JsonSelect jsonSelect = new JsonSelect(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testName"); + row.add("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + consistencyInfo.put("type", "atomic"); + jsonSelect.setConsistencyInfo(consistencyInfo); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.filter(majorV, minorV,patchV,"abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, keyspaceName, tableName, info); + HashMap<String,HashMap<String,Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + assertEquals("2500", ((HashMap<String,Object>) result.get("row 0")).get("emp_salary").toString()); + }*/ + +/* @Test + public void Test6_peekQ() throws Exception { //select + JsonSelect jsonSelect = new JsonSelect(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testName"); + consistencyInfo.put("type", "atomic"); + jsonSelect.setConsistencyInfo(consistencyInfo); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.peek(majorV, minorV,patchV,"abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, keyspaceName, tableName, info); + HashMap<String,HashMap<String,Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + if (result.isEmpty() ) assertTrue(true); + else assertFalse(false); + //assertEquals("2500", ((HashMap<String,Object>) result.get("row 0")).get("emp_salary").toString()); + }*/ +/* + @Test + public void Test6_peekQ_empty() throws Exception { //select + // row is not needed in thhis test + JsonSelect jsonSelect = new JsonSelect(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testName"); + consistencyInfo.put("type", "atomic"); + jsonSelect.setConsistencyInfo(consistencyInfo); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + UriInfo infoe= mockUriInfo("/peek?");//empty queryParam: cause exception + // infoe.setQueryParameters(""); + System.out.println("uriinfo="+infoe.getQueryParameters()); + Mockito.when(infoe.getQueryParameters()).thenReturn(row); + Response response = qData.peek(majorV, minorV,patchV,"abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, keyspaceName, tableName, infoe); + HashMap<String,HashMap<String,Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + if (result.isEmpty() ) assertTrue(true); + else assertFalse(false); + //assertEquals("2500", ((HashMap<String,Object>) result.get("row 0")).get("emp_salary").toString()); + }*/ + +/* @Test + public void Test6_deleteFromQ1() throws Exception { + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "test1"); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.deleteFromQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + jsonDelete, keyspaceName, tableName, info); + assertEquals(200, response.getStatus()); + }*/ + + // Values + @Test + @Ignore + public void Test6_deleteFromQ() throws Exception { + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.deleteFromQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + jsonDelete, keyspaceName, tableName, info); + assertEquals(400, response.getStatus()); + } + + // delObj + @Test + public void Test6_deleteFromQ2() throws Exception { + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "test1"); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + //Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = qData.deleteFromQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + null, keyspaceName, tableName, info); + assertEquals(400, response.getStatus()); + } +/* + @Test + public void Test7_dropQ() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonTable.setConsistencyInfo(consistencyInfo); + Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.dropQ(majorV, minorV,patchV, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + keyspaceName, tableName); + assertEquals(200, response.getStatus()); + }*/ + + private UriInfo mockUriInfo(String urix) throws URISyntaxException { + String uri="http://localhost:8080/MUSIC/rest/v"+majorV+"/priorityq/keyspaces/"+keyspaceName+"/"+tableName+urix; + UriInfo uriInfo = Mockito.mock(UriInfo.class); + System.out.println("mock urix="+urix+" uri="+uri); + Mockito.when(uriInfo.getRequestUri()).thenReturn(new URI(uri)); + return uriInfo; + } + + + //Empty Fields + @Test + public void Test8_createQ_fields_empty() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPartitionKey("emp_name"); + jsonTable.setClusteringKey("emp_id"); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setTableName(tableNameC); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + //Partition key null + @Test + public void Test8_createQ_partitionKey_empty() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setClusteringKey("emp_id"); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + //Clustering key null + @Test + public void Test8_createQ_ClusteringKey_empty() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPartitionKey("emp_name"); + jsonTable.setClusteringOrder("emp_id DESC"); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + //Clustering Order null + @Test + public void Test8_createQ_ClusteringOrder_empty() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPartitionKey("emp_name"); + jsonTable.setClusteringKey("emp_id"); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + //Invalid primary key + @Test + public void Test8_createQ_primaryKey_invalid() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setPrimaryKey("(emp_name"); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setClusteringKey("emp_id"); + jsonTable.setClusteringOrder("emp_id ASC"); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + //Primary key with no clustering key + @Test + public void Test8_createQ_primaryKey_with_empty_clusteringKey() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + jsonTable.setClusteringOrder("emp_id ASC"); + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + + } + + //Primary key with no partition key + @Test + public void Test8_createQ_primaryKey_with_empty_partitionKey() throws Exception { + String tableNameC="testcjcC"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "text"); + fields.put("emp_salary", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey(" "); + jsonTable.setTableName(tableNameC); + jsonTable.setFields(fields); + jsonTable.setClusteringOrder("emp_id ASC"); + + //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = qData.createQ(majorV, minorV,patchV, + aid, appName, authorization, + jsonTable, keyspaceName, tableNameC); + System.out.println("#######status is " + response.getStatus()+"table namec="+tableNameC); + System.out.println("Entity" + response.getEntity()); + assertEquals(400, response.getStatus()); + } + +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/TestsUsingCassandra.java b/music-rest/src/test/java/org/onap/music/unittests/TestsUsingCassandra.java new file mode 100644 index 00000000..cc7c5146 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/TestsUsingCassandra.java @@ -0,0 +1,116 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import java.util.List; +import java.util.UUID; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; +import org.mindrot.jbcrypt.BCrypt; +import org.onap.music.datastore.MusicDataStore; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.lockingservice.cassandra.CassaLockStore; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.springframework.test.util.ReflectionTestUtils; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.sun.jersey.core.util.Base64; + +@RunWith(Suite.class) +@SuiteClasses({ TstRestMusicDataAPI.class, TstRestMusicLockAPI.class, + TstRestMusicConditionalAPI.class}) +public class TestsUsingCassandra { + + static String appName = "TestApp"; + static String userId = "TestUser"; + static String password = "TestPassword"; + static String authData = userId+":"+password; + static String wrongAuthData = userId+":"+"pass"; + static String authorization = new String(Base64.encode(authData.getBytes())); + static String wrongAuthorization = new String(Base64.encode(wrongAuthData.getBytes())); + static boolean isAAF = false; + static UUID uuid = UUID.fromString("abc66ccc-d857-4e90-b1e5-df98a3d40ce6"); + static String keyspaceName = "testcassa"; + static String tableName = "employees"; + static String xLatestVersion = "X-latestVersion"; + static String onboardUUID = null; + static String aid = "abc66ccc-d857-4e90-b1e5-df98a3d40ce6"; + + @BeforeClass + public static void beforeClass() throws Exception { + ReflectionTestUtils.setField(MusicDataStoreHandle.class, "mDstoreHandle", + CassandraCQL.connectToEmbeddedCassandra()); + MusicCore.setmLockHandle(new CassaLockStore(MusicDataStoreHandle.getDSHandle())); + createAdminTable(); + } + + @AfterClass + public static void afterClass() { + PreparedQueryObject testObject = new PreparedQueryObject(); + testObject.appendQueryString("DROP KEYSPACE IF EXISTS admin"); + MusicCore.eventualPut(testObject); + MusicDataStore mds = (MusicDataStore) ReflectionTestUtils.getField(MusicDataStoreHandle.class, "mDstoreHandle"); + if (mds != null) + mds.close(); + } + + private static void createAdminTable() throws Exception { + PreparedQueryObject testObject = new PreparedQueryObject(); + testObject.appendQueryString(CassandraCQL.createAdminKeyspace); + MusicCore.eventualPut(testObject); + testObject = new PreparedQueryObject(); + testObject.appendQueryString(CassandraCQL.createAdminTable); + MusicCore.eventualPut(testObject); + + testObject = new PreparedQueryObject(); + testObject.appendQueryString( + "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)"); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), + keyspaceName)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), BCrypt.hashpw(password, BCrypt.gensalt()))); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + MusicCore.eventualPut(testObject); + + testObject = new PreparedQueryObject(); + testObject.appendQueryString( + "select uuid from admin.keyspace_master where application_name = ? allow filtering"); + testObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + ResultSet rs = MusicCore.get(testObject); + List<Row> rows = rs.all(); + if (rows.size() > 0) { + System.out.println("#######UUID is:" + rows.get(0).getUUID("uuid")); + onboardUUID = rows.get(0).getUUID("uuid").toString(); + } + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicConditionalAPI.java b/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicConditionalAPI.java new file mode 100644 index 00000000..7021178e --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicConditionalAPI.java @@ -0,0 +1,373 @@ +/* + * ============LICENSE_START========================================== org.onap.music + * =================================================================== Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import static org.junit.Assert.assertEquals; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mindrot.jbcrypt.BCrypt; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.music.conductor.conditionals.JsonConditional; +import org.onap.music.conductor.conditionals.RestMusicConditionalAPI; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.datastore.jsonobjects.JsonDelete; +import org.onap.music.datastore.jsonobjects.JsonInsert; +import org.onap.music.datastore.jsonobjects.JsonKeySpace; +import org.onap.music.datastore.jsonobjects.JsonSelect; +import org.onap.music.datastore.jsonobjects.JsonTable; +import org.onap.music.datastore.jsonobjects.JsonUpdate; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.rest.RestMusicDataAPI; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.sun.jersey.core.util.Base64; +import com.sun.jersey.core.util.MultivaluedMapImpl; + +@RunWith(MockitoJUnitRunner.class) +public class TstRestMusicConditionalAPI { + + RestMusicDataAPI data = new RestMusicDataAPI(); + RestMusicConditionalAPI cond = new RestMusicConditionalAPI(); + static PreparedQueryObject testObject; + + @Mock + HttpServletResponse http; + + @Mock + UriInfo info; + + static String appName = "TestApp"; + static String userId = "TestUser"; + static String password = "TestPassword"; + static String authData = userId + ":" + password; + static String wrongAuthData = userId + ":" + "pass"; + static String authorization = new String(Base64.encode(authData.getBytes())); + static String wrongAuthorization = new String(Base64.encode(wrongAuthData.getBytes())); + static boolean isAAF = false; + static UUID uuid = UUID.fromString("abc66ccc-d857-4e90-b1e5-df98a3d40ce6"); + static String keyspaceName = "testcassa"; + static String tableName = "employees"; + static String xLatestVersion = "X-latestVersion"; + static String onboardUUID = null; + + @BeforeClass + public static void init() throws Exception { + System.out.println("Testing RestMusicConditional class"); + try { + createKeyspace(); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Unable to initialize before TestRestMusicData test class. " + e.getMessage()); + } + } + + @After + public void afterEachTest() throws MusicServiceException { + clearAllTablesFromKeyspace(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + testObject = new PreparedQueryObject(); + testObject.appendQueryString("DROP KEYSPACE IF EXISTS " + keyspaceName); + MusicCore.eventualPut(testObject); + } + + @Test + public void test_insertIntoTable() throws Exception { + System.out.println("Testing conditional insert into table"); + createTable(); + + JsonConditional jsonCond = new JsonConditional(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("id", "test_id"); + consistencyInfo.put("type", "eventual"); + HashMap<String, Object> cascadeData = new HashMap<>(); + HashMap<String, String> cascadeValue = new HashMap<>(); + cascadeValue.put("created", "hello"); + cascadeValue.put("updated", "world"); + cascadeData.put("key", "p1"); + cascadeData.put("value", cascadeValue); + HashMap<String, Map<String, String>> condition = new HashMap<>(); + HashMap<String, String> exists = new HashMap<>(); + exists.put("status", "parked"); + HashMap<String, String> nonexists = new HashMap<>(); + nonexists.put("status", "underway"); + condition.put("exists", exists); + condition.put("nonexists", nonexists); + + jsonCond.setPrimaryKey("id"); + jsonCond.setPrimaryKeyValue("testname"); + jsonCond.setCasscadeColumnName("plans"); + jsonCond.setTableValues(values); + jsonCond.setCasscadeColumnData(cascadeData); + jsonCond.setConditions(condition); + + Response response = cond.insertConditional("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, keyspaceName, tableName, jsonCond); + + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + /* + * @Test public void test4_insertIntoTable2() throws Exception { System.out.println("Testing insert into table #2"); + * createTable(); JsonInsert jsonInsert = new JsonInsert(); Map<String, String> consistencyInfo = new HashMap<>(); + * Map<String, Object> values = new HashMap<>(); values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + * values.put("emp_name", "test1"); values.put("emp_salary", 1500); consistencyInfo.put("type", "eventual"); + * jsonInsert.setConsistencyInfo(consistencyInfo); jsonInsert.setKeyspaceName(keyspaceName); + * jsonInsert.setTableName(tableName); jsonInsert.setValues(values); Response response = data.insertIntoTable("1", + * "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, jsonInsert, keyspaceName, tableName); + * System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + * + * assertEquals(200, response.getStatus()); } + * + * // Auth Error + * + * @Test public void test4_insertIntoTable3() throws Exception { + * System.out.println("Testing insert into table with bad credentials"); createTable(); JsonInsert jsonInsert = new + * JsonInsert(); Map<String, String> consistencyInfo = new HashMap<>(); Map<String, Object> values = new + * HashMap<>(); values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); values.put("emp_name", "test1"); + * values.put("emp_salary", 1500); consistencyInfo.put("type", "eventual"); + * jsonInsert.setConsistencyInfo(consistencyInfo); jsonInsert.setKeyspaceName(keyspaceName); + * jsonInsert.setTableName(tableName); jsonInsert.setValues(values); Response response = data.insertIntoTable("1", + * "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, wrongAuthorization, jsonInsert, keyspaceName, + * tableName); System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + * + * assertEquals(401, response.getStatus()); } + * + * // Table wrong + * + * @Test public void test4_insertIntoTable4() throws Exception { + * System.out.println("Testing insert into wrong table"); createTable(); JsonInsert jsonInsert = new JsonInsert(); + * Map<String, String> consistencyInfo = new HashMap<>(); Map<String, Object> values = new HashMap<>(); + * values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); values.put("emp_name", "test1"); + * values.put("emp_salary", 1500); consistencyInfo.put("type", "eventual"); + * jsonInsert.setConsistencyInfo(consistencyInfo); jsonInsert.setKeyspaceName(keyspaceName); + * jsonInsert.setTableName(tableName); jsonInsert.setValues(values); Response response = data.insertIntoTable("1", + * "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, jsonInsert, keyspaceName, "wrong"); + * System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + * + * assertEquals(400, response.getStatus()); } + */ + + @Test + public void test5_updateTable() throws Exception { + System.out.println("Testing conditional update table"); + createAndInsertIntoTable(); + + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + + JsonConditional jsonCond = new JsonConditional(); + Map<String, Object> values = new HashMap<>(); + values.put("id", "test_id"); + HashMap<String, Object> cascadeData = new HashMap<>(); + HashMap<String, String> cascadeValue = new HashMap<>(); + cascadeValue.put("created", "hello"); + cascadeValue.put("updated", "world"); + cascadeData.put("key", "p1"); + cascadeData.put("value", cascadeValue); + + jsonCond.setPrimaryKey("id"); + jsonCond.setPrimaryKeyValue("test_id"); + jsonCond.setCasscadeColumnName("plans"); + jsonCond.setTableValues(values); + jsonCond.setCasscadeColumnData(cascadeData); + + Response response = cond.updateConditional("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, keyspaceName, tableName, jsonCond); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + /* + * // need mock code to create error for MusicCore methods + * + * @Test public void test5_updateTableAuthE() throws Exception { System.out.println("Testing update table #2"); + * createTable(); //MockitoAnnotations.initMocks(this); JsonUpdate jsonUpdate = new JsonUpdate(); Map<String, + * String> consistencyInfo = new HashMap<>(); MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + * Map<String, Object> values = new HashMap<>(); row.add("emp_name", "testname"); values.put("emp_salary", 2500); + * consistencyInfo.put("type", "atomic"); jsonUpdate.setConsistencyInfo(consistencyInfo); + * jsonUpdate.setKeyspaceName(keyspaceName); jsonUpdate.setTableName(tableName); jsonUpdate.setValues(values); //add + * ttl & timestamp //Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + * Mockito.when(info.getQueryParameters()).thenReturn(row); //Map<String, Object> m1= new HashMap<>() ; + * //Mockito.when(MusicCore.autheticateUser(appName,userId,password,keyspaceName, + * "abc66ccc-d857-4e90-b1e5-df98a3d40ce6","updateTable")).thenReturn(m1); Response response = data.updateTable("1", + * "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, jsonUpdate, keyspaceName, tableName, + * info); System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + * + * assertEquals(200, response.getStatus()); } + * + * @Ignore + * + * @Test public void test5_updateTableAuthException1() throws Exception { + * System.out.println("Testing update table authentication error"); createTable(); JsonUpdate jsonUpdate = new + * JsonUpdate(); Map<String, String> consistencyInfo = new HashMap<>(); MultivaluedMap<String, String> row = new + * MultivaluedMapImpl(); Map<String, Object> values = new HashMap<>(); row.add("emp_name", "testname"); + * values.put("emp_salary", 2500); consistencyInfo.put("type", "atomic"); + * jsonUpdate.setConsistencyInfo(consistencyInfo); jsonUpdate.setKeyspaceName(keyspaceName); + * jsonUpdate.setTableName(tableName); jsonUpdate.setValues(values); + * + * Mockito.when(info.getQueryParameters()).thenReturn(row); String authDatax = ":"; String authorizationx = new + * String(Base64.encode(authDatax.getBytes())); Response response = data.updateTable("1", "1", "1", + * "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorizationx, jsonUpdate, keyspaceName, tableName, info); + * System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + * + * assertEquals(401, response.getStatus()); } + * + * @Ignore + * + * @Test public void test5_updateTableAuthEmpty() throws Exception { + * System.out.println("Testing update table without authentication"); createTable(); + * + * JsonUpdate jsonUpdate = new JsonUpdate(); Map<String, String> consistencyInfo = new HashMap<>(); + * MultivaluedMap<String, String> row = new MultivaluedMapImpl(); Map<String, Object> values = new HashMap<>(); + * row.add("emp_name", "testname"); values.put("emp_salary", 2500); consistencyInfo.put("type", "atomic"); + * jsonUpdate.setConsistencyInfo(consistencyInfo); jsonUpdate.setKeyspaceName(keyspaceName); + * jsonUpdate.setTableName(tableName); jsonUpdate.setValues(values); + * + * Mockito.when(info.getQueryParameters()).thenReturn(row); String authDatax =":"+password; String authorizationx = + * new String(Base64.encode(authDatax.getBytes())); String appNamex="xx"; Response response = data.updateTable("1", + * "1", "1", "", appNamex, authorizationx, jsonUpdate, keyspaceName, tableName, info); System.out.println("Status: " + * + response.getStatus() + ". Entity " + response.getEntity()); + * + * assertEquals(401, response.getStatus()); } + * + */ + + private static void createKeyspace() throws Exception { + // shouldn't really be doing this here, but create keyspace is currently turned off + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString(CassandraCQL.createKeySpace); + MusicCore.eventualPut(query); + + boolean isAAF = false; + String hashedpwd = BCrypt.hashpw(password, BCrypt.gensalt()); + query = new PreparedQueryObject(); + query.appendQueryString("INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) values (?,?,?,?,?,?,?)"); + query.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspaceName)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + query.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), hashedpwd)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + query.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + MusicCore.eventualPut(query); + } + + private void clearAllTablesFromKeyspace() throws MusicServiceException { + ArrayList<String> tableNames = new ArrayList<>(); + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString( + "SELECT table_name FROM system_schema.tables WHERE keyspace_name = '" + keyspaceName + "';"); + ResultSet rs = MusicCore.get(query); + for (Row row : rs) { + tableNames.add(row.getString("table_name")); + } + for (String table : tableNames) { + query = new PreparedQueryObject(); + query.appendQueryString("DROP TABLE " + keyspaceName + "." + table); + MusicCore.eventualPut(query); + } + } + + /** + * Create a table {@link tableName} in {@link keyspaceName} + * + * @throws Exception + */ + private void createTable() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("id", "text"); + fields.put("plans", "map<text,text>"); + fields.put("PRIMARY KEY", "(id)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("id"); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableName); + } + + /** + * Create table {@link createTable} and insert into said table + * + * @throws Exception + */ + private void createAndInsertIntoTable() throws Exception { + createTable(); + + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + JsonConditional jsonCond = new JsonConditional(); + Map<String, Object> values = new HashMap<>(); + values.put("id", "test_id"); + HashMap<String, Object> cascadeData = new HashMap<>(); + HashMap<String, String> cascadeValue = new HashMap<>(); + cascadeValue.put("created", "hello"); + cascadeValue.put("updated", "world"); + cascadeData.put("key", "p1"); + cascadeData.put("value", cascadeValue); + HashMap<String, Map<String, String>> condition = new HashMap<>(); + HashMap<String, String> exists = new HashMap<>(); + exists.put("status", "parked"); + HashMap<String, String> nonexists = new HashMap<>(); + nonexists.put("status", "underway"); + condition.put("exists", exists); + condition.put("nonexists", nonexists); + + jsonCond.setPrimaryKey("id"); + jsonCond.setPrimaryKeyValue("test_id"); + jsonCond.setCasscadeColumnName("plans"); + jsonCond.setTableValues(values); + jsonCond.setCasscadeColumnData(cascadeData); + jsonCond.setConditions(condition); + + Response response = cond.insertConditional("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, keyspaceName, tableName, jsonCond); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicDataAPI.java b/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicDataAPI.java new file mode 100644 index 00000000..ea3fb54e --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicDataAPI.java @@ -0,0 +1,1161 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import static org.junit.Assert.assertEquals; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mindrot.jbcrypt.BCrypt; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.music.datastore.MusicDataStoreHandle; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.datastore.jsonobjects.JsonDelete; +import org.onap.music.datastore.jsonobjects.JsonInsert; +import org.onap.music.datastore.jsonobjects.JsonKeySpace; +import org.onap.music.datastore.jsonobjects.JsonSelect; +import org.onap.music.datastore.jsonobjects.JsonTable; +import org.onap.music.datastore.jsonobjects.JsonUpdate; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.main.ResultType; +import org.onap.music.rest.RestMusicDataAPI; +import org.onap.music.rest.RestMusicLocksAPI; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.sun.jersey.core.util.Base64; +import com.sun.jersey.core.util.MultivaluedMapImpl; + +@RunWith(MockitoJUnitRunner.class) +public class TstRestMusicDataAPI { + + RestMusicDataAPI data = new RestMusicDataAPI(); + RestMusicLocksAPI lock = new RestMusicLocksAPI(); + static PreparedQueryObject testObject; + + @Mock + HttpServletResponse http; + + @Mock + UriInfo info; + + static String appName = "TestApp"; + static String userId = "TestUser"; + static String password = "TestPassword"; + static String authData = userId + ":" + password; + static String wrongAuthData = userId + ":" + "pass"; + static String authorization = new String(Base64.encode(authData.getBytes())); + static String wrongAuthorization = new String(Base64.encode(wrongAuthData.getBytes())); + static boolean isAAF = false; + static UUID uuid = UUID.fromString("abc66ccc-d857-4e90-b1e5-df98a3d40ce6"); + static String keyspaceName = "testcassa"; + static String tableName = "employees"; + static String xLatestVersion = "X-latestVersion"; + static String onboardUUID = null; + static String aid = TestsUsingCassandra.aid; + + @BeforeClass + public static void init() throws Exception { + System.out.println("Testing RestMusicData class"); + try { + createKeyspace(); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Unable to initialize before TestRestMusicData test class. " + e.getMessage()); + } + } + + @After + public void afterEachTest() throws MusicServiceException { + clearAllTablesFromKeyspace(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + testObject = new PreparedQueryObject(); + testObject.appendQueryString("DROP KEYSPACE IF EXISTS " + keyspaceName); + MusicCore.eventualPut(testObject); + } + + @Test + public void test1_createKeyspace() throws Exception { + System.out.println("Testing create keyspace"); + JsonKeySpace jsonKeyspace = new JsonKeySpace(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> replicationInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + replicationInfo.put("class", "SimpleStrategy"); + replicationInfo.put("replication_factor", 1); + jsonKeyspace.setConsistencyInfo(consistencyInfo); + jsonKeyspace.setDurabilityOfWrites("true"); + jsonKeyspace.setKeyspaceName(keyspaceName); + jsonKeyspace.setReplicationInfo(replicationInfo); + // Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = + data.createKeySpace("1", "1", "1", null, authorization, appName, jsonKeyspace, keyspaceName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + Map<String, String> respMap = (Map<String, String>) response.getEntity(); + assertEquals(ResultType.FAILURE, respMap.get("status")); + } + + @Test + public void test1_createKeyspaceSuccess() throws Exception { + System.out.println("Testing successful creation and deletion of keyspace"); + MusicUtil.setKeyspaceActive(true); + + String keyspaceToCreate = "temp"+keyspaceName; + + + JsonKeySpace jsonKeyspace = new JsonKeySpace(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> replicationInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + replicationInfo.put("class", "SimpleStrategy"); + replicationInfo.put("replication_factor", 1); + jsonKeyspace.setConsistencyInfo(consistencyInfo); + jsonKeyspace.setDurabilityOfWrites("true"); + //don't overwrite a keyspace we already have + jsonKeyspace.setKeyspaceName(keyspaceToCreate); + jsonKeyspace.setReplicationInfo(replicationInfo); + // Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = + data.createKeySpace("1", "1", "1", null, authorization, appName, jsonKeyspace, keyspaceToCreate); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + Map<String, String> respMap = (Map<String, String>) response.getEntity(); + assertEquals(ResultType.SUCCESS, respMap.get("status")); + + response = data.dropKeySpace("1", "1", "1", null, authorization, appName, keyspaceToCreate); + assertEquals(200, response.getStatus()); + respMap = (Map<String, String>) response.getEntity(); + assertEquals(ResultType.SUCCESS, respMap.get("status")); + + //unset to not mess up any further tests + MusicUtil.setKeyspaceActive(false); + } + + @Test + public void test3_createTable() throws Exception { + System.out.println("Testing create table"); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test3_createTableNoBody() throws Exception { + System.out.println("Testing create table w/o body"); + + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, null, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test3_createTableNoName() throws Exception { + System.out.println("Testing create table without name"); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(""); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, ""); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test3_createTableNoFields() throws Exception { + System.out.println("Testing create table without fields"); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(""); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, ""); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + + @Test + public void test3_createTableClusterOrderBad() throws Exception { + System.out.println("Testing create table bad clustering"); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name,emp_salary)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name,emp_salary"); + jsonTable.setClusteringOrder("ASC"); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test3_createTable_withPropertiesNotNull() throws Exception { + System.out.println("Testing create table with properties"); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + Map<String, Object> properties = new HashMap<>(); + properties.put("comment", "Testing prperties not null"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + String tableName_prop = tableName + "_Prop"; + jsonTable.setTableName(tableName_prop); + jsonTable.setFields(fields); + jsonTable.setProperties(properties); + + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableName_prop); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test3_createTable_duplicateTable() throws Exception { + System.out.println("Testing creating duplicate tables"); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + String tableNameDup = tableName + "x"; + jsonTable.setTableName(tableNameDup); + jsonTable.setFields(fields); + // Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response1 = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameDup); + + Response response2 = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameDup); + System.out.println("Status: " + response2.getStatus() + ". Entity " + response2.getEntity()); + + assertEquals(400, response2.getStatus()); + Map<String, String> respMap = (Map<String, String>) response2.getEntity(); + assertEquals(ResultType.FAILURE, respMap.get("status")); + assertEquals("Already Exists Exception: Table " + keyspaceName + "." + tableNameDup + " already exists", respMap.get("error")); + } + + + // Improper parenthesis in key field + @Test + public void test3_createTable_badParanthesis() throws Exception { + System.out.println("Testing malformed create table request"); + String tableNameC = "testTable0"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name),emp_id)"); + fields.put("emp_id", "varint"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_id Desc"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + + // good clustering key + @Test + public void test3_createTable_1_clusterKey_good() throws Exception { + System.out.println("Testing create w/ clusterKey"); + + String tableNameC = "testTableC1"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name),emp_salary)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + // jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + // bad partition key=clustering key + @Test + public void test3_createTable_2_clusterKey_bad() throws Exception { + System.out.println("Testing create w/ bad clusterKey"); + String tableNameC = "testTableC2"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name),emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); // "PRIMARY KEY" overrides if primaryKey present + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + // good composite partition key,clustering key + @Test + public void test3_createTable_3_pfartition_clusterKey_good() throws Exception { + System.out.println("Testing create w/ composite partition key, clusterKey"); + + String tableNameC = "testTableC3"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "varint"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name,emp_id),emp_salary)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + // bad - wrong cols in order by of composite partition key,clustering key + @Test + public void test3_createTable_5_clusteringOrder_bad() throws Exception { + System.out.println("Testing create table bad request with clustering & composite keys"); + String tableNameC = "testTableC5"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_id", "varint"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((uuid,emp_name),emp_id,emp_salary)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_idx desc, emp_salary ASC"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + + // good clustering key, need to pass queryparameter + @Test + public void test3_createTableIndex_1() throws Exception { + System.out.println("Testing index in create table"); + String tableNameC = "testTableCinx"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name),emp_salary)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + // if 200 print to log otherwise fail assertEquals(200, response.getStatus()); + // info.setQueryParameters("index_name=inx_uuid"); + Map<String, String> queryParametersMap = new HashMap<String, String>(); + + queryParametersMap.put("index_name", "inxuuid"); + Mockito.when(info.getQueryParameters()).thenReturn(new MultivaluedHashMap<String, String>(queryParametersMap)); + response = data.createIndex("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + keyspaceName, tableNameC, "uuid", info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + // create index without table name + @Test + public void test3_createTableIndexNoName() throws Exception { + System.out.println("Testing index in create table w/o tablename"); + String tableNameC = "testTableCinx"; + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "((emp_name),emp_salary)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setTableName(tableNameC); + jsonTable.setClusteringOrder("emp_salary ASC"); + jsonTable.setFields(fields); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableNameC); + // if 200 print to log otherwise fail assertEquals(200, response.getStatus()); + // info.setQueryParameters("index_name=inx_uuid"); + Map<String, String> queryParametersMap = new HashMap<String, String>(); + + queryParametersMap.put("index_name", "inxuuid"); + response = data.createIndex("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, "", + "", "uuid", info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertIntoTable() throws Exception { + System.out.println("Testing insert into table"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + @Test + public void test4_insertIntoTableNoBody() throws Exception { + System.out.println("Testing insert into table w/o body"); + createTable(); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, null, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertIntoTableNoaValues() throws Exception { + System.out.println("Testing insert into table"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertIntoTableNoValues() throws Exception { + System.out.println("Testing insert into table"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertIntoTableCriticalNoLockID() throws Exception { + System.out.println("Testing critical insert into table without lockid"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + consistencyInfo.put("type", "critical"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertIntoTableAtomic() throws Exception { + System.out.println("Testing atomic insert into table without lockid"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + consistencyInfo.put("type", "atomic"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + @Test + public void test4_insertIntoTableNoName() throws Exception { + System.out.println("Testing insert into table w/o table name"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, "", ""); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertIntoTable2() throws Exception { + System.out.println("Testing insert into table #2"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "test1"); + values.put("emp_salary", 1500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + // Table wrong + @Test + public void test4_insertIntoTable4() throws Exception { + System.out.println("Testing insert into wrong table"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "test1"); + values.put("emp_salary", 1500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, "wrong"); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test4_insertBlobIntoTable() throws Exception { + System.out.println("Testing insert a blob into table"); + createTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + values.put("binary", "somestuffhere"); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + @Test + public void test5_updateTable() throws Exception { + System.out.println("Testing update table"); + createTable(); + + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + Map<String, Object> values = new HashMap<>(); + row.add("emp_name", "testname"); + values.put("emp_salary", 2500); + consistencyInfo.put("type", "atomic"); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, tableName, info); + + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + + public void test5_updateTableNoBody() throws Exception { + System.out.println("Testing update table no body"); + createTable(); + + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, null, keyspaceName, tableName, info); + + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test5_updateTable_tableDNE() throws Exception { + System.out.println("Testing update table that does not exist"); + createTable(); + + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("emp_salary", 2500); + consistencyInfo.put("type", "atomic"); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName("wrong_"+tableName); + jsonUpdate.setValues(values); + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, "wrong_"+ tableName, info); + + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test5_updateTableNoName() throws Exception { + System.out.println("Testing update table without tablename"); + createTable(); + + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("emp_salary", 2500); + consistencyInfo.put("type", "atomic"); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, "", "", info); + + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + // need mock code to create error for MusicCore methods + @Test + public void test5_updateTableAuthE() throws Exception { + System.out.println("Testing update table #2"); + createTable(); + // MockitoAnnotations.initMocks(this); + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + Map<String, Object> values = new HashMap<>(); + row.add("emp_name", "testname"); + values.put("emp_salary", 2500); + consistencyInfo.put("type", "atomic"); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + // add ttl & timestamp + // Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Mockito.when(info.getQueryParameters()).thenReturn(row); + // Map<String, Object> m1= new HashMap<>() ; + // Mockito.when(MusicCore.autheticateUser(appName,userId,password,keyspaceName,"abc66ccc-d857-4e90-b1e5-df98a3d40ce6","updateTable")).thenReturn(m1); + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, tableName, info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + @Test + public void test6_critical_selectAtomic() throws Exception { + System.out.println("Testing critical select atomic"); + createAndInsertIntoTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testname"); + consistencyInfo.put("type", "atomic"); + jsonInsert.setConsistencyInfo(consistencyInfo); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.selectCritical("1", "1", "1","abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, tableName,info); + HashMap<String,HashMap<String,Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + Map<String, String> row0 = (Map<String, String>) result.get("row 0"); + assertEquals("testname", row0.get("emp_name")); + assertEquals(BigInteger.valueOf(500), row0.get("emp_salary")); + } + + + @Test + public void test6_critical_select() throws Exception { + System.out.println("Testing critical select w/o body"); + createAndInsertIntoTable(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testname"); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.selectCritical("1", "1", "1","abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, null, keyspaceName, tableName,info); + HashMap<String,HashMap<String,Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + // Added during merge? + @Test + public void test6_critical_selectCritical_nolockid() throws Exception { + System.out.println("Testing critical select critical w/o lockid"); + createAndInsertIntoTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testname"); + consistencyInfo.put("type", "critical"); + jsonInsert.setConsistencyInfo(consistencyInfo); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.selectCritical("1", "1", "1","abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, tableName,info); + HashMap<String,HashMap<String,Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test6_critical_select_nulltable() throws Exception { + System.out.println("Testing critical select w/ null tablename"); + createAndInsertIntoTable(); + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonInsert.setConsistencyInfo(consistencyInfo); + Response response = data.selectCritical("1", "1", "1","abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, authorization, jsonInsert, keyspaceName, null,info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test6_select() throws Exception { + System.out.println("Testing select"); + createAndInsertIntoTable(); + JsonSelect jsonSelect = new JsonSelect(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testname"); + consistencyInfo.put("type", "atomic"); + jsonSelect.setConsistencyInfo(consistencyInfo); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.selectWithCritical("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, authorization, + null,keyspaceName, tableName, info); + HashMap<String, HashMap<String, Object>> map = (HashMap<String, HashMap<String, Object>>) response.getEntity(); + HashMap<String, Object> result = map.get("result"); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + Map<String, String> row0 = (Map<String, String>) result.get("row 0"); + assertEquals("testname", row0.get("emp_name")); + assertEquals(BigInteger.valueOf(500), row0.get("emp_salary")); + } + + @Test + public void test6_select_nullTablename() throws Exception { + System.out.println("Testing select w/ null tablename"); + createAndInsertIntoTable(); + JsonSelect jsonSelect = new JsonSelect(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonSelect.setConsistencyInfo(consistencyInfo); + Response response = data.selectWithCritical("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", + appName, wrongAuthorization,null, keyspaceName, null, info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test6_deleteFromTable() throws Exception { + System.out.println("Testing delete from table"); + createAndInsertIntoTable(); + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "test1"); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.deleteFromTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonDelete, keyspaceName, tableName, info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test6_deleteFromTable_missingTablename() throws Exception { + System.out.println("Testing delete from table w/ null tablename"); + createAndInsertIntoTable(); + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + Response response = data.deleteFromTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + wrongAuthorization, jsonDelete, keyspaceName, null, info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + // Values + @Ignore + @Test + public void test6_deleteFromTable1() throws Exception { + System.out.println("Testing delete from table missing delete object"); + createAndInsertIntoTable(); + + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + Mockito.when(info.getQueryParameters()).thenReturn(row); + Response response = data.deleteFromTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonDelete, keyspaceName, tableName, info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + // delObj + @Test + public void test6_deleteFromTable2() throws Exception { + System.out.println("Testing delete from table missing delete object"); + createAndInsertIntoTable(); + JsonDelete jsonDelete = new JsonDelete(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonDelete.setConsistencyInfo(consistencyInfo); + Response response = data.deleteFromTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, null, keyspaceName, tableName, info); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test7_dropTable() throws Exception { + System.out.println("Testing drop table"); + createTable(); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonTable.setConsistencyInfo(consistencyInfo); + Response response = data.dropTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, keyspaceName, tableName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + } + + @Test + public void test7_dropTable_nullTablename() throws Exception { + System.out.println("Testing drop table w/ null tablename"); + createTable(); + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + consistencyInfo.put("type", "atomic"); + jsonTable.setConsistencyInfo(consistencyInfo); + Response response = data.dropTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, keyspaceName, null); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + + @Test + public void test8_deleteKeyspace() throws Exception { + System.out.println("Testing drop keyspace"); + + JsonKeySpace jsonKeyspace = new JsonKeySpace(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> replicationInfo = new HashMap<>(); + consistencyInfo.put("type", "eventual"); + replicationInfo.put("class", "SimpleStrategy"); + replicationInfo.put("replication_factor", 1); + jsonKeyspace.setConsistencyInfo(consistencyInfo); + jsonKeyspace.setDurabilityOfWrites("true"); + jsonKeyspace.setKeyspaceName("TestApp1"); + jsonKeyspace.setReplicationInfo(replicationInfo); + Response response = data.dropKeySpace("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", authorization, + appName, keyspaceName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + private static void createKeyspace() throws Exception { + // shouldn't really be doing this here, but create keyspace is currently turned off + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString(CassandraCQL.createKeySpace); + MusicCore.eventualPut(query); + + boolean isAAF = false; + String hashedpwd = BCrypt.hashpw(password, BCrypt.gensalt()); + query = new PreparedQueryObject(); + query.appendQueryString("INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) values (?,?,?,?,?,?,?)"); + query.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspaceName)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + query.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), hashedpwd)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + query.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + MusicCore.eventualPut(query); + } + + private void clearAllTablesFromKeyspace() throws MusicServiceException { + ArrayList<String> tableNames = new ArrayList<>(); + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString( + "SELECT table_name FROM system_schema.tables WHERE keyspace_name = '" + keyspaceName + "';"); + ResultSet rs = MusicCore.get(query); + for (Row row : rs) { + tableNames.add(row.getString("table_name")); + } + for (String table : tableNames) { + query = new PreparedQueryObject(); + query.appendQueryString("DROP TABLE " + keyspaceName + "." + table); + MusicCore.eventualPut(query); + } + } + + /** + * Create a table {@link tableName} in {@link keyspaceName} + * + * @throws Exception + */ + private void createTable() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("binary", "blob"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + // Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableName); + } + + /** + * Create table {@link createTable} and insert into said table + * + * @throws Exception + */ + private void createAndInsertIntoTable() throws Exception { + createTable(); + + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + values.put("binary", "binarydatahere"); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicLockAPI.java b/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicLockAPI.java new file mode 100644 index 00000000..91781a34 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/TstRestMusicLockAPI.java @@ -0,0 +1,768 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mindrot.jbcrypt.BCrypt; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.datastore.jsonobjects.JsonInsert; +import org.onap.music.datastore.jsonobjects.JsonLeasedLock; +import org.onap.music.datastore.jsonobjects.JsonLock; +import org.onap.music.datastore.jsonobjects.JsonTable; +import org.onap.music.datastore.jsonobjects.JsonUpdate; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.lockingservice.cassandra.CassaLockStore; +import org.onap.music.lockingservice.cassandra.LockType; +import org.onap.music.main.MusicCore; +import org.onap.music.main.MusicUtil; +import org.onap.music.rest.RestMusicDataAPI; +import org.onap.music.rest.RestMusicLocksAPI; +import com.datastax.driver.core.DataType; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.sun.jersey.core.util.Base64; +import com.sun.jersey.core.util.MultivaluedMapImpl; + +@RunWith(MockitoJUnitRunner.class) +public class TstRestMusicLockAPI { + + + @Mock + UriInfo info; + + RestMusicLocksAPI lock = new RestMusicLocksAPI(); + RestMusicDataAPI data = new RestMusicDataAPI(); + static PreparedQueryObject testObject; + + static String appName = "TestApp"; + static String userId = "TestUser"; + static String password = "TestPassword"; + static String authData = userId + ":" + password; + static String wrongAuthData = userId + ":" + "pass"; + static String authorization = new String(Base64.encode(authData.getBytes())); + static String wrongAuthorization = new String(Base64.encode(wrongAuthData.getBytes())); + static boolean isAAF = false; + static UUID uuid = UUID.fromString("abc66ccc-d857-4e90-b1e5-df98a3d40ce6"); + static String keyspaceName = "testcassa"; + static String tableName = "employees"; + static String onboardUUID = null; + static String lockName = "testcassa.employees.testname"; + + @BeforeClass + public static void init() throws Exception { + System.out.println("Testing RestMusicLock class"); + try { + createKeyspace(); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Unable to initialize before TestRestMusicData test class. " + e.getMessage()); + } + } + + @After + public void afterEachTest() throws MusicServiceException { + clearAllTablesFromKeyspace(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + testObject = new PreparedQueryObject(); + testObject.appendQueryString("DROP KEYSPACE IF EXISTS " + keyspaceName); + MusicCore.eventualPut(testObject); + } + + @SuppressWarnings("unchecked") + @Test + public void test_createLockReference() throws Exception { + System.out.println("Testing create lockref"); + createAndInsertIntoTable(); + Response response = lock.createLockReference(lockName, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", null, null, appName); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + assertTrue(respMap.containsKey("lock")); + assertTrue(((Map<String, String>) respMap.get("lock")).containsKey("lock")); + } + + @Test + public void test_createBadLockReference() throws Exception { + System.out.println("Testing create bad lockref"); + createAndInsertIntoTable(); + Response response = lock.createLockReference("badlock", "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", null, null, appName); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test_createReadLock() throws Exception { + System.out.println("Testing create read lockref"); + createAndInsertIntoTable(); + JsonLock jsonLock = createJsonLock(LockType.READ); + Response response = lock.createLockReference(lockName, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", jsonLock, null, appName); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + assertTrue(respMap.containsKey("lock")); + assertTrue(((Map<String, String>) respMap.get("lock")).containsKey("lock")); + } + + @Test + public void test_createWriteLock() throws Exception { + System.out.println("Testing create read lockref"); + createAndInsertIntoTable(); + JsonLock jsonLock = createJsonLock(LockType.WRITE); + Response response = lock.createLockReference(lockName, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", jsonLock, null, appName); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + + assertEquals(200, response.getStatus()); + assertTrue(respMap.containsKey("lock")); + assertTrue(((Map<String, String>) respMap.get("lock")).containsKey("lock")); + } + + @Test + public void test_accquireLock() throws Exception { + System.out.println("Testing acquire lock"); + createAndInsertIntoTable(); + String lockRef = createLockReference(); + + Response response = + lock.accquireLock(lockRef, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test_acquireReadLock() throws Exception { + System.out.println("Testing acquire read lock"); + createAndInsertIntoTable(); + String lockRef = createLockReference(LockType.READ); + String lockRef2 = createLockReference(LockType.READ); + + Response response = + lock.accquireLock(lockRef, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + response = + lock.accquireLock(lockRef2, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test_acquireReadLockaFail() throws Exception { + System.out.println("Testing acquire read lock"); + createAndInsertIntoTable(); + String lockRef = createLockReference(LockType.WRITE); + String lockRef2 = createLockReference(LockType.READ); + + Response response = + lock.accquireLock(lockRef, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + response = + lock.accquireLock(lockRef2, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_writeWReadLock() throws Exception { + System.out.println("Testing writing with a read lock"); + createAndInsertIntoTable(); + String lockRef = createLockReference(LockType.READ); + + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("emp_salary", 2500); + consistencyInfo.put("type", "critical"); + consistencyInfo.put("lockId", lockRef); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testname"); + Mockito.when(info.getQueryParameters()).thenReturn(row); + + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, tableName, info); + + assertEquals(400, response.getStatus()); + } + + @Test + public void test_writeWWriteLock() throws Exception { + System.out.println("Testing writing with a read lock"); + createAndInsertIntoTable(); + String lockRef = createLockReference(LockType.WRITE); + + JsonUpdate jsonUpdate = new JsonUpdate(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("emp_salary", 2500); + consistencyInfo.put("type", "critical"); + consistencyInfo.put("lockId", lockRef); + jsonUpdate.setConsistencyInfo(consistencyInfo); + jsonUpdate.setKeyspaceName(keyspaceName); + jsonUpdate.setTableName(tableName); + jsonUpdate.setValues(values); + MultivaluedMap<String, String> row = new MultivaluedMapImpl(); + row.add("emp_name", "testname"); + Mockito.when(info.getQueryParameters()).thenReturn(row); + + Response response = data.updateTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonUpdate, keyspaceName, tableName, info); + + assertEquals(200, response.getStatus()); + } + + @Test + public void test_accquireLockWLease() throws Exception { + System.out.println("Testing acquire lock with lease"); + createAndInsertIntoTable(); + String lockRef = createLockReference(); + + JsonLeasedLock jsonLock = new JsonLeasedLock(); + jsonLock.setLeasePeriod(10000); // 10 second lease period? + Response response = lock.accquireLockWithLease(jsonLock, lockRef, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test_accquireBadLockWLease() throws Exception { + System.out.println("Testing acquire bad lock ref with lease"); + createAndInsertIntoTable(); + String lockRef = createLockReference(); + + JsonLeasedLock jsonLock = new JsonLeasedLock(); + jsonLock.setLeasePeriod(10000); // 10 second lease period? + Response response = lock.accquireLockWithLease(jsonLock, "badlock", "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_accquireBadLock() throws Exception { + System.out.println("Testing acquire lock that is not lock-holder"); + createAndInsertIntoTable(); + // This is required to create an initial loc reference. + String lockRef1 = createLockReference(); + // This will create the next lock reference, whcih will not be avalale yet. + String lockRef2 = createLockReference(); + + Response response = lock.accquireLock(lockRef2, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_accquireBadLockRef() throws Exception { + System.out.println("Testing acquire bad lock ref"); + createAndInsertIntoTable(); + // This is required to create an initial loc reference. + String lockRef1 = createLockReference(); + + Response response = lock.accquireLock("badlockref", "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_currentLockHolder() throws Exception { + System.out.println("Testing get current lock holder"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = + lock.enquireLock(lockName, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + assertEquals(lockRef, ((Map<String, String>) respMap.get("lock")).get("lock-holder")); + } + + @Test + public void test_nocurrentLockHolder() throws Exception { + System.out.println("Testing get current lock holder w/ bad lockref"); + createAndInsertIntoTable(); + + Response response = + lock.enquireLock(lockName, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_badcurrentLockHolder() throws Exception { + System.out.println("Testing get current lock holder w/ bad lockref"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = + lock.enquireLock("badlock", "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_holders() throws Exception { + System.out.println("Testing holders api"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = + lock.currentLockHolder(lockName, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + assertEquals(lockRef, ((Map<String, List>) respMap.get("lock")).get("lock-holder").get(0)); + } + + @Test + public void test_holdersbadRef() throws Exception { + System.out.println("Testing holders api w/ bad lockref"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = + lock.currentLockHolder("badname", "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_unLock() throws Exception { + System.out.println("Testing unlock"); + createAndInsertIntoTable(); + String lockRef = createLockReference(); + + Response response = + lock.unLock(lockRef, "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + @Test + public void test_unLockBadRef() throws Exception { + System.out.println("Testing unlock w/ bad lock ref"); + createAndInsertIntoTable(); + String lockRef = createLockReference(); + + Response response = + lock.unLock("badref", "1", "1", authorization, "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @Test + public void test_getLockState() throws Exception { + System.out.println("Testing get lock state"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = lock.currentLockState(lockName, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + Map<String,Object> respMap = (Map<String, Object>) response.getEntity(); + assertEquals(lockRef, ((Map<String,String>) respMap.get("lock")).get("lock-holder")); + } + + @Test + public void test_getLockStateBadRef() throws Exception { + System.out.println("Testing get lock state w/ bad ref"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = lock.currentLockState("badname", "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(400, response.getStatus()); + } + + @SuppressWarnings("unchecked") + @Test + public void test_deadlock() throws Exception { + System.out.println("Testing deadlock"); + createAndInsertIntoTable(); + insertAnotherIntoTable(); + + // Process 1 creates and acquires a lock on row 1 + JsonLock jsonLock = createJsonLock(LockType.WRITE); + Response responseCreate1 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLock, "process1", appName); + Map<String, Object> respMapCreate1 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate1 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + Response responseAcquire1 = + lock.accquireLock(lockRefCreate1, "1", "1", authorization, "abc66001-d857-4e90-b1e5-df98a3d40ce6", appName); + + // Process 2 creates and acquires a lock on row 2 + Response responseCreate2 = lock.createLockReference(lockName + "2", "1", "1", authorization, + "abcde002-d857-4e90-b1e5-df98a3d40ce6", jsonLock, "process2", appName); + Map<String, Object> respMapCreate2 = (Map<String, Object>) responseCreate2.getEntity(); + String lockRefCreate2 = ((Map<String, String>) respMapCreate2.get("lock")).get("lock"); + + Response responseAcquire2 = + lock.accquireLock(lockRefCreate2, "1", "1", authorization, "abc66002-d857-4e90-b1e5-df98a3d40ce6", appName); + + // Process 2 creates a lock on row 1 + Response responseCreate3 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde003-d857-4e90-b1e5-df98a3d40ce6", jsonLock, "process2", appName); + + // Process 1 creates a lock on row 2, causing deadlock + Response responseCreate4 = lock.createLockReference(lockName + "2", "1", "1", authorization, + "abcde004-d857-4e90-b1e5-df98a3d40ce6", jsonLock, "process1", appName); + Map<String, Object> respMapCreate4 = (Map<String, Object>) responseCreate4.getEntity(); + + System.out.println("Status: " + responseCreate4.getStatus() + ". Entity " + responseCreate4.getEntity()); + assertEquals(400, responseCreate4.getStatus()); + assertTrue(respMapCreate4.containsKey("error")); + assertTrue( ((String)respMapCreate4.get("error")).toLowerCase().indexOf("deadlock") > -1 ); + } + + + @SuppressWarnings("unchecked") + @Test + public void test_lockPromotion() throws Exception { + System.out.println("Testing lock promotion"); + createAndInsertIntoTable(); + insertAnotherIntoTable(); + + // creates a lock 1 + JsonLock jsonLock = createJsonLock(LockType.READ); + Response responseCreate1 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLock, "process1", appName); + Map<String, Object> respMapCreate1 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate1 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + Response respMapPromote = lock.promoteLock(lockRefCreate1, "1", "1", authorization); + System.out.println("Status: " + respMapPromote.getStatus() + ". Entity " + respMapPromote.getEntity()); + + assertEquals(200, respMapPromote.getStatus()); + } + + @SuppressWarnings("unchecked") + @Test + public void test_lockPromotionReadWrite() throws Exception { + System.out.println("Testing lock promotion with read and writes"); + createAndInsertIntoTable(); + insertAnotherIntoTable(); + + // creates a lock 1 + JsonLock jsonLockRead = createJsonLock(LockType.READ); + Response responseCreate1 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockRead, "process1", appName); + Map<String, Object> respMapCreate1 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate1 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + JsonLock jsonLockWrite = createJsonLock(LockType.WRITE); + Response responseCreate2 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockWrite, "process1", appName); + Map<String, Object> respMapCreate2 = (Map<String, Object>) responseCreate2.getEntity(); + String lockRefCreate2 = ((Map<String, String>) respMapCreate2.get("lock")).get("lock"); + + Response respMapPromote = lock.promoteLock(lockRefCreate1, "1", "1", authorization); + System.out.println("Status: " + respMapPromote.getStatus() + ". Entity " + respMapPromote.getEntity()); + + assertEquals(200, respMapPromote.getStatus()); + } + + @SuppressWarnings("unchecked") + @Test + public void test_lockPromotionWriteRead() throws Exception { + System.out.println("Testing lock promotion with reads not at top of queue"); + createAndInsertIntoTable(); + insertAnotherIntoTable(); + + // creates a lock 1 + JsonLock jsonLockWrite = createJsonLock(LockType.WRITE); + Response responseCreate2 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockWrite, "process1", appName); + Map<String, Object> respMapCreate2 = (Map<String, Object>) responseCreate2.getEntity(); + String lockRefCreate2 = ((Map<String, String>) respMapCreate2.get("lock")).get("lock"); + + // creates a lock 2 + JsonLock jsonLockRead = createJsonLock(LockType.READ); + Response responseCreate1 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockRead, "process1", appName); + Map<String, Object> respMapCreate1 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate1 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + Response respMapPromote = lock.promoteLock(lockRefCreate1, "1", "1", authorization); + System.out.println("Status: " + respMapPromote.getStatus() + ". Entity " + respMapPromote.getEntity()); + + assertEquals(200, respMapPromote.getStatus()); + } + + @SuppressWarnings("unchecked") + @Test + public void test_lockPromotion2Reads() throws Exception { + System.out.println("Testing lock promotion w/ 2 ReadLocks"); + createAndInsertIntoTable(); + insertAnotherIntoTable(); + + // creates a lock 1 + JsonLock jsonLockRead = createJsonLock(LockType.READ); + Response responseCreate1 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockRead, "process1", appName); + Map<String, Object> respMapCreate1 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate1 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + Response responseCreate2 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockRead, "process1", appName); + Map<String, Object> respMapCreate2 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate2 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + Response respMapPromote = lock.promoteLock(lockRefCreate1, "1", "1", authorization); + System.out.println("Status: " + respMapPromote.getStatus() + ". Entity " + respMapPromote.getEntity()); + + assertEquals(400, respMapPromote.getStatus()); + } + + @SuppressWarnings("unchecked") + @Test + public void test_2lockPromotions() throws Exception { + System.out.println("Testing 2 lock promotions"); + createAndInsertIntoTable(); + insertAnotherIntoTable(); + + // creates a lock 1 + JsonLock jsonLockRead = createJsonLock(LockType.READ); + Response responseCreate1 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockRead, "process1", appName); + Map<String, Object> respMapCreate1 = (Map<String, Object>) responseCreate1.getEntity(); + String lockRefCreate1 = ((Map<String, String>) respMapCreate1.get("lock")).get("lock"); + + Response responseCreate2 = lock.createLockReference(lockName, "1", "1", authorization, + "abcde001-d857-4e90-b1e5-df98a3d40ce6", jsonLockRead, "process1", appName); + Map<String, Object> respMapCreate2 = (Map<String, Object>) responseCreate2.getEntity(); + String lockRefCreate2 = ((Map<String, String>) respMapCreate2.get("lock")).get("lock"); + + Response respMapPromote = lock.promoteLock(lockRefCreate1, "1", "1", authorization); + System.out.println("Status: " + respMapPromote.getStatus() + ". Entity " + respMapPromote.getEntity()); + + assertEquals(400, respMapPromote.getStatus()); + + Response respMap2Promote = lock.promoteLock(lockRefCreate2, "1", "1", authorization); + System.out.println("Status: " + respMap2Promote.getStatus() + ". Entity " + respMap2Promote.getEntity()); + + assertEquals(400, respMapPromote.getStatus()); + } + + + + // Ignoring since this is now a duplicate of delete lock ref. + @Test + @Ignore + public void test_deleteLock() throws Exception { + System.out.println("Testing get lock state"); + createAndInsertIntoTable(); + + String lockRef = createLockReference(); + + Response response = lock.deleteLock(lockName, "1", "1", + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", authorization, appName); + System.out.println("Status: " + response.getStatus() + ". Entity " + response.getEntity()); + assertEquals(200, response.getStatus()); + } + + /** + * Create table and lock reference + * + * @return the lock ref created + * @throws Exception + */ + @SuppressWarnings("unchecked") + private String createLockReference() throws Exception { + Response response = lock.createLockReference(lockName, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", null, null, appName); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + return ((Map<String, String>) respMap.get("lock")).get("lock"); + } + + /** + * Create table and lock reference + * + * @return the lock ref created + * @throws Exception + */ + @SuppressWarnings("unchecked") + private String createLockReference(LockType lockType) throws Exception { + JsonLock jsonLock = createJsonLock(lockType); + Response response = lock.createLockReference(lockName, "1", "1", authorization, + "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", jsonLock, null, appName); + Map<String, Object> respMap = (Map<String, Object>) response.getEntity(); + return ((Map<String, String>) respMap.get("lock")).get("lock"); + } + + private static void createKeyspace() throws Exception { + // shouldn't really be doing this here, but create keyspace is currently turned off + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString(CassandraCQL.createKeySpace); + MusicCore.eventualPut(query); + + boolean isAAF = false; + String hashedpwd = BCrypt.hashpw(password, BCrypt.gensalt()); + query = new PreparedQueryObject(); + query.appendQueryString("INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, " + + "password, username, is_aaf) values (?,?,?,?,?,?,?)"); + query.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspaceName)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName)); + query.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True")); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), hashedpwd)); + query.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId)); + query.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF)); + //CachingUtil.updateMusicCache(keyspaceName, appName); + //CachingUtil.updateMusicValidateCache(appName, userId, hashedpwd); + MusicCore.eventualPut(query); + } + + private void clearAllTablesFromKeyspace() throws MusicServiceException { + ArrayList<String> tableNames = new ArrayList<>(); + PreparedQueryObject query = new PreparedQueryObject(); + query.appendQueryString( + "SELECT table_name FROM system_schema.tables WHERE keyspace_name = '" + keyspaceName + "';"); + ResultSet rs = MusicCore.get(query); + for (Row row : rs) { + tableNames.add(row.getString("table_name")); + } + for (String table : tableNames) { + query = new PreparedQueryObject(); + query.appendQueryString("DROP TABLE " + keyspaceName + "." + table); + MusicCore.eventualPut(query); + } + } + + /** + * Create a table {@link tableName} in {@link keyspaceName} + * + * @throws Exception + */ + private void createTable() throws Exception { + JsonTable jsonTable = new JsonTable(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, String> fields = new HashMap<>(); + fields.put("uuid", "text"); + fields.put("emp_name", "text"); + fields.put("emp_salary", "varint"); + fields.put("PRIMARY KEY", "(emp_name)"); + consistencyInfo.put("type", "eventual"); + jsonTable.setConsistencyInfo(consistencyInfo); + jsonTable.setKeyspaceName(keyspaceName); + jsonTable.setPrimaryKey("emp_name"); + jsonTable.setTableName(tableName); + jsonTable.setFields(fields); + // Mockito.doNothing().when(http).addHeader(xLatestVersion, MusicUtil.getVersion()); + Response response = data.createTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonTable, keyspaceName, tableName); + } + + /** + * Create table {@link createTable} and insert into said table + * + * @throws Exception + */ + private void createAndInsertIntoTable() throws Exception { + createTable(); + + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cfd66ccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname"); + values.put("emp_salary", 500); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abc66ccc-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + } + + private void insertAnotherIntoTable() throws Exception { + createTable(); + + JsonInsert jsonInsert = new JsonInsert(); + Map<String, String> consistencyInfo = new HashMap<>(); + Map<String, Object> values = new HashMap<>(); + values.put("uuid", "cccccccc-d857-4e90-b1e5-df98a3d40cd6"); + values.put("emp_name", "testname2"); + values.put("emp_salary", 700); + consistencyInfo.put("type", "eventual"); + jsonInsert.setConsistencyInfo(consistencyInfo); + jsonInsert.setKeyspaceName(keyspaceName); + jsonInsert.setTableName(tableName); + jsonInsert.setValues(values); + Response response = data.insertIntoTable("1", "1", "1", "abcdef00-d857-4e90-b1e5-df98a3d40ce6", appName, + authorization, jsonInsert, keyspaceName, tableName); + } + + private JsonLock createJsonLock(LockType lockType) { + JsonLock jsonLock = new JsonLock(); + jsonLock.setLockType(lockType); + return jsonLock; + } + +}
\ No newline at end of file diff --git a/music-rest/src/test/java/org/onap/music/unittests/authentication/AuthUtilTest.java b/music-rest/src/test/java/org/onap/music/unittests/authentication/AuthUtilTest.java new file mode 100644 index 00000000..b578bd66 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/authentication/AuthUtilTest.java @@ -0,0 +1,123 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests.authentication; + +import static org.junit.Assert.*; +import java.util.ArrayList; +import java.util.List; +import javax.servlet.ServletRequest; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aaf.cadi.CadiWrap; +import org.onap.aaf.cadi.Permission; +import org.onap.aaf.cadi.aaf.AAFPermission; +import org.onap.music.authentication.AuthUtil; + +public class AuthUtilTest { + + @Test + public void testGetAAFPermissions() { + CadiWrap cw = Mockito.mock(CadiWrap.class); + List<Permission> permList = new ArrayList<Permission>(); + Permission perm1 = Mockito.mock(AAFPermission.class); + permList.add(perm1); + Mockito.when(cw.getPermissions(Mockito.any())).thenReturn(permList); + + List<AAFPermission> returnedPerm = AuthUtil.getAAFPermissions(cw); + + assertEquals(perm1, returnedPerm.get(0)); + } + + @Test + public void testDecodeFunctionCode() throws Exception { + String toDecode = "some%2dthing.something.%2a"; + String decoded = AuthUtil.decodeFunctionCode(toDecode); + + assertEquals("some-thing.something.*", decoded); + } + + @Test + public void testIsAccessAllowed() throws Exception { + System.out.println("Request perms"); + assertTrue(AuthUtil.isAccessAllowed(createRequest("*", "*"), "testns")); + } + + @Test + public void testIsAccessNotAllowed() throws Exception { + System.out.println("Request to write when have read perms"); + assertFalse(AuthUtil.isAccessAllowed(createRequest("POST", "GET"), "testns")); + } + + @Test + public void testIsAccessAllowedNullRequest() { + try { + assertFalse(AuthUtil.isAccessAllowed(null, "namespace")); + fail("Should throw exception"); + } catch (Exception e) { + } + } + + @Test + public void testIsAccessAllowedNullNamespace() { + try { + assertFalse(AuthUtil.isAccessAllowed(createRequest(), null)); + fail("Should throw exception"); + } catch (Exception e) { + } + } + + @Test + public void testIsAccessAllowedEmptyNamespace() { + try { + assertFalse(AuthUtil.isAccessAllowed(createRequest(), "")); + fail("Should throw exception"); + } catch (Exception e) { + } + } + + /** + * + * @param permRequested 'PUT', 'POST', 'GET', or 'DELETE' + * @param permGranted '*' or 'GET' + * @return + */ + private ServletRequest createRequest(String permRequested, String permGranted) { + CadiWrap cw = Mockito.mock(CadiWrap.class); + List<Permission> permList = new ArrayList<Permission>(); + AAFPermission perm1 = Mockito.mock(AAFPermission.class); + Mockito.when(perm1.getType()).thenReturn("testns"); + Mockito.when(perm1.getKey()).thenReturn("org.onap.music.api.user.access|testns|" + permGranted); + + permList.add(perm1); + Mockito.when(cw.getPermissions(Mockito.any())).thenReturn(permList); + Mockito.when(cw.getRequestURI()).thenReturn("/v2/locks/create/testns.MyTable.Field1"); + Mockito.when(cw.getContextPath()).thenReturn("/v2/locks/create"); + Mockito.when(cw.getMethod()).thenReturn(permRequested); + + return cw; + } + + private ServletRequest createRequest() { + return createRequest("POST","*"); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/authentication/AuthorizationErrorTest.java b/music-rest/src/test/java/org/onap/music/unittests/authentication/AuthorizationErrorTest.java new file mode 100644 index 00000000..b432072a --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/authentication/AuthorizationErrorTest.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2019 IBM. + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ + +package org.onap.music.unittests.authentication; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.onap.music.authentication.AuthorizationError; + +public class AuthorizationErrorTest { + + private AuthorizationError authorizationError; + + @Before + public void setUp() { + authorizationError = new AuthorizationError(); + } + + @Test + public void testResponseCode() { + authorizationError.setResponseCode(400); + assertEquals(400, authorizationError.getResponseCode()); + } + + @Test + public void testResponseMessage() { + authorizationError.setResponseMessage("ResponseMessage"); + assertEquals("ResponseMessage", authorizationError.getResponseMessage()); + } +} diff --git a/music-rest/src/test/java/org/onap/music/unittests/authentication/CadiAuthFilterTest.java b/music-rest/src/test/java/org/onap/music/unittests/authentication/CadiAuthFilterTest.java new file mode 100644 index 00000000..eb6dde39 --- /dev/null +++ b/music-rest/src/test/java/org/onap/music/unittests/authentication/CadiAuthFilterTest.java @@ -0,0 +1,63 @@ +/* + * ============LICENSE_START========================================== + * org.onap.music + * =================================================================== + * Copyright (c) 2017 AT&T Intellectual Property + * =================================================================== + * Licensed 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. + * + * ============LICENSE_END============================================= + * ==================================================================== + */ +package org.onap.music.unittests.authentication; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aaf.cadi.PropAccess; +import org.onap.music.authentication.CadiAuthFilter; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import javax.servlet.FilterConfig; + +public class CadiAuthFilterTest { + + @Test + public void Test1() throws ServletException + { + PropAccess props=new PropAccess(); + CadiAuthFilter c=new CadiAuthFilter(props); + } + + + @Test + public void Test2() throws ServletException + { + CadiAuthFilter c=new CadiAuthFilter(); + } + + } + + diff --git a/music-rest/src/test/resources/logback.xml b/music-rest/src/test/resources/logback.xml new file mode 100644 index 00000000..6bc5fd5e --- /dev/null +++ b/music-rest/src/test/resources/logback.xml @@ -0,0 +1,302 @@ +<!-- + ============LICENSE_START========================================== + org.onap.music + =================================================================== + Copyright (c) 2017 AT&T Intellectual Property + =================================================================== + Licensed 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. + + ============LICENSE_END============================================= + ==================================================================== +--> +<configuration scan="true" scanPeriod="3 seconds"> + <!--<jmxConfigurator /> --> + <!-- directory path for all other type logs --> + <property name="logDir" value="/opt/app/music/logs" /> + + <!-- directory path for debugging type logs --> + <property name="debugDir" value="debug-logs" /> + + <!-- specify the component name --> + <!-- <property name="componentName" value="EELF"></property> --> + <property name="componentName" value="MUSIC"></property> + + <!-- log file names --> + <property name="generalLogName" value="music" /> + <property name="securityLogName" value="security" /> + <property name="errorLogName" value="error" /> + <property name="metricsLogName" value="metrics" /> + <property name="auditLogName" value="audit" /> + <property name="debugLogName" value="debug" /> + <property name="defaultPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n" /> + <!-- <property name="applicationLoggerPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %msg%n" /> --> + <property name="applicationLoggerPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %X{keyspace} - %msg%n" /> + <property name="auditLoggerPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" /> + <property name="metricsLoggerPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" /> + <!-- <property name="errorLoggerPattern" value= "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %msg%n " /> --> + <property name="errorLoggerPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level %X{keyspace} - %msg%n" /> + <property name="debugLoggerPattern" value="%date{ISO8601,UTC}|%X{RequestId}| %msg%n" ></property> + <property name="logDirectory" value="${logDir}/${componentName}" /> + <property name="debugLogDirectory" value="${debugDir}/${componentName}" /> + <!-- Example evaluator filter applied against console appender --> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <!-- <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> --> + <layout class=""> + <pattern> + %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + </pattern> + </layout> + </appender> + + <!-- ============================================================================ --> + <!-- EELF Appenders --> + <!-- ============================================================================ --> +<!-- <appender name="EELF" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${generalLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${generalLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>100MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${applicationLoggerPattern}</pattern> + </encoder> + </appender> --> + + <!-- <appender name="EELF" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${generalLogName}.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + daily rollover + <fileNamePattern>${logDirectory}/${generalLogName}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> + <maxFileSize>1GB</maxFileSize> + <maxHistory>5</maxHistory> + <totalSizeCap>5GB</totalSizeCap> + </rollingPolicy> + <encoder> + <pattern>${applicationLoggerPattern}</pattern> + </encoder> + </appender> --> + + + <appender name="EELF" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${generalLogName}.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + <!-- daily rollover --> + <fileNamePattern>${logDirectory}/${generalLogName}.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern> + <maxFileSize>1GB</maxFileSize> + <maxHistory>5</maxHistory> + <totalSizeCap>5GB</totalSizeCap> + </rollingPolicy> + <encoder> + <pattern>${applicationLoggerPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELF" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <includeCallerData>true</includeCallerData> + <appender-ref ref="EELF" /> + </appender> + + <!-- EELF Security Appender. This appender is used to record security events + to the security log file. Security events are separate from other loggers + in EELF so that security log records can be captured and managed in a secure + way separate from the other logs. This appender is set to never discard any + events. --> + <appender name="EELFSecurity" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${securityLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${securityLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n </pattern> + </encoder> + </appender> + + <appender name="asyncEELFSecurity" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <discardingThreshold>0</discardingThreshold> + <appender-ref ref="EELFSecurity" /> + </appender> + + + + + <!-- EELF Audit Appender. This appender is used to record audit engine + related logging events. The audit logger and appender are specializations + of the EELF application root logger and appender. This can be used to segregate + Policy engine events from other components, or it can be eliminated to record + these events as part of the application root log. --> + + <appender name="EELFAudit" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${auditLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${auditLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${auditLoggerPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFAudit" /> + </appender> + +<appender name="EELFMetrics" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${metricsLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${metricsLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - + %msg%n"</pattern> --> + <pattern>${metricsLoggerPattern}</pattern> + </encoder> + </appender> + + + <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFMetrics"/> + </appender> + + <appender name="EELFError" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${errorLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${errorLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${errorLoggerPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFError" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFError"/> + </appender> + + <appender name="EELFDebug" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${debugLogDirectory}/${debugLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${debugLogDirectory}/${debugLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${debugLoggerPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFDebug" /> + <includeCallerData>true</includeCallerData> + </appender> + + + <!-- ============================================================================ --> + <!-- EELF loggers --> + <!-- ============================================================================ --> + <logger name="com.att.eelf" level="info" additivity="false"> + <appender-ref ref="asyncEELF" /> + + </logger> + <logger name="com.att.eelf.security" level="info" additivity="false"> + <appender-ref ref="asyncEELFSecurity" /> + + </logger> + + + <logger name="com.att.eelf.audit" level="info" additivity="false"> + <appender-ref ref="asyncEELFAudit" /> + + </logger> + + <logger name="com.att.eelf.metrics" level="info" additivity="false"> + <appender-ref ref="asyncEELFMetrics" /> + + </logger> + + + <logger name="com.att.eelf.error" level="error" additivity="false"> + <appender-ref ref="asyncEELFError" /> + + </logger> + + <logger name="com.att.eelf.debug" level="debug" additivity="false"> + <appender-ref ref="asyncEELFDebug" /> + + </logger> + + <root level="INFO"> + <appender-ref ref="asyncEELF" /> + <!-- <appender-ref ref="STDOUT" /> --> + </root> + + <!-- Conductor Specific additions to squash WARNING and INFO --> + <logger name="com.datastax.driver.core.Cluster" level="ERROR"/> + <logger name="org.onap.music.main.MusicCore" level="ERROR"/> + +</configuration> |