Example usage for javax.management MBeanAttributeInfo isWritable

List of usage examples for javax.management MBeanAttributeInfo isWritable

Introduction

In this page you can find the example usage for javax.management MBeanAttributeInfo isWritable.

Prototype

public boolean isWritable() 

Source Link

Document

Whether new values can be written to the attribute.

Usage

From source file:org.hyperic.hq.plugin.jboss.MBeanUtil.java

public static OperationParams getAttributeParams(MBeanInfo info, String method, Object args[])
        throws PluginException {

    if (method.startsWith("set")) {
        method = method.substring(3);//from  w  w w . jav  a 2 s .c o  m
    }

    MBeanAttributeInfo[] attrs = info.getAttributes();
    for (int i = 0; i < attrs.length; i++) {
        MBeanAttributeInfo attr = attrs[i];
        if (!attr.getName().equals(method)) {
            continue;
        }
        if (!attr.isWritable()) {
            throw new PluginException("Attribute '" + method + "' is not writable");
        }

        String sig = attr.getType();
        if (!hasConverter(sig)) {
            String msg = "Cannot convert String argument to " + sig;
            throw new PluginException(msg);
        }

        if (args.length != 1) {
            String msg = "setAttribute(" + method + ") takes [1] argument, [" + args.length + "] given";
            throw new PluginException(msg);
        }

        OperationParams params = new OperationParams();
        Object value;
        try {
            value = convert(sig, (String) args[0]);
        } catch (Exception e) {
            String msg = "Exception converting param '" + args[0] + "' to type '" + sig + "'";
            throw new PluginException(msg + ": " + e);
        }
        params.arguments = new Object[] { value };
        params.isAttribute = true;
        return params;
    }

    return null;
}

From source file:org.jolokia.handler.list.AttributeDataUpdater.java

/** {@inheritDoc} */
@Override/*from  ww  w.ja  v a 2 s  .  c o m*/
protected JSONObject extractData(MBeanInfo pMBeanInfo, String attribute) {
    JSONObject attrMap = new JSONObject();

    for (MBeanAttributeInfo attrInfo : pMBeanInfo.getAttributes()) {
        if (attribute == null || attrInfo.getName().equals(attribute)) {
            JSONObject map = new JSONObject();
            map.put(TYPE.getKey(), attrInfo.getType());
            map.put(DESCRIPTION.getKey(), attrInfo.getDescription());
            map.put(READ_WRITE.getKey(), Boolean.valueOf(attrInfo.isWritable() && attrInfo.isReadable()));
            attrMap.put(attrInfo.getName(), map);
        }
    }
    return attrMap;
}

From source file:org.rifidi.edge.configuration.ConfigurationServiceImpl.java

@Override
public synchronized void storeConfiguration() {
    HashSet<DefaultConfigurationImpl> copy = new HashSet<DefaultConfigurationImpl>(IDToConfigurations.values());
    ConfigurationStore store = new ConfigurationStore();
    store.setServices(new ArrayList<ServiceStore>());
    for (DefaultConfigurationImpl config : copy) {
        ServiceStore serviceStore = new ServiceStore();
        serviceStore.setServiceID(config.getServiceID());
        serviceStore.setFactoryID(config.getFactoryID());

        Map<String, Object> configAttrs = config.getAttributes();
        Map<String, String> attributes = new HashMap<String, String>();
        try {/*from w w w. j  ava2s  .  c  om*/
            for (MBeanAttributeInfo attrInfo : config.getMBeanInfo().getAttributes()) {
                if (attrInfo.isWritable()) {
                    try {
                        attributes.put(attrInfo.getName(), configAttrs.get(attrInfo.getName()).toString());
                    } catch (NullPointerException ex) {
                        logger.error("No property: " + attrInfo.getName());
                    }
                }
            }
        } catch (NullPointerException ex) {
            logger.error("Problem with config: " + config);
        }
        serviceStore.setAttributes(attributes);
        try {
            RifidiService target = config.getTarget();
            if (target != null && target instanceof AbstractSensor<?>) {
                serviceStore.setSessionDTOs(new HashSet<SessionDTO>());
                for (SensorSession session : ((AbstractSensor<?>) target).getSensorSessions().values()) {
                    serviceStore.getSessionDTOs().add(session.getDTO());
                }
            }
        } catch (RuntimeException e) {
            logger.warn("Target went away while trying to store it: " + e);
        }
        store.getServices().add(serviceStore);
    }

    try {
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        File file = persistanceResource.getFile();
        marshaller.marshal(store, file);
        logger.info("configuration saved at " + file);
    } catch (IOException e) {
        logger.error(e);
    } catch (JAXBException e) {
        logger.error(e);
    }
}

