gluu
公開メンバ関数 | 非公開メンバ関数 | 非公開変数類 | 全メンバ一覧
org.gluu.oxtrust.service.scim2.Scim2PatchService クラス
org.gluu.oxtrust.service.scim2.Scim2PatchService 連携図
Collaboration graph

公開メンバ関数

BaseScimResource applyPatchOperation (BaseScimResource resource, PatchOperation operation) throws Exception
 

非公開メンバ関数

BaseScimResource applyPatchOperationWithValueFilter (BaseScimResource resource, PatchOperation operation, String valSelFilter, String attribute, String subAttribute) throws SCIMException, InvalidAttributeValueException
 
Pair< Boolean, String > validateBracketedPath (String path)
 
void applyPartialUpdate (String attribute, String subAttribute, List< Map< String, Object >> list, int index, Object value, Class<? extends BaseScimResource > cls) throws InvalidAttributeValueException
 
void assertMutability (String path, Object currentVal, Object value, Class<? extends BaseScimResource > cls) throws InvalidAttributeValueException
 

非公開変数類

Logger log
 
ScimFilterParserService filterService
 
ExtensionService extService
 

詳解

Created by jgomer on 2017-12-17.

関数詳解

◆ applyPartialUpdate()

void org.gluu.oxtrust.service.scim2.Scim2PatchService.applyPartialUpdate ( String  attribute,
String  subAttribute,
List< Map< String, Object >>  list,
int  index,
Object  value,
Class<? extends BaseScimResource cls 
) throws InvalidAttributeValueException
inlineprivate
262  {
263 
264  if (subAttribute.length()==0) {
265  //Updates the whole item in the list after passing mutability check, see section 3.5.2 RFC 7644:
266  //"Each operation against an attribute MUST be compatible with the attribute's mutability and schema ... "
267  Map<String, Object> map=IntrospectUtil.strObjMap(value);
268 
269  for (String subAttr : map.keySet())
270  assertMutability(attribute, list.get(index).get(subAttr), map.get(subAttr), cls);
271  list.set(index, map);
272  }
273  else{
274  //Updates a subattribute only
275  assertMutability(attribute + "." + subAttribute, list.get(index).get(subAttribute), value, cls);
276  list.get(index).put(subAttribute, value);
277  }
278 
279  }
void assertMutability(String path, Object currentVal, Object value, Class<? extends BaseScimResource > cls)
Definition: Scim2PatchService.java:281

◆ applyPatchOperation()

BaseScimResource org.gluu.oxtrust.service.scim2.Scim2PatchService.applyPatchOperation ( BaseScimResource  resource,
PatchOperation  operation 
) throws Exception
inline
58  {
59 
60  BaseScimResource result=null;
61  Map<String, Object> genericMap=null;
62  PatchOperationType opType=operation.getType();
63  Class<? extends BaseScimResource> clazz=resource.getClass();
64  String path = operation.getPath();
65 
66  log.debug("applyPatchOperation of type {}", opType);
67 
68  //Determine if operation is with value filter
69  if (StringUtils.isNotEmpty(path) && !operation.getType().equals(PatchOperationType.ADD)) {
70  Pair<Boolean, String> pair = validateBracketedPath(path);
71 
72  if (pair.getFirst()) {
73  String valSelFilter = pair.getSecond();
74  if (valSelFilter == null)
75  throw new SCIMException("Unexpected syntax in value selection filter");
76  else {
77  int i=path.indexOf("[");
78  String attribute=path.substring(0, i);
79 
80  i=path.lastIndexOf("].");
81  String subAttribute= i==-1 ? "" : path.substring(i+2);
82  //Abort earlier
83  return applyPatchOperationWithValueFilter(resource, operation, valSelFilter, attribute, subAttribute);
84  }
85  }
86  }
87 
88  if (!opType.equals(PatchOperationType.REMOVE)) {
89  Object value = operation.getValue();
90  List<String> extensionUrns=extService.getUrnsOfExtensions(clazz);
91 
92  if (value instanceof Map)
93  genericMap = IntrospectUtil.strObjMap(value);
94  else{
95  //It's an atomic value or an array
96  if (StringUtils.isEmpty(path))
97  throw new SCIMException("Value(s) supplied for resource not parseable");
98 
99  //Create a simple map and trim the last part of path
100  String subPaths[] = ScimResourceUtil.splitPath(path, extensionUrns);
101  genericMap = Collections.singletonMap(subPaths[subPaths.length - 1], value);
102 
103  if (subPaths.length == 1)
104  path = "";
105  else
106  path = path.substring(0, path.lastIndexOf("."));
107  }
108 
109  if (StringUtils.isNotEmpty(path)){
110  //Visit backwards creating a composite map
111  String subPaths[] = ScimResourceUtil.splitPath(path, extensionUrns);
112  for (int i = subPaths.length - 1; i >= 0; i--) {
113 
114  //Create a string consisting of all subpaths until the i-th
115  StringBuilder sb=new StringBuilder();
116  for (int j=0;j<=i;j++)
117  sb.append(subPaths[j]).append(".");
118 
119  Attribute annot = IntrospectUtil.getFieldAnnotation(sb.substring(0, sb.length()-1), clazz, Attribute.class);
120  boolean multivalued=!(annot==null || annot.multiValueClass().equals(NullType.class));
121 
122  Map<String, Object> genericBiggerMap = new HashMap<String, Object>();
123  genericBiggerMap.put(subPaths[i], multivalued ? Collections.singletonList(genericMap) : genericMap);
124  genericMap = genericBiggerMap;
125  }
126  }
127 
128  log.debug("applyPatchOperation. Generating a ScimResource from generic map: {}", genericMap.toString());
129  }
130 
131  //Try parse genericMap as an instance of the resource
132  ObjectMapper mapper = new ObjectMapper();
133  BaseScimResource alter=opType.equals(PatchOperationType.REMOVE) ? resource : mapper.convertValue(genericMap, clazz);
134  List<Extension> extensions=extService.getResourceExtensions(clazz);
135 
136  switch (operation.getType()){
137  case REPLACE:
138  result=ScimResourceUtil.transferToResourceReplace(alter, resource, extensions);
139  break;
140  case ADD:
141  result=ScimResourceUtil.transferToResourceAdd(alter, resource, extensions);
142  break;
143  case REMOVE:
144  result=ScimResourceUtil.deleteFromResource(alter, operation.getPath(), extensions);
145  break;
146  }
147  return result;
148 
149  }
ExtensionService extService
Definition: Scim2PatchService.java:56
Pair< Boolean, String > validateBracketedPath(String path)
Definition: Scim2PatchService.java:233
BaseScimResource applyPatchOperationWithValueFilter(BaseScimResource resource, PatchOperation operation, String valSelFilter, String attribute, String subAttribute)
Definition: Scim2PatchService.java:151
List< Extension > getResourceExtensions(Class<? extends BaseScimResource > cls)
Definition: ExtensionService.java:46
Logger log
Definition: Scim2PatchService.java:50
List< String > getUrnsOfExtensions(Class<? extends BaseScimResource > cls)
Definition: ExtensionService.java:86

◆ applyPatchOperationWithValueFilter()

BaseScimResource org.gluu.oxtrust.service.scim2.Scim2PatchService.applyPatchOperationWithValueFilter ( BaseScimResource  resource,
PatchOperation  operation,
String  valSelFilter,
String  attribute,
String  subAttribute 
) throws SCIMException, InvalidAttributeValueException
inlineprivate
153  {
154 
155  String path=operation.getPath();
156  ObjectMapper mapper=new ObjectMapper();
157  Class<? extends BaseScimResource> cls=resource.getClass();
158  Map<String, Object> resourceAsMap=mapper.convertValue(resource, new TypeReference<Map<String, Object>>(){});
159  List<Map<String, Object>> list;
160 
161  Attribute attrAnnot=IntrospectUtil.getFieldAnnotation(attribute, cls, Attribute.class);
162  if (attrAnnot!=null){
163  if (!attrAnnot.multiValueClass().equals(NullType.class) && attrAnnot.type().equals(AttributeDefinition.Type.COMPLEX)){
164  Object colObject=resourceAsMap.get(attribute);
165  list = colObject==null ? null : new ArrayList<Map<String, Object>>((Collection<Map<String, Object>>) colObject);
166  }
167  else
168  throw new SCIMException(String.format("Attribute '%s' expected to be complex multi-valued", attribute));
169  }
170  else
171  throw new SCIMException(String.format("Attribute '%s' not recognized or expected to be complex multi-valued", attribute));
172 
173  if (list==null)
174  log.info("applyPatchOperationWithValueFilter. List of values for {} is empty. Operation has no effect", attribute);
175  else{
176  try {
177  valSelFilter = FilterUtil.preprocess(valSelFilter, cls);
178  ParseTree parseTree = filterService.getParseTree(valSelFilter);
179 
180  List<Integer> matchingIndexes=new ArrayList<Integer>();
181  for (int i=0;i<list.size();i++){
182  if (filterService.complexAttributeMatch(parseTree, list.get(i), attribute, cls))
183  matchingIndexes.add(0, i); //Important: add so that resulting list is reverse-ordered
184  }
185 
186  if (subAttribute.length()>0 && matchingIndexes.size()>0 && operation.getType().equals(PatchOperationType.REMOVE)){
187  //per spec (section 3.5.2.2 RFC 7644) subAttribute must not be required or read-only
188  Attribute subAttrAnnot=IntrospectUtil.getFieldAnnotation(attribute + "." + subAttribute, cls, Attribute.class);
189 
190  if (subAttrAnnot != null && (subAttrAnnot.mutability().equals(READ_ONLY) || subAttrAnnot.isRequired()))
191  throw new InvalidAttributeValueException("Cannot remove read-only or required attribute " + attribute + "." + subAttribute);
192  }
193  /*
194  Here we differ from spec (see section 3.5.2.3/4 of RFC7644. If no record match is made, we are supposed to
195  return error 400 with scimType of noTarget. But this is clearly inconvenient
196  */
197  log.info("There are {} entries matching the filter '{}'", matchingIndexes.size(), path);
198 
199  for (Integer index : matchingIndexes){
200  if (operation.getType().equals(PatchOperationType.REMOVE)) {
201  if (subAttribute.length()==0) //Remove the whole item
202  list.remove(index.intValue()); //If intValue is not used, the remove(Object) method is called!
203  else //remove subattribute only
204  list.get(index).remove(subAttribute);
205  }
206  else
207  applyPartialUpdate(attribute, subAttribute, list, index, operation.getValue(), cls);
208  }
209 
210  log.trace("New {} list is:\n{}", attribute, mapper.writeValueAsString(list));
211  resourceAsMap.put(attribute, list.size()==0 ? null : list);
212  resource=mapper.convertValue(resourceAsMap, cls);
213  }
214  catch (InvalidAttributeValueException ei){
215  throw ei;
216  }
217  catch (Exception e){
218  log.info("Error processing Patch operation with value selection path '{}'", path);
219  log.error(e.getMessage(), e);
220  throw new SCIMException(e.getMessage(), e);
221  }
222  }
223  return resource;
224 
225  }
void applyPartialUpdate(String attribute, String subAttribute, List< Map< String, Object >> list, int index, Object value, Class<? extends BaseScimResource > cls)
Definition: Scim2PatchService.java:261
ScimFilterParserService filterService
Definition: Scim2PatchService.java:53
Logger log
Definition: Scim2PatchService.java:50
ParseTree getParseTree(String filter, ScimFilterErrorListener errorListener)
Definition: ScimFilterParserService.java:37
Boolean complexAttributeMatch(ParseTree parseTree, Map< String, Object > item, String parent, Class<? extends BaseScimResource > clazz)
Definition: ScimFilterParserService.java:102

