View Javadoc
1   /*
2    * Copyright (C) 2013 4th Line GmbH, Switzerland
3    *
4    * The contents of this file are subject to the terms of either the GNU
5    * Lesser General Public License Version 2 or later ("LGPL") or the
6    * Common Development and Distribution License Version 1 or later
7    * ("CDDL") (collectively, the "License"). You may not use this file
8    * except in compliance with the License. See LICENSE.txt for more
9    * information.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   */
15  
16  package org.fourthline.cling.model.meta;
17  
18  import org.fourthline.cling.model.Validatable;
19  import org.fourthline.cling.model.ValidationError;
20  import org.fourthline.cling.model.types.Datatype;
21  import org.fourthline.cling.model.ModelUtil;
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.logging.Logger;
26  
27  /**
28   * Describes a single action argument, either input or output.
29   * <p>
30   * No, I haven't  figured out so far what the "return value" thingy is good for.
31   * </p>
32   *
33   * @author Christian Bauer
34   */
35  public class ActionArgument<S extends Service> implements Validatable {
36  
37      final private static Logger log = Logger.getLogger(ActionArgument.class.getName());
38  
39      public enum Direction {
40          IN, OUT
41      }
42  
43      final private String name;
44      final private String[] aliases;
45      final private String relatedStateVariableName;
46      final private Direction direction;
47      final private boolean returnValue;     // TODO: What is this stuff good for anyway?
48  
49      // Package mutable state
50      private Action<S> action;
51  
52      public ActionArgument(String name, String relatedStateVariableName, Direction direction) {
53          this(name, new String[0], relatedStateVariableName, direction, false);
54      }
55  
56      public ActionArgument(String name, String[] aliases, String relatedStateVariableName, Direction direction) {
57          this(name, aliases, relatedStateVariableName, direction, false);
58      }
59      
60      public ActionArgument(String name, String relatedStateVariableName, Direction direction, boolean returnValue) {
61          this(name, new String[0], relatedStateVariableName, direction, returnValue);
62      }
63  
64      public ActionArgument(String name, String[] aliases, String relatedStateVariableName, Direction direction, boolean returnValue) {
65          this.name = name;
66          this.aliases = aliases;
67          this.relatedStateVariableName = relatedStateVariableName;
68          this.direction = direction;
69          this.returnValue = returnValue;
70      }
71  
72      public String getName() {
73          return name;
74      }
75  
76      public String[] getAliases() {
77          return aliases;
78      }
79  
80      public boolean isNameOrAlias(String name) {
81          if (getName().equalsIgnoreCase(name)) return true;
82          for (String alias : aliases) {
83              if (alias.equalsIgnoreCase(name)) return true;
84          }
85          return false;
86      }
87  
88      public String getRelatedStateVariableName() {
89          return relatedStateVariableName;
90      }
91  
92      public Direction getDirection() {
93          return direction;
94      }
95  
96      public boolean isReturnValue() {
97          return returnValue;
98      }
99  
100     public Action<S> getAction() {
101         return action;
102     }
103 
104     void setAction(Action<S> action) {
105         if (this.action != null)
106             throw new IllegalStateException("Final value has been set already, model is immutable");
107         this.action = action;
108     }
109 
110     public Datatype getDatatype() {
111         return getAction().getService().getDatatype(this);
112     }
113 
114     public List<ValidationError> validate() {
115         List<ValidationError> errors = new ArrayList<>();
116 
117         if (getName() == null || getName().length() == 0) {
118             errors.add(new ValidationError(
119                     getClass(),
120                     "name",
121                     "Argument without name of: " + getAction()
122             ));
123         } else if (!ModelUtil.isValidUDAName(getName())) {
124             log.warning("UPnP specification violation of: " + getAction().getService().getDevice());
125             log.warning("Invalid argument name: " + this);
126         } else if (getName().length() > 32) {
127             log.warning("UPnP specification violation of: " + getAction().getService().getDevice());
128             log.warning("Argument name should be less than 32 characters: " + this);
129         }
130 
131         if (getDirection() == null) {
132             errors.add(new ValidationError(
133                     getClass(),
134                     "direction",
135                     "Argument '"+getName()+"' requires a direction, either IN or OUT"
136             ));
137         }
138 
139         if (isReturnValue() && getDirection() != ActionArgument.Direction.OUT) {
140             errors.add(new ValidationError(
141                     getClass(),
142                     "direction",
143                     "Return value argument '" + getName() + "' must be direction OUT"
144             ));
145         }
146 
147         return errors;
148     }
149 
150     public ActionArgument<S> deepCopy() {
151         return new ActionArgument<>(
152                 getName(),
153                 getAliases(),
154                 getRelatedStateVariableName(),
155                 getDirection(),
156                 isReturnValue()
157         );
158     }
159 
160     @Override
161     public String toString() {
162         return "(" + getClass().getSimpleName() + ", " + getDirection() + ") " + getName();
163     }
164 }