From source file:org.opennms.tools.jmxconfiggenerator.jmxconfig.JmxDatacollectionConfiggenerator.java

public JmxDatacollectionConfig generateJmxConfigModel(MBeanServerConnection mBeanServerConnection,
        String serviceName, Boolean runStandardVmBeans, Boolean runWritableMBeans) {

    logger.debug("Startup values: \n serviceName: " + serviceName + "\n runStandardVmBeans: "
            + runStandardVmBeans + "\n runWritableMBeans: " + runWritableMBeans);
    JmxDatacollectionConfig xmlJmxDatacollectionConfig = xmlObjectFactory.createJmxDatacollectionConfig();
    JmxCollection xmlJmxCollection = xmlObjectFactory.createJmxCollection();

    xmlJmxCollection.setName("JSR160-" + serviceName);
    xmlJmxCollection.setRrd(rrd);/* w ww .jav  a2 s.  c  o m*/
    xmlJmxDatacollectionConfig.getJmxCollection().add(xmlJmxCollection);
    xmlJmxCollection.setMbeans(xmlObjectFactory.createMbeans());

    if (runStandardVmBeans) {
        ignores.clear();
    } else {
        ignores.addAll(standardVmBeans);
    }

    try {
        for (String domainName : mBeanServerConnection.getDomains()) {

            // just domains that are relevant for the service
            if (!ignores.contains(domainName)) {
                logger.debug("domain: " + domainName);

                // for all mBeans of the actual domain
                for (ObjectInstance jmxObjectInstance : mBeanServerConnection
                        .queryMBeans(new ObjectName(domainName + ":*"), null)) {
                    Mbean xmlMbean = xmlObjectFactory.createMbean();
                    xmlMbean.setObjectname(jmxObjectInstance.getObjectName().toString());
                    String typeAndOthers = StringUtils
                            .substringAfterLast(jmxObjectInstance.getObjectName().getCanonicalName(), "=");
                    xmlMbean.setName(domainName + "." + typeAndOthers);

                    logger.debug("\t" + jmxObjectInstance.getObjectName());

                    MBeanInfo jmxMbeanInfo;
                    try {
                        jmxMbeanInfo = mBeanServerConnection.getMBeanInfo(jmxObjectInstance.getObjectName());
                    } catch (InstanceNotFoundException e) {
                        logger.error("InstanceNotFoundException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (IntrospectionException e) {
                        logger.error("IntrospectionException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (ReflectionException e) {
                        logger.error("ReflectionException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (Throwable e) {
                        logger.error(
                                "problem during remote call to get MBeanInfo for '{}' skipping this MBean. Message '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    }

                    logger.debug("--- Attributes for " + jmxObjectInstance.getObjectName());

                    for (MBeanAttributeInfo jmxBeanAttributeInfo : jmxMbeanInfo.getAttributes()) {

                        // process just readable mbeans
                        if (jmxBeanAttributeInfo.isReadable()) {
                            // precess writable mbeans if run writable mbeans is set
                            if (!jmxBeanAttributeInfo.isWritable() || runWritableMBeans) {

                                logger.debug("Check mBean: '{}', attribute: '{}'",
                                        jmxObjectInstance.getObjectName().toString(),
                                        jmxBeanAttributeInfo.getName());
                                logger.debug("isWritable: '{}', type: '{}'", jmxBeanAttributeInfo.isWritable(),
                                        jmxBeanAttributeInfo.getType());

                                // check for CompositeData
                                if ("javax.management.openmbean.CompositeData"
                                        .equals(jmxBeanAttributeInfo.getType())) {
                                    logger.error("actual mBean: '{}'", jmxObjectInstance.getObjectName());
                                    CompAttrib compAttrib = createCompAttrib(mBeanServerConnection,
                                            jmxObjectInstance, jmxBeanAttributeInfo);
                                    if (compAttrib != null) {
                                        logger.debug("xmlMbean got CompAttrib");
                                        xmlMbean.getCompAttrib().add(compAttrib);
                                    }
                                }

                                if (numbers.contains(jmxBeanAttributeInfo.getType())) {
                                    Attrib xmlJmxAttribute = createAttr(jmxBeanAttributeInfo);
                                    logger.debug("Added MBean: '{}' Added attribute: '{}'",
                                            xmlMbean.getObjectname(),
                                            xmlJmxAttribute.getName() + " as " + xmlJmxAttribute.getAlias());
                                    xmlMbean.getAttrib().add(xmlJmxAttribute);
                                }
                            }
                        }
                    }

                    if (xmlMbean.getAttrib().size() > 0 || xmlMbean.getCompAttrib().size() > 0) {
                        xmlJmxCollection.getMbeans().getMbean().add(xmlMbean);
                    } else {
                        logger.debug("mbean: " + xmlMbean.getName() + " has no relavant attributes.");
                    }
                }
            } else {
                logger.debug("ignored: " + domainName);
            }
        }

    } catch (MalformedObjectNameException e) {
        logger.error("MalformedObjectNameException '{}'", e.getMessage());
    } catch (IOException e) {
        logger.error("IOException '{}'", e.getMessage());
    }

    return xmlJmxDatacollectionConfig;
}

From source file:org.opennms.jmxconfiggenerator.jmxconfig.JmxDatacollectionConfiggenerator.java

public JmxDatacollectionConfig generateJmxConfigModel(MBeanServerConnection mBeanServerConnection,
        String serviceName, Boolean runStandardVmBeans, Boolean runWritableMBeans,
        Map<String, String> dictionary) {

    logger.debug("Startup values: \n serviceName: " + serviceName + "\n runStandardVmBeans: "
            + runStandardVmBeans + "\n runWritableMBeans: " + runWritableMBeans + "\n dictionary" + dictionary);
    nameCutter.setDictionary(dictionary);
    JmxDatacollectionConfig xmlJmxDatacollectionConfig = xmlObjectFactory.createJmxDatacollectionConfig();
    JmxCollection xmlJmxCollection = xmlObjectFactory.createJmxCollection();

    xmlJmxCollection.setName("JSR160-" + serviceName);
    xmlJmxCollection.setRrd(rrd);//from   w  w  w.  jav  a 2  s .  co m
    xmlJmxDatacollectionConfig.getJmxCollection().add(xmlJmxCollection);
    xmlJmxCollection.setMbeans(xmlObjectFactory.createMbeans());

    if (runStandardVmBeans) {
        ignores.clear();
    } else {
        ignores.addAll(standardVmBeans);
    }

    try {
        for (String domainName : mBeanServerConnection.getDomains()) {

            // just domains that are relevant for the service
            if (!ignores.contains(domainName)) {
                logger.debug("domain: " + domainName);

                // for all mBeans of the actual domain
                for (ObjectInstance jmxObjectInstance : mBeanServerConnection
                        .queryMBeans(new ObjectName(domainName + ":*"), null)) {
                    Mbean xmlMbean = xmlObjectFactory.createMbean();
                    xmlMbean.setObjectname(jmxObjectInstance.getObjectName().toString());
                    String typeAndOthers = StringUtils
                            .substringAfterLast(jmxObjectInstance.getObjectName().getCanonicalName(), "=");
                    xmlMbean.setName(domainName + "." + typeAndOthers);

                    logger.debug("\t" + jmxObjectInstance.getObjectName());

                    MBeanInfo jmxMbeanInfo;
                    try {
                        jmxMbeanInfo = mBeanServerConnection.getMBeanInfo(jmxObjectInstance.getObjectName());
                    } catch (InstanceNotFoundException e) {
                        logger.error("InstanceNotFoundException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (IntrospectionException e) {
                        logger.error("IntrospectionException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (ReflectionException e) {
                        logger.error("ReflectionException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (Throwable e) {
                        logger.error(
                                "problem during remote call to get MBeanInfo for '{}' skipping this MBean. Message '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    }

                    logger.debug("--- Attributes for " + jmxObjectInstance.getObjectName());

                    for (MBeanAttributeInfo jmxBeanAttributeInfo : jmxMbeanInfo.getAttributes()) {

                        // process just readable mbeans
                        if (jmxBeanAttributeInfo.isReadable()) {
                            // precess writable mbeans if run writable mbeans is set
                            if (!jmxBeanAttributeInfo.isWritable() || runWritableMBeans) {

                                logger.debug("Check mBean: '{}', attribute: '{}'",
                                        jmxObjectInstance.getObjectName().toString(),
                                        jmxBeanAttributeInfo.getName());
                                logger.debug("isWritable: '{}', type: '{}'", jmxBeanAttributeInfo.isWritable(),
                                        jmxBeanAttributeInfo.getType());

                                // check for CompositeData
                                if ("javax.management.openmbean.CompositeData"
                                        .equals(jmxBeanAttributeInfo.getType())) {
                                    logger.error("actual mBean: '{}'", jmxObjectInstance.getObjectName());
                                    CompAttrib compAttrib = createCompAttrib(mBeanServerConnection,
                                            jmxObjectInstance, jmxBeanAttributeInfo);
                                    if (compAttrib != null) {
                                        logger.debug("xmlMbean got CompAttrib");
                                        xmlMbean.getCompAttrib().add(compAttrib);
                                    }
                                }

                                if (numbers.contains(jmxBeanAttributeInfo.getType())) {
                                    Attrib xmlJmxAttribute = createAttr(jmxBeanAttributeInfo);
                                    logger.debug("Added MBean: '{}' Added attribute: '{}'",
                                            xmlMbean.getObjectname(),
                                            xmlJmxAttribute.getName() + " as " + xmlJmxAttribute.getAlias());
                                    xmlMbean.getAttrib().add(xmlJmxAttribute);
                                }
                            }
                        }
                    }

                    if (xmlMbean.getAttrib().size() > 0 || xmlMbean.getCompAttrib().size() > 0) {
                        xmlJmxCollection.getMbeans().getMbean().add(xmlMbean);
                    } else {
                        logger.debug("mbean: " + xmlMbean.getName() + " has no relavant attributes.");
                    }
                }
            } else {
                logger.debug("ignored: " + domainName);
            }
        }

    } catch (MalformedObjectNameException e) {
        logger.error("MalformedObjectNameException '{}'", e.getMessage());
    } catch (IOException e) {
        logger.error("IOException '{}'", e.getMessage());
    }

    return xmlJmxDatacollectionConfig;
}

From source file:org.opennms.features.jmxconfiggenerator.jmxconfig.JmxDatacollectionConfiggenerator.java

public JmxDatacollectionConfig generateJmxConfigModel(MBeanServerConnection mBeanServerConnection,
        String serviceName, Boolean runStandardVmBeans, Boolean runWritableMBeans,
        Map<String, String> dictionary) {

    logger.debug("Startup values: \n serviceName: " + serviceName + "\n runStandardVmBeans: "
            + runStandardVmBeans + "\n runWritableMBeans: " + runWritableMBeans + "\n dictionary" + dictionary);
    nameCutter.setDictionary(dictionary);
    JmxDatacollectionConfig xmlJmxDatacollectionConfig = xmlObjectFactory.createJmxDatacollectionConfig();
    JmxCollection xmlJmxCollection = xmlObjectFactory.createJmxCollection();

    xmlJmxCollection.setName("JSR160-" + serviceName);
    xmlJmxCollection.setRrd(rrd);//ww w . j a  va  2  s.  c o m
    xmlJmxDatacollectionConfig.getJmxCollection().add(xmlJmxCollection);
    xmlJmxCollection.setMbeans(xmlObjectFactory.createMbeans());

    if (runStandardVmBeans) {
        ignores.clear();
    } else {
        ignores.addAll(standardVmBeans);
    }

    try {
        String[] domains = mBeanServerConnection.getDomains();
        logger.info("Found " + domains.length + " domains");
        logger.info("domains: " + Arrays.toString(domains));
        for (String domainName : domains) {

            // just domains that are relevant for the service
            if (!ignores.contains(domainName)) {
                logger.info("domain: " + domainName);

                // for all mBeans of the actual domain
                for (ObjectInstance jmxObjectInstance : mBeanServerConnection
                        .queryMBeans(new ObjectName(domainName + ":*"), null)) {
                    Mbean xmlMbean = xmlObjectFactory.createMbean();
                    xmlMbean.setObjectname(jmxObjectInstance.getObjectName().toString());
                    String typeAndOthers = StringUtils
                            .substringAfterLast(jmxObjectInstance.getObjectName().getCanonicalName(), "=");
                    xmlMbean.setName(domainName + "." + typeAndOthers);

                    logger.debug("\t" + jmxObjectInstance.getObjectName());

                    MBeanInfo jmxMbeanInfo;
                    try {
                        jmxMbeanInfo = mBeanServerConnection.getMBeanInfo(jmxObjectInstance.getObjectName());
                    } catch (InstanceNotFoundException e) {
                        logger.error("InstanceNotFoundException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (IntrospectionException e) {
                        logger.error("IntrospectionException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (ReflectionException e) {
                        logger.error("ReflectionException skipping MBean '{}' message: '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    } catch (Throwable e) {
                        logger.error(
                                "problem during remote call to get MBeanInfo for '{}' skipping this MBean. Message '{}'",
                                jmxObjectInstance.getObjectName(), e.getMessage());
                        continue;
                    }

                    logger.debug("--- Attributes for " + jmxObjectInstance.getObjectName());

                    for (MBeanAttributeInfo jmxBeanAttributeInfo : jmxMbeanInfo.getAttributes()) {

                        // process just readable mbeans
                        if (jmxBeanAttributeInfo.isReadable()) {
                            // precess writable mbeans if run writable
                            // mbeans is set
                            if (!jmxBeanAttributeInfo.isWritable() || runWritableMBeans) {

                                logger.debug("Check mBean: '{}', attribute: '{}'",
                                        jmxObjectInstance.getObjectName().toString(),
                                        jmxBeanAttributeInfo.getName());
                                logger.debug("isWritable: '{}', type: '{}'", jmxBeanAttributeInfo.isWritable(),
                                        jmxBeanAttributeInfo.getType());

                                // check for CompositeData
                                if ("javax.management.openmbean.CompositeData"
                                        .equals(jmxBeanAttributeInfo.getType())) {
                                    logger.error("actual mBean: '{}'", jmxObjectInstance.getObjectName());
                                    CompAttrib compAttrib = createCompAttrib(mBeanServerConnection,
                                            jmxObjectInstance, jmxBeanAttributeInfo);
                                    if (compAttrib != null) {
                                        logger.debug("xmlMbean got CompAttrib");
                                        xmlMbean.getCompAttrib().add(compAttrib);
                                    }
                                }

                                if (numbers.contains(jmxBeanAttributeInfo.getType())) {
                                    Attrib xmlJmxAttribute = createAttr(jmxBeanAttributeInfo);
                                    logger.debug("Added MBean: '{}' Added attribute: '{}'",
                                            xmlMbean.getObjectname(),
                                            xmlJmxAttribute.getName() + " as " + xmlJmxAttribute.getAlias());
                                    xmlMbean.getAttrib().add(xmlJmxAttribute);
                                }
                            }
                        }
                    }

                    if (xmlMbean.getAttrib().size() > 0 || xmlMbean.getCompAttrib().size() > 0) {
                        xmlJmxCollection.getMbeans().getMbean().add(xmlMbean);
                    } else {
                        logger.debug("mbean: " + xmlMbean.getName() + " has no relavant attributes.");
                    }
                }
            } else {
                logger.debug("ignored: " + domainName);
            }
        }

    } catch (MalformedObjectNameException e) {
        logger.error("MalformedObjectNameException '{}'", e.getMessage());
    } catch (IOException e) {
        logger.error("IOException '{}'", e.getMessage());
    }
    logger.debug("finish collection!");
    return xmlJmxDatacollectionConfig;
}

From source file:org.hyperic.hq.product.jmx.MxLiveDataPlugin.java

private Object queryMBeans(String pattern, Properties props) throws PluginException {

    MBeanServerConnection mServer;
    try {/*from w  w  w  .j a v  a2 s .  c o m*/
        mServer = MxUtil.getMBeanServer(props);
    } catch (Exception e) {
        throw new PluginException("getMBeanServer(" + props.getProperty(MxUtil.PROP_JMX_URL) + "): " + e, e);
    }
    ObjectName query;
    try {
        query = new ObjectName(pattern);
    } catch (Exception e) {
        throw new PluginException("Invalid query '" + pattern + "': " + e);
    }
    Map res = new HashMap();
    try {
        Iterator beans = mServer.queryNames(query, null).iterator();
        while (beans.hasNext()) {
            ObjectName obj = (ObjectName) beans.next();
            Map bean = new HashMap();
            Map attrs = new LinkedHashMap();
            bean.put(PROP_ATTRIBUTE + "s", attrs);
            res.put(obj.toString(), bean);

            MBeanInfo info = mServer.getMBeanInfo(obj);
            MBeanAttributeInfo[] attrInfo = info.getAttributes();
            for (int i = 0; i < attrInfo.length; i++) {
                MBeanAttributeInfo mia = attrInfo[i];
                String name = mia.getName();
                Map attr = new HashMap();
                Object val;
                try {
                    val = mServer.getAttribute(obj, name);
                } catch (Exception e) {
                    continue; //XXX
                }

                if (val == null) {
                    val = "-";
                }
                attr.put("Value", val);
                attr.put("Description", mia.getDescription());
                attr.put("isWritable", new Boolean(mia.isWritable()));
                attrs.put(name, attr);
            }

            bean.put(PROP_METHOD + "s", info.getOperations());
        }
    } catch (Exception e) {
        throw new PluginException("Error in query '" + pattern + "': " + e, e);
    }

    return res;
}

From source file:org.springframework.jmx.access.MBeanClientInterceptor.java

@Nullable
private Object invokeAttribute(PropertyDescriptor pd, MethodInvocation invocation)
        throws JMException, IOException {

    Assert.state(this.serverToUse != null, "No MBeanServerConnection available");

    String attributeName = JmxUtils.getAttributeName(pd, this.useStrictCasing);
    MBeanAttributeInfo inf = this.allowedAttributes.get(attributeName);
    // If no attribute is returned, we know that it is not defined in the
    // management interface.
    if (inf == null) {
        throw new InvalidInvocationException(
                "Attribute '" + pd.getName() + "' is not exposed on the management interface");
    }//  w  w  w .jav  a2s .  c om

    if (invocation.getMethod().equals(pd.getReadMethod())) {
        if (inf.isReadable()) {
            return this.serverToUse.getAttribute(this.objectName, attributeName);
        } else {
            throw new InvalidInvocationException("Attribute '" + attributeName + "' is not readable");
        }
    } else if (invocation.getMethod().equals(pd.getWriteMethod())) {
        if (inf.isWritable()) {
            this.serverToUse.setAttribute(this.objectName,
                    new Attribute(attributeName, invocation.getArguments()[0]));
            return null;
        } else {
            throw new InvalidInvocationException("Attribute '" + attributeName + "' is not writable");
        }
    } else {
        throw new IllegalStateException(
                "Method [" + invocation.getMethod() + "] is neither a bean property getter nor a setter");
    }
}