Coverage Report - org.mule.DefaultMuleMessage
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultMuleMessage
63%
124/198
51%
45/88
1.814
 
 1  
 /*
 2  
  * $Id: DefaultMuleMessage.java 12269 2008-07-10 04:19:03Z dfeist $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule;
 12  
 
 13  
 import org.mule.api.ExceptionPayload;
 14  
 import org.mule.api.MuleMessage;
 15  
 import org.mule.api.MuleRuntimeException;
 16  
 import org.mule.api.ThreadSafeAccess;
 17  
 import org.mule.api.transformer.Transformer;
 18  
 import org.mule.api.transformer.TransformerException;
 19  
 import org.mule.api.transport.MessageAdapter;
 20  
 import org.mule.api.transport.MutableMessageAdapter;
 21  
 import org.mule.api.transport.PropertyScope;
 22  
 import org.mule.config.i18n.CoreMessages;
 23  
 import org.mule.transport.AbstractMessageAdapter;
 24  
 import org.mule.transport.DefaultMessageAdapter;
 25  
 import org.mule.transport.NullPayload;
 26  
 import org.mule.util.ClassUtils;
 27  
 
 28  
 import java.io.InputStream;
 29  
 import java.lang.reflect.Proxy;
 30  
 import java.util.ArrayList;
 31  
 import java.util.Iterator;
 32  
 import java.util.List;
 33  
 import java.util.Map;
 34  
 import java.util.Set;
 35  
 
 36  
 import javax.activation.DataHandler;
 37  
 
 38  
 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
 39  
 
 40  
 import org.apache.commons.logging.Log;
 41  
 import org.apache.commons.logging.LogFactory;
 42  
 
 43  
 /**
 44  
  * <code>DefaultMuleMessage</code> is a wrapper that contains a payload and properties
 45  
  * associated with the payload.
 46  
  */
 47  
 
 48  
 public class DefaultMuleMessage implements MuleMessage, ThreadSafeAccess
 49  
 {
 50  
     /** Serial version */
 51  
     private static final long serialVersionUID = 1541720810851984842L;
 52  2
     private static Log logger = LogFactory.getLog(DefaultMuleMessage.class);
 53  
 
 54  
     private MessageAdapter adapter;
 55  1024
     private MessageAdapter originalAdapter = null;
 56  1024
     private transient List appliedTransformerHashCodes = new CopyOnWriteArrayList();
 57  
     private byte[] cache;
 58  
     
 59  2
     private static final List consumableClasses = new ArrayList(); 
 60  
     
 61  
     static
 62  
     {
 63  
         try
 64  
         {
 65  2
             consumableClasses.add(ClassUtils.loadClass("javax.xml.stream.XMLStreamReader",
 66  
                 DefaultMuleMessage.class));
 67  
         }
 68  2
         catch (ClassNotFoundException e)
 69  
         {
 70  0
         }
 71  2
     }
 72  
     public DefaultMuleMessage(Object message)
 73  
     {
 74  342
         this(message, (Map) null);
 75  342
     }
 76  
 
 77  
     public DefaultMuleMessage(Object message, Map properties)
 78  708
     {
 79  708
         if (message instanceof MessageAdapter)
 80  
         {
 81  4
             adapter = (MessageAdapter) message;
 82  
         }
 83  
         else
 84  
         {
 85  704
             adapter = new DefaultMessageAdapter(message);
 86  
         }
 87  708
         addProperties(properties);
 88  708
         resetAccessControl();
 89  708
     }
 90  
 
 91  
 
 92  
     public DefaultMuleMessage(Object message, MessageAdapter previous)
 93  316
     {
 94  316
         if (message instanceof MessageAdapter)
 95  
         {
 96  278
             adapter = (MessageAdapter) message;
 97  278
             ((ThreadSafeAccess) adapter).resetAccessControl();
 98  
         }
 99  
         else
 100  
         {
 101  38
             adapter = new DefaultMessageAdapter(message, previous);
 102  
         }
 103  316
         if (previous.getExceptionPayload() != null)
 104  
         {
 105  0
             setExceptionPayload(previous.getExceptionPayload());
 106  
         }
 107  316
         setEncoding(previous.getEncoding());
 108  316
         if (previous.getAttachmentNames().size() > 0)
 109  
         {
 110  0
             Set attNames = adapter.getAttachmentNames();
 111  0
             synchronized (attNames)
 112  
             {
 113  0
                 for (Iterator iterator = attNames.iterator(); iterator.hasNext();)
 114  
                 {
 115  0
                     String s = (String) iterator.next();
 116  
                     try
 117  
                     {
 118  0
                         addAttachment(s, adapter.getAttachment(s));
 119  
                     }
 120  0
                     catch (Exception e)
 121  
                     {
 122  0
                         throw new MuleRuntimeException(CoreMessages.failedToReadAttachment(s), e);
 123  0
                     }
 124  0
                 }
 125  0
             }
 126  
         }
 127  316
         resetAccessControl();
 128  316
     }
 129  
 
 130  
     /** {@inheritDoc} */
 131  
     public Object getPayload(Class outputType) throws TransformerException
 132  
     {
 133  66
         return getPayload(outputType, getEncoding());
 134  
     }
 135  
 
 136  
     /**
 137  
      * Will attempt to obtain the payload of this message with the desired Class type. This will
 138  
      * try and resolve a trnsformr that can do this transformation. If a transformer cannot be found
 139  
      * an exception is thrown.  Any transfromers added to the reqgistry will be checked for compatability
 140  
      *
 141  
      * @param outputType the desired return type
 142  
      * @param encoding   the encoding to use if required
 143  
      * @return The converted payload of this message. Note that this method will not alter the payload of this
 144  
      *         message *unless* the payload is an inputstream in which case the stream will be read and the payload will become
 145  
      *         the fully read stream.
 146  
      * @throws TransformerException if a transformer cannot be found or there is an error during transformation of the
 147  
      *                              payload
 148  
      */
 149  
     protected Object getPayload(Class outputType, String encoding) throws TransformerException
 150  
     {
 151  
         //Handle null by ignoring the request
 152  66
         if (outputType == null)
 153  
         {
 154  0
             return getPayload();
 155  
         }
 156  
 
 157  66
         Class inputCls = getPayload().getClass();
 158  
 
 159  
         //Special case where proxies are used for testing
 160  66
         if (Proxy.isProxyClass(inputCls))
 161  
         {
 162  0
             inputCls = inputCls.getInterfaces()[0];
 163  
         }
 164  
 
 165  
         //If no conversion is necessary, just return the payload as-is
 166  66
         if (outputType.isAssignableFrom(inputCls))
 167  
         {
 168  58
             return getPayload();
 169  
         }
 170  
         //Grab a list of transformers that batch out input/output requirements
 171  
         // List transformers = RegistryContext.getRegistry().lookupTransformers(inputCls, outputType);
 172  
 
 173  
         //The transformer to execute on this message
 174  8
         Transformer transformer = null;
 175  8
         transformer = MuleServer.getMuleContext().getRegistry().lookupTransformer(inputCls, outputType);
 176  
 
 177  
         //no transformers found
 178  8
         if (transformer == null)
 179  
         {
 180  0
             throw new TransformerException(CoreMessages.noTransformerFoundForMessage(inputCls, outputType));
 181  
         }
 182  
 
 183  
         // Pass in the adapter itself, so we respect the encoding
 184  8
         Object result = transformer.transform(this);
 185  
 
 186  
         //TODO Unless we disallow Object.class as a valid return type we need to do this extra check
 187  8
         if (!outputType.isAssignableFrom(result.getClass()))
 188  
         {
 189  0
             throw new TransformerException(CoreMessages.transformOnObjectNotOfSpecifiedType(outputType.getName(), result.getClass()));
 190  
         }
 191  
         //If the payload is a stream and we've consumed it, then we should
 192  
         //set the payload on the message
 193  
         //This is the only time this method will alter the payload on the message
 194  8
         if (isPayloadConsumed(inputCls))
 195  
         {
 196  2
             setPayload(result);
 197  
         }
 198  
 
 199  8
         return result;
 200  
     }
 201  
 
 202  
     /**
 203  
      * Checks if the payload has been consumed for this message. This only applies to Streaming payload types
 204  
      * since once the stream has been read, the payload of the message should be updated to represent the data read
 205  
      * from the stream
 206  
      *
 207  
      * @param inputCls the input type of the message payload
 208  
      * @return true if the payload message type was stream-based, false otherwise
 209  
      */
 210  
     protected boolean isPayloadConsumed(Class inputCls)
 211  
     {
 212  8
         return InputStream.class.isAssignableFrom(inputCls) || isConsumedFromAdditional(inputCls);
 213  
     }
 214  
 
 215  
     private boolean isConsumedFromAdditional(Class inputCls)
 216  
     {
 217  6
         if (consumableClasses.isEmpty())
 218  
         {
 219  6
             return false;
 220  
         }
 221  
         
 222  0
         for (Iterator itr = consumableClasses.iterator(); itr.hasNext();) 
 223  
         {
 224  0
             Class c = (Class) itr.next();
 225  
         
 226  0
             if (c.isAssignableFrom(inputCls))
 227  
             {
 228  0
                 return true;
 229  
             }
 230  0
         }
 231  0
         return false;
 232  
     }
 233  
 
 234  
     /** {@inheritDoc} */
 235  
     public MessageAdapter getAdapter()
 236  
     {
 237  0
         return adapter;
 238  
     }
 239  
 
 240  
     /** {@inheritDoc} */
 241  
     public Object getOrginalPayload()
 242  
     {
 243  0
         return (originalAdapter == null ? adapter.getPayload() : originalAdapter.getPayload());
 244  
     }
 245  
 
 246  
     /** {@inheritDoc} */
 247  
     public MessageAdapter getOriginalAdapter()
 248  
     {
 249  0
         return (originalAdapter == null ? adapter : originalAdapter);
 250  
     }
 251  
 
 252  
     /** {@inheritDoc} */
 253  
     public void setProperty(String key, Object value, PropertyScope scope)
 254  
     {
 255  0
         adapter.setProperty(key, value, scope);
 256  0
     }
 257  
 
 258  
 
 259  
     /** {@inheritDoc} */
 260  
     public Object getProperty(String key)
 261  
     {
 262  342
         return adapter.getProperty(key);
 263  
     }
 264  
 
 265  
     /** {@inheritDoc} */
 266  
     public Object removeProperty(String key)
 267  
     {
 268  86
         return adapter.removeProperty(key);
 269  
     }
 270  
 
 271  
     /** {@inheritDoc} */
 272  
     public void setProperty(String key, Object value)
 273  
     {
 274  78
         adapter.setProperty(key, value);
 275  78
     }
 276  
 
 277  
     /** {@inheritDoc} */
 278  
     public final String getPayloadAsString() throws Exception
 279  
     {
 280  58
         assertAccess(READ);
 281  58
         return getPayloadAsString(getEncoding());
 282  
     }
 283  
 
 284  
     /** {@inheritDoc} */
 285  
     public byte[] getPayloadAsBytes() throws Exception
 286  
     {
 287  0
         assertAccess(READ);
 288  0
         if (cache != null)
 289  
         {
 290  0
             return cache;
 291  
         }
 292  0
         byte[] result = (byte[]) getPayload(byte[].class);
 293  0
         if (MuleServer.getMuleContext().getConfiguration().isCacheMessageAsBytes())
 294  
         {
 295  0
             cache = result;
 296  
         }
 297  0
         return result;
 298  
     }
 299  
 
 300  
     /** {@inheritDoc} */
 301  
     public String getPayloadAsString(String encoding) throws Exception
 302  
     {
 303  94
         assertAccess(READ);
 304  94
         if (cache != null)
 305  
         {
 306  34
             return new String(cache, encoding);
 307  
         }
 308  60
         String result = (String) getPayload(String.class);
 309  60
         if (MuleServer.getMuleContext().getConfiguration().isCacheMessageAsBytes())
 310  
         {
 311  60
             cache = result.getBytes(encoding);
 312  
         }
 313  60
         return result;
 314  
     }
 315  
 
 316  
     /** {@inheritDoc} */
 317  
     public Set getPropertyNames()
 318  
     {
 319  372
         return adapter.getPropertyNames();
 320  
     }
 321  
 
 322  
     //** {@inheritDoc} */
 323  
     public double getDoubleProperty(String name, double defaultValue)
 324  
     {
 325  0
         return adapter.getDoubleProperty(name, defaultValue);
 326  
     }
 327  
 
 328  
     /** {@inheritDoc} */
 329  
     public void setDoubleProperty(String name, double value)
 330  
     {
 331  0
         adapter.setDoubleProperty(name, value);
 332  0
     }
 333  
 
 334  
     /** {@inheritDoc} */
 335  
     public String getUniqueId()
 336  
     {
 337  146
         return adapter.getUniqueId();
 338  
     }
 339  
 
 340  
     /** {@inheritDoc} */
 341  
     public Object getProperty(String name, Object defaultValue)
 342  
     {
 343  0
         return adapter.getProperty(name, defaultValue);
 344  
     }
 345  
 
 346  
     /** {@inheritDoc} */
 347  
     public int getIntProperty(String name, int defaultValue)
 348  
     {
 349  12
         return adapter.getIntProperty(name, defaultValue);
 350  
     }
 351  
 
 352  
     /** {@inheritDoc} */
 353  
     public long getLongProperty(String name, long defaultValue)
 354  
     {
 355  0
         return adapter.getLongProperty(name, defaultValue);
 356  
     }
 357  
 
 358  
     /** {@inheritDoc} */
 359  
     public boolean getBooleanProperty(String name, boolean defaultValue)
 360  
     {
 361  0
         return adapter.getBooleanProperty(name, defaultValue);
 362  
     }
 363  
 
 364  
     /** {@inheritDoc} */
 365  
     public void setBooleanProperty(String name, boolean value)
 366  
     {
 367  0
         adapter.setBooleanProperty(name, value);
 368  0
     }
 369  
 
 370  
     /** {@inheritDoc} */
 371  
     public void setIntProperty(String name, int value)
 372  
     {
 373  0
         adapter.setIntProperty(name, value);
 374  0
     }
 375  
 
 376  
     /** {@inheritDoc} */
 377  
     public void setLongProperty(String name, long value)
 378  
     {
 379  0
         adapter.setLongProperty(name, value);
 380  0
     }
 381  
 
 382  
     /** {@inheritDoc} */
 383  
     public void setCorrelationId(String id)
 384  
     {
 385  104
         adapter.setCorrelationId(id);
 386  104
     }
 387  
 
 388  
     /** {@inheritDoc} */
 389  
     public String getCorrelationId()
 390  
     {
 391  258
         return adapter.getCorrelationId();
 392  
     }
 393  
 
 394  
     /** {@inheritDoc} */
 395  
     public void setReplyTo(Object replyTo)
 396  
     {
 397  12
         adapter.setReplyTo(replyTo);
 398  12
     }
 399  
 
 400  
     /** {@inheritDoc} */
 401  
     public Object getReplyTo()
 402  
     {
 403  12
         return adapter.getReplyTo();
 404  
     }
 405  
 
 406  
     /** {@inheritDoc} */
 407  
     public int getCorrelationSequence()
 408  
     {
 409  12
         return adapter.getCorrelationSequence();
 410  
     }
 411  
 
 412  
     /** {@inheritDoc} */
 413  
     public void setCorrelationSequence(int sequence)
 414  
     {
 415  48
         adapter.setCorrelationSequence(sequence);
 416  48
     }
 417  
 
 418  
     /** {@inheritDoc} */
 419  
     public int getCorrelationGroupSize()
 420  
     {
 421  56
         return adapter.getCorrelationGroupSize();
 422  
     }
 423  
 
 424  
     //** {@inheritDoc} */
 425  
     public void setCorrelationGroupSize(int size)
 426  
     {
 427  76
         adapter.setCorrelationGroupSize(size);
 428  76
     }
 429  
 
 430  
     /** {@inheritDoc} */
 431  
     public ExceptionPayload getExceptionPayload()
 432  
     {
 433  382
         return adapter.getExceptionPayload();
 434  
     }
 435  
 
 436  
     /** {@inheritDoc} */
 437  
     public void setExceptionPayload(ExceptionPayload exceptionPayload)
 438  
     {
 439  22
         adapter.setExceptionPayload(exceptionPayload);
 440  20
     }
 441  
 
 442  
     /** {@inheritDoc} */
 443  
     public String toString()
 444  
     {
 445  8
         return adapter.toString();
 446  
     }
 447  
 
 448  
     /** {@inheritDoc} */
 449  
     public void addAttachment(String name, DataHandler dataHandler) throws Exception
 450  
     {
 451  36
         adapter.addAttachment(name, dataHandler);
 452  36
     }
 453  
 
 454  
     /** {@inheritDoc} */
 455  
     public void removeAttachment(String name) throws Exception
 456  
     {
 457  0
         adapter.removeAttachment(name);
 458  0
     }
 459  
 
 460  
     /** {@inheritDoc} */
 461  
     public DataHandler getAttachment(String name)
 462  
     {
 463  32
         return adapter.getAttachment(name);
 464  
     }
 465  
 
 466  
     /** {@inheritDoc} */
 467  
     public Set getAttachmentNames()
 468  
     {
 469  392
         return adapter.getAttachmentNames();
 470  
     }
 471  
 
 472  
     /** {@inheritDoc} */
 473  
     public String getEncoding()
 474  
     {
 475  700
         return adapter.getEncoding();
 476  
     }
 477  
 
 478  
     /** {@inheritDoc} */
 479  
     public void setEncoding(String encoding)
 480  
     {
 481  320
         adapter.setEncoding(encoding);
 482  320
     }
 483  
 
 484  
     /** {@inheritDoc} */
 485  
     public String getStringProperty(String name, String defaultValue)
 486  
     {
 487  0
         return adapter.getStringProperty(name, defaultValue);
 488  
     }
 489  
 
 490  
     /** {@inheritDoc} */
 491  
     public void setStringProperty(String name, String value)
 492  
     {
 493  0
         adapter.setStringProperty(name, value);
 494  0
     }
 495  
 
 496  
 
 497  
     /** {@inheritDoc} */
 498  
     public void addProperties(Map properties)
 499  
     {
 500  710
         adapter.addProperties(properties);
 501  710
     }
 502  
 
 503  
     /** {@inheritDoc} */
 504  
     public void addProperties(Map properties, PropertyScope scope)
 505  
     {
 506  0
         adapter.addProperties(properties, scope);
 507  0
     }
 508  
 
 509  
     /** {@inheritDoc} */
 510  
     public void clearProperties()
 511  
     {
 512  0
         adapter.clearProperties();
 513  0
     }
 514  
 
 515  
     /** {@inheritDoc} */
 516  
     public Object getPayload()
 517  
     {
 518  1822
         return adapter.getPayload();
 519  
     }
 520  
 
 521  
     /** {@inheritDoc} */
 522  
     public synchronized void setPayload(Object payload)
 523  
     {
 524  
         //TODO we may want to enforce stricter rules here, rather than silently wrapping the existing adapter
 525  172
         if (!(adapter instanceof MutableMessageAdapter))
 526  
         {
 527  0
             adapter = new DefaultMessageAdapter(payload, adapter);
 528  
         }
 529  
         else
 530  
         {
 531  172
             ((MutableMessageAdapter) adapter).setPayload(payload);
 532  
         }
 533  172
         cache = null;
 534  172
     }
 535  
 
 536  
     /** {@inheritDoc} */
 537  
     public void release()
 538  
     {
 539  0
         adapter.release();
 540  0
         if (originalAdapter != null)
 541  
         {
 542  0
             originalAdapter.release();
 543  
         }
 544  0
         cache = null;
 545  0
         appliedTransformerHashCodes.clear();
 546  0
     }
 547  
 
 548  
     /** {@inheritDoc} */
 549  
     public void applyTransformers(List transformers) throws TransformerException
 550  
     {
 551  208
         applyTransformers(transformers, null);
 552  204
     }
 553  
 
 554  
     public void applyTransformers(List transformers, Class outputType) throws TransformerException
 555  
     {
 556  208
         if (!transformers.isEmpty() && !appliedTransformerHashCodes.contains(new Integer(transformers.hashCode())))
 557  
         {
 558  122
             applyAllTransformers(transformers);
 559  118
             appliedTransformerHashCodes.add(new Integer(transformers.hashCode()));
 560  
         }
 561  
 
 562  204
         if (null != outputType && !getPayload().getClass().isAssignableFrom(outputType))
 563  
         {
 564  0
             setPayload(getPayload(outputType));
 565  
         }
 566  204
     }
 567  
 
 568  
     protected void applyAllTransformers(List transformers) throws TransformerException
 569  
     {
 570  122
         if (!transformers.isEmpty())
 571  
         {
 572  
 
 573  122
             Iterator iterator = transformers.iterator();
 574  270
             while (iterator.hasNext())
 575  
             {
 576  154
                 Transformer transformer = (Transformer) iterator.next();
 577  
 
 578  154
                 if (getPayload() == null)
 579  
                 {
 580  0
                     if (transformer.isAcceptNull())
 581  
                     {
 582  0
                         setPayload(NullPayload.getInstance());
 583  
                     }
 584  
                     else
 585  
                     {
 586  0
                         if (logger.isDebugEnabled())
 587  
                         {
 588  0
                             logger.debug("Transformer " + transformer +
 589  
                                     " doesn't support the null payload, exiting from transformer chain.");
 590  
                         }
 591  
                         break;
 592  
                     }
 593  
                 }
 594  
 
 595  154
                 Class srcCls = getPayload().getClass();
 596  154
                 if (transformer.isSourceTypeSupported(srcCls))
 597  
                 {
 598  152
                     Object result = transformer.transform(this);
 599  
 
 600  148
                     if (originalAdapter == null && MuleServer.getMuleContext().getConfiguration().isCacheMessageOriginalPayload())
 601  
                     {
 602  116
                         originalAdapter = adapter;
 603  
                     }
 604  
                     //TODO RM*: Must make sure this works for all scenarios
 605  148
                     if (result instanceof MuleMessage)
 606  
                     {
 607  0
                         synchronized (this)
 608  
                         {
 609  0
                             adapter = ((MuleMessage) result).getAdapter();
 610  0
                         }
 611  
                     }
 612  
                     else
 613  
                     {
 614  148
                         setPayload(result);
 615  
                     }
 616  148
                 }
 617  
                 else
 618  
                 {
 619  2
                     if (logger.isDebugEnabled())
 620  
                     {
 621  0
                         logger.debug("Transformer " + transformer + " doesn't support the source payload: " + srcCls);
 622  
                     }
 623  2
                     if (!transformer.isIgnoreBadInput())
 624  
                     {
 625  2
                         if (logger.isDebugEnabled())
 626  
                         {
 627  0
                             logger.debug("Exiting from transformer chain (ignoreBadInput = false)");
 628  
                         }
 629  
                         break;
 630  
                     }
 631  
                 }
 632  148
             }
 633  
         }
 634  118
     }
 635  
 
 636  
     //////////////////////////////// ThreadSafeAccess Impl ///////////////////////////////
 637  
 
 638  
     /** {@inheritDoc} */
 639  
     public ThreadSafeAccess newThreadCopy()
 640  
     {
 641  278
         if (adapter instanceof ThreadSafeAccess)
 642  
         {
 643  278
             logger.debug("new copy of message for " + Thread.currentThread());
 644  278
             return new DefaultMuleMessage(((ThreadSafeAccess) adapter).newThreadCopy(), this);
 645  
         }
 646  
         else
 647  
         {
 648  
             // not much we can do here - streaming will have to handle things itself
 649  0
             return this;
 650  
         }
 651  
     }
 652  
 
 653  
     /** {@inheritDoc} */
 654  
     public void resetAccessControl()
 655  
     {
 656  1304
         if (adapter instanceof AbstractMessageAdapter)
 657  
         {
 658  1302
             ((AbstractMessageAdapter) adapter).resetAccessControl();
 659  
         }
 660  1304
         if (originalAdapter instanceof AbstractMessageAdapter)
 661  
         {
 662  0
             ((AbstractMessageAdapter) originalAdapter).resetAccessControl();
 663  
         }
 664  1304
     }
 665  
 
 666  
     /** {@inheritDoc} */
 667  
     public void assertAccess(boolean write)
 668  
     {
 669  236
         if (adapter instanceof AbstractMessageAdapter)
 670  
         {
 671  236
             ((AbstractMessageAdapter) adapter).assertAccess(write);
 672  
         }
 673  220
     }
 674  
 }