* Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
package org.apache.brooklyn.entity.database.derby;

import static java.lang.String.format;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.management.ObjectName;

import org.apache.brooklyn.core.entity.AbstractEntity;
import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
import org.apache.brooklyn.util.core.flags.SetFromFlag;
import org.apache.brooklyn.entity.database.Schema;

import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.entity.java.UsesJmx;
import org.apache.brooklyn.feed.jmx.JmxAttributePollConfig;
import org.apache.brooklyn.feed.jmx.JmxFeed;
import org.apache.brooklyn.feed.jmx.JmxHelper;
import org.apache.brooklyn.api.sensor.AttributeSensor;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.exceptions.Exceptions;

import com.google.common.base.Objects.ToStringHelper;

public class DerbySchema extends AbstractEntity implements Schema {

    // FIXME Needs reviewed and implemented properly; while fixing compilation errors
    // I added enough for it to look mostly plausible but it's completely untested.
    // And I have not looked up the derby docs to check that the attributes etc are valid. 
    // TODO Somehow share jmx connection with DerbyDatabase instance
    // TODO Declare effectors
    public static AttributeSensor<Integer> SCHEMA_DEPTH = new BasicAttributeSensor<Integer>(
            Integer.class, "derby.schema.depth", "schema depth");
    public static AttributeSensor<Integer> MESSAGE_COUNT = new BasicAttributeSensor<Integer>(
            Integer.class, "derby.schema.messageCount", "message count");
    String virtualHost;
    String name;

    protected ObjectName virtualHostManager;
    protected ObjectName exchange;

    transient JmxHelper jmxHelper;
    transient JmxFeed jmxFeed;
    public DerbySchema() {
        super(MutableMap.of(), null);
    public DerbySchema(Map properties) {
        super(properties, null);
    public DerbySchema(Entity parent) {
        this(MutableMap.of(), parent);
    public DerbySchema(Map properties, Entity parent) {
        super(properties, parent);
    public String getName() {
        return name;
    public DerbyDatabase getParent() {
        return (DerbyDatabase) super.getParent();
     * Return the JDBC connection URL for the schema.
    public String getConnectionUrl() { return String.format("jdbc:derby:%s", name); }

    public void init() {
        try {
            virtualHostManager = new ObjectName(format("org.apache.derby:type=VirtualHost.VirtualHostManager,VirtualHost=\"%s\"", virtualHost));
            exchange = new ObjectName(format("org.apache.derby:type=VirtualHost.Exchange,VirtualHost=\"%s\",name=\"amq.direct\",ExchangeType=direct", virtualHost));

            jmxHelper = new JmxHelper(getParent());

            ObjectName schemaMBeanName = new ObjectName(format("org.apache.derby:type=VirtualHost.Schema,VirtualHost=\"%s\",name=\"%s\"", virtualHost, name));

            jmxFeed = JmxFeed.builder()
                    .period(500, TimeUnit.MILLISECONDS)
                    .pollAttribute(new JmxAttributePollConfig<Integer>(SCHEMA_DEPTH)
                    .pollAttribute(new JmxAttributePollConfig<Integer>(MESSAGE_COUNT)
        } catch (Exception e) {
            throw Exceptions.propagate(e);

    public void create() {
        jmxHelper.operation(virtualHostManager, "createNewSchema", name, getParent().getAttribute(UsesJmx.JMX_USER), true);
        jmxHelper.operation(exchange, "createNewBinding", name, name);

    public void remove() {
        jmxHelper.operation(exchange, "removeBinding", name, name);
        jmxHelper.operation(virtualHostManager, "deleteSchema", name);

    public void destroy() {
        if (jmxFeed != null) jmxFeed.stop();

    protected ToStringHelper toStringHelper() {
        return super.toStringHelper().add("name", name);