001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.model;
018    
019    import java.util.HashMap;
020    import java.util.Map;
021    import java.util.concurrent.atomic.AtomicInteger;
022    
023    import javax.xml.bind.annotation.XmlAccessType;
024    import javax.xml.bind.annotation.XmlAccessorType;
025    import javax.xml.bind.annotation.XmlAttribute;
026    import javax.xml.bind.annotation.XmlElement;
027    import javax.xml.bind.annotation.XmlID;
028    import javax.xml.bind.annotation.XmlTransient;
029    import javax.xml.bind.annotation.XmlType;
030    import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
031    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
032    
033    /**
034     * Allows an element to have an optional ID specified
035     *
036     * @version $Revision: 765910 $
037     */
038    @XmlType(name = "optionalIdentifiedType")
039    @XmlAccessorType(XmlAccessType.FIELD)
040    public abstract class OptionalIdentifiedType<T extends OptionalIdentifiedType> {
041        @XmlTransient
042        protected static Map<String, AtomicInteger> nodeCounters = new HashMap<String, AtomicInteger>();
043        @XmlAttribute(required = false)
044        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
045        @XmlID
046        private String id;
047        @XmlTransient
048        private boolean customId;
049        @XmlElement(required = false)
050        private DescriptionDefinition description;
051    
052    
053        /**
054         * Gets the value of the id property.
055         */
056        public String getId() {
057            return id;
058        }
059    
060        /**
061         * Sets the value of the id property.
062         */
063        public void setId(String value) {
064            this.id = value;
065            customId = true;
066        }
067    
068        public DescriptionDefinition getDescription() {
069            return description;
070        }
071    
072        public void setDescription(DescriptionDefinition description) {
073            this.description = description;
074        }
075    
076        /**
077         * Returns a short name for this node which can be useful for ID generation or referring to related resources like images
078         *
079         * @return defaults to "node" but derived nodes should overload this to provide a unique name
080         */
081        public String getShortName() {
082            return "node";
083        }
084    
085        // Fluent API
086        // -------------------------------------------------------------------------
087    
088        /**
089         * Sets the description of this node
090         *
091         * @param id  sets the id, use null to not set an id
092         * @param text  sets the text description, use null to not set a text
093         * @param lang  sets the language for the description, use null to not set a language
094         * @return the builder
095         */
096        @SuppressWarnings("unchecked")
097        public T description(String id, String text, String lang) {
098            if (id != null) {
099                setId(id);
100            }
101            if (text != null) {
102                if (description == null) {
103                    description = new DescriptionDefinition();
104                }
105                description.setText(text);
106            }
107            if (lang != null) {
108                if (description == null) {
109                    description = new DescriptionDefinition();
110                }
111                description.setLang(lang);
112            }
113            return (T) this;
114        }
115    
116        /**
117         * Sets the id of this node
118         *
119         * @param id  the id
120         * @return the builder
121         */
122        @SuppressWarnings("unchecked")
123        public T id(String id) {
124            setId(id);
125            return (T) this;
126        }
127    
128        /**
129         * Gets the node id, creating one if not already set.
130         */
131        public String idOrCreate() {
132            if (id == null) {
133                id = createId();
134            }
135            return getId();
136        }
137    
138        /**
139         * Returns whether a custom id has been assigned
140         */
141        public boolean hasCustomIdAssigned() {
142            return customId;
143        }
144    
145        // Implementation methods
146        // -------------------------------------------------------------------------
147    
148        /**
149         * A helper method to create a new id for this node
150         */
151        protected String createId() {
152            String key = getShortName();
153            return key + getNodeCounter(key).incrementAndGet();
154        }
155    
156        /**
157         * Returns the counter for the given node key, lazily creating one if necessary
158         */
159        protected static synchronized AtomicInteger getNodeCounter(String key) {
160            AtomicInteger answer = nodeCounters.get(key);
161            if (answer == null) {
162                answer = new AtomicInteger(0);
163                nodeCounters.put(key, answer);
164            }
165            return answer;
166        }
167    }