◆ assertMutability()

void org.gluu.oxtrust.service.scim2.Scim2PatchService.assertMutability ( String  path,
Object  currentVal,
Object  value,
Class<? extends BaseScimResource cls 
) throws InvalidAttributeValueException
inlineprivate
281  {
282 
283  Attribute attrAnnot=IntrospectUtil.getFieldAnnotation(path, cls, Attribute.class);
284  if (attrAnnot !=null) {
285  if (attrAnnot.mutability().equals(IMMUTABLE) && currentVal!=null && !value.equals(currentVal))
286  throw new InvalidAttributeValueException( "Invalid value passed for immutable attribute " + path);
287  }
288 
289  }

◆ validateBracketedPath()

Pair<Boolean, String> org.gluu.oxtrust.service.scim2.Scim2PatchService.validateBracketedPath ( String  path)
inlineprivate

It tries to determine if this is a valid path in terms of PATCH operation for the case of value selection filter. Example: emails[value co ".com"]

引数
path
戻り値
233  {
234 
235  boolean isFilterExpression;
236  String selFilter=null;
237 
238  int lBracketIndex = path.indexOf("[");
239  //Check if characters preceding bracket look like attribute name
240  isFilterExpression=(lBracketIndex>0) && path.substring(0, lBracketIndex).matches("[a-zA-Z]\\w*");
241 
242  if (isFilterExpression){
243  int rBracketIndex = path.lastIndexOf("]");
244  int lenm1=path.length()-1;
245  /*
246  It will be valid if character ] is the last of string, or if it is followed by a dot and at least one
247  letter (thus specifying a subattribute name). Examples:
248  - emails[type eq null]
249  - addresses[value co "any[...]thing"]
250  - ims[value eq "hi"].primary
251  */
252  if ((rBracketIndex>lBracketIndex) && (rBracketIndex==lenm1 ||
253  (lenm1-rBracketIndex>1 && path.charAt(rBracketIndex+1)=='.' && Character.isLetter(path.charAt(rBracketIndex+2)))))
254  selFilter=path.substring(lBracketIndex+1, rBracketIndex);
255 
256  }
257  return new Pair<Boolean, String>(isFilterExpression, selFilter);
258 
259  }

メンバ詳解

◆ extService

ExtensionService org.gluu.oxtrust.service.scim2.Scim2PatchService.extService
private

◆ filterService

ScimFilterParserService org.gluu.oxtrust.service.scim2.Scim2PatchService.filterService
private

◆ log

Logger org.gluu.oxtrust.service.scim2.Scim2PatchService.log
private

このクラス詳解は次のファイルから抽出されました: