2525import  org .elasticsearch .cluster .metadata .ProjectMetadata ;
2626import  org .elasticsearch .cluster .routing .IndexRouting ;
2727import  org .elasticsearch .common .UUIDs ;
28- import  org .elasticsearch .common .bytes .BytesArray ;
2928import  org .elasticsearch .common .bytes .BytesReference ;
3029import  org .elasticsearch .common .io .stream .StreamInput ;
3130import  org .elasticsearch .common .io .stream .StreamOutput ;
3938import  org .elasticsearch .index .mapper .MapperService ;
4039import  org .elasticsearch .index .shard .ShardId ;
4140import  org .elasticsearch .ingest .IngestService ;
42- import  org .elasticsearch .plugins .internal .XContentParserDecorator ;
4341import  org .elasticsearch .xcontent .XContentBuilder ;
44- import  org .elasticsearch .xcontent .XContentFactory ;
4542import  org .elasticsearch .xcontent .XContentType ;
4643
4744import  java .io .IOException ;
@@ -98,15 +95,13 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
9895    @ Nullable 
9996    private  String  routing ;
10097
101-     private  BytesReference   source ;
98+     private  SourceContext   sourceContext  =  new   SourceContext () ;
10299
103100    private  OpType  opType  = OpType .INDEX ;
104101
105102    private  long  version  = Versions .MATCH_ANY ;
106103    private  VersionType  versionType  = VersionType .INTERNAL ;
107104
108-     private  XContentType  contentType ;
109- 
110105    private  String  pipeline ;
111106    private  String  finalPipeline ;
112107
@@ -165,7 +160,14 @@ public IndexRequest(@Nullable ShardId shardId, StreamInput in) throws IOExceptio
165160        }
166161        id  = in .readOptionalString ();
167162        routing  = in .readOptionalString ();
168-         source  = in .readBytesReference ();
163+         boolean  beforeSourceContext  = in .getTransportVersion ().before (TransportVersions .SOURCE_CONTEXT );
164+         BytesReference  source ;
165+         if  (beforeSourceContext ) {
166+             source  = in .readBytesReference ();
167+         } else  {
168+             sourceContext  = new  SourceContext (in );
169+             source  = null ;
170+         }
169171        opType  = OpType .fromId (in .readByte ());
170172        version  = in .readLong ();
171173        versionType  = VersionType .fromValue (in .readByte ());
@@ -174,11 +176,15 @@ public IndexRequest(@Nullable ShardId shardId, StreamInput in) throws IOExceptio
174176        isPipelineResolved  = in .readBoolean ();
175177        isRetry  = in .readBoolean ();
176178        autoGeneratedTimestamp  = in .readLong ();
177-         if  (in .readBoolean ()) {
178-             // faster than StreamInput::readEnum, do not replace we read a lot of these instances at times 
179-             contentType  = XContentType .ofOrdinal (in .readByte ());
180-         } else  {
181-             contentType  = null ;
179+         if  (beforeSourceContext ) {
180+             XContentType  contentType ;
181+             if  (in .readBoolean ()) {
182+                 // faster than StreamInput::readEnum, do not replace we read a lot of these instances at times 
183+                 contentType  = XContentType .ofOrdinal (in .readByte ());
184+             } else  {
185+                 contentType  = null ;
186+             }
187+             sourceContext  = new  SourceContext (contentType , source , () -> {});
182188        }
183189        ifSeqNo  = in .readZLong ();
184190        ifPrimaryTerm  = in .readVLong ();
@@ -250,10 +256,10 @@ private static String readPipelineName(StreamInput in) throws IOException {
250256    @ Override 
251257    public  ActionRequestValidationException  validate () {
252258        ActionRequestValidationException  validationException  = super .validate ();
253-         if  (source  == null ) {
259+         if  (sourceContext . hasSource ()  == false ) {
254260            validationException  = addValidationError ("source is missing" , validationException );
255261        }
256-         if  (contentType  == null ) {
262+         if  (sourceContext . contentType ()  == null ) {
257263            validationException  = addValidationError ("content type is missing" , validationException );
258264        }
259265        assert  opType  == OpType .INDEX  || opType  == OpType .CREATE  : "unexpected op-type: "  + opType ;
@@ -311,7 +317,7 @@ public ActionRequestValidationException validate() {
311317     * source at index time 
312318     */ 
313319    public  XContentType  getContentType () {
314-         return  contentType ;
320+         return  sourceContext . contentType () ;
315321    }
316322
317323    /** 
@@ -412,15 +418,11 @@ public boolean isPipelineResolved() {
412418     * The source of the document to index, recopied to a new array if it is unsafe. 
413419     */ 
414420    public  BytesReference  source () {
415-         return  source ;
421+         return  sourceContext . bytes () ;
416422    }
417423
418424    public  Map <String , Object > sourceAsMap () {
419-         return  XContentHelper .convertToMap (source , false , contentType ).v2 ();
420-     }
421- 
422-     public  Map <String , Object > sourceAsMap (XContentParserDecorator  parserDecorator ) {
423-         return  XContentHelper .convertToMap (source , false , contentType , parserDecorator ).v2 ();
425+         return  sourceContext .sourceAsMap ();
424426    }
425427
426428    /** 
@@ -429,7 +431,8 @@ public Map<String, Object> sourceAsMap(XContentParserDecorator parserDecorator)
429431     * @param source The map to index 
430432     */ 
431433    public  IndexRequest  source (Map <String , ?> source ) throws  ElasticsearchGenerationException  {
432-         return  source (source , Requests .INDEX_CONTENT_TYPE );
434+         sourceContext .source (source );
435+         return  this ;
433436    }
434437
435438    /** 
@@ -438,24 +441,14 @@ public IndexRequest source(Map<String, ?> source) throws ElasticsearchGeneration
438441     * @param source The map to index 
439442     */ 
440443    public  IndexRequest  source (Map <String , ?> source , XContentType  contentType ) throws  ElasticsearchGenerationException  {
441-         try  {
442-             XContentBuilder  builder  = XContentFactory .contentBuilder (contentType );
443-             builder .map (source );
444-             return  source (builder );
445-         } catch  (IOException  e ) {
446-             throw  new  ElasticsearchGenerationException ("Failed to generate ["  + source  + "]" , e );
447-         }
444+         sourceContext .source (source , contentType );
445+         return  this ;
448446    }
449447
450448    public  IndexRequest  source (Map <String , ?> source , XContentType  contentType , boolean  ensureNoSelfReferences )
451449        throws  ElasticsearchGenerationException  {
452-         try  {
453-             XContentBuilder  builder  = XContentFactory .contentBuilder (contentType );
454-             builder .map (source , ensureNoSelfReferences );
455-             return  source (builder );
456-         } catch  (IOException  e ) {
457-             throw  new  ElasticsearchGenerationException ("Failed to generate ["  + source  + "]" , e );
458-         }
450+         sourceContext .source (source , contentType , ensureNoSelfReferences );
451+         return  this ;
459452    }
460453
461454    /** 
@@ -465,14 +458,16 @@ public IndexRequest source(Map<String, ?> source, XContentType contentType, bool
465458     * or using the {@link #source(byte[], XContentType)}. 
466459     */ 
467460    public  IndexRequest  source (String  source , XContentType  xContentType ) {
468-         return  source (new  BytesArray (source ), xContentType );
461+         sourceContext .source (source , xContentType );
462+         return  this ;
469463    }
470464
471465    /** 
472466     * Sets the content source to index. 
473467     */ 
474468    public  IndexRequest  source (XContentBuilder  sourceBuilder ) {
475-         return  source (BytesReference .bytes (sourceBuilder ), sourceBuilder .contentType ());
469+         sourceContext .source (sourceBuilder );
470+         return  this ;
476471    }
477472
478473    /** 
@@ -484,7 +479,8 @@ public IndexRequest source(XContentBuilder sourceBuilder) {
484479     * </p> 
485480     */ 
486481    public  IndexRequest  source (Object ... source ) {
487-         return  source (Requests .INDEX_CONTENT_TYPE , source );
482+         sourceContext .source (source );
483+         return  this ;
488484    }
489485
490486    /** 
@@ -496,57 +492,29 @@ public IndexRequest source(Object... source) {
496492     * </p> 
497493     */ 
498494    public  IndexRequest  source (XContentType  xContentType , Object ... source ) {
499-         return  source (getXContentBuilder (xContentType , source ));
495+         sourceContext .source (xContentType , source );
496+         return  this ;
500497    }
501498
502-     /** 
503-      * Returns an XContentBuilder for the given xContentType and source array 
504-      * <p> 
505-      * <b>Note: the number of objects passed to this method as varargs must be an even 
506-      * number. Also the first argument in each pair (the field name) must have a 
507-      * valid String representation.</b> 
508-      * </p> 
509-      */ 
510-     public  static  XContentBuilder  getXContentBuilder (XContentType  xContentType , Object ... source ) {
511-         if  (source .length  % 2  != 0 ) {
512-             throw  new  IllegalArgumentException ("The number of object passed must be even but was ["  + source .length  + "]" );
513-         }
514-         if  (source .length  == 2  && source [0 ] instanceof  BytesReference  && source [1 ] instanceof  Boolean ) {
515-             throw  new  IllegalArgumentException (
516-                 "you are using the removed method for source with bytes and unsafe flag, the unsafe flag" 
517-                     + " was removed, please just use source(BytesReference)" 
518-             );
519-         }
520-         try  {
521-             XContentBuilder  builder  = XContentFactory .contentBuilder (xContentType );
522-             builder .startObject ();
523-             // This for loop increments by 2 because the source array contains adjacent key/value pairs: 
524-             for  (int  i  = 0 ; i  < source .length ; i  = i  + 2 ) {
525-                 String  field  = source [i ].toString ();
526-                 Object  value  = source [i  + 1 ];
527-                 builder .field (field , value );
528-             }
529-             builder .endObject ();
530-             return  builder ;
531-         } catch  (IOException  e ) {
532-             throw  new  ElasticsearchGenerationException ("Failed to generate" , e );
533-         }
499+     public  IndexRequest  sourceContext (SourceContext  sourceContext ) {
500+         sourceContext  = Objects .requireNonNull (sourceContext );
501+         return  this ;
534502    }
535503
536504    /** 
537505     * Sets the document to index in bytes form. 
538506     */ 
539507    public  IndexRequest  source (BytesReference  source , XContentType  xContentType ) {
540-         this .source  = Objects .requireNonNull (source );
541-         this .contentType  = Objects .requireNonNull (xContentType );
508+         sourceContext .source (Objects .requireNonNull (source ), Objects .requireNonNull (xContentType ));
542509        return  this ;
543510    }
544511
545512    /** 
546513     * Sets the document to index in bytes form. 
547514     */ 
548515    public  IndexRequest  source (byte [] source , XContentType  xContentType ) {
549-         return  source (source , 0 , source .length , xContentType );
516+         sourceContext .source (source , xContentType );
517+         return  this ;
550518    }
551519
552520    /** 
@@ -558,7 +526,8 @@ public IndexRequest source(byte[] source, XContentType xContentType) {
558526     * @param length The length of the data 
559527     */ 
560528    public  IndexRequest  source (byte [] source , int  offset , int  length , XContentType  xContentType ) {
561-         return  source (new  BytesArray (source , offset , length ), xContentType );
529+         sourceContext .source (source , offset , length , xContentType );
530+         return  this ;
562531    }
563532
564533    /** 
@@ -769,7 +738,11 @@ private void writeBody(StreamOutput out) throws IOException {
769738        }
770739        out .writeOptionalString (id );
771740        out .writeOptionalString (routing );
772-         out .writeBytesReference (source );
741+         if  (out .getTransportVersion ().onOrAfter (TransportVersions .SOURCE_CONTEXT )) {
742+             sourceContext .writeTo (out );
743+         } else  {
744+             out .writeBytesReference (sourceContext .bytes ());
745+         }
773746        out .writeByte (opType .getId ());
774747        out .writeLong (version );
775748        out .writeByte (versionType .getValue ());
@@ -778,11 +751,14 @@ private void writeBody(StreamOutput out) throws IOException {
778751        out .writeBoolean (isPipelineResolved );
779752        out .writeBoolean (isRetry );
780753        out .writeLong (autoGeneratedTimestamp );
781-         if  (contentType  != null ) {
782-             out .writeBoolean (true );
783-             XContentHelper .writeTo (out , contentType );
784-         } else  {
785-             out .writeBoolean (false );
754+         if  (out .getTransportVersion ().before (TransportVersions .SOURCE_CONTEXT )) {
755+             XContentType  contentType  = sourceContext .contentType ();
756+             if  (contentType  != null ) {
757+                 out .writeBoolean (true );
758+                 XContentHelper .writeTo (out , contentType );
759+             } else  {
760+                 out .writeBoolean (false );
761+             }
786762        }
787763        out .writeZLong (ifSeqNo );
788764        out .writeVLong (ifPrimaryTerm );
@@ -821,13 +797,13 @@ private void writeBody(StreamOutput out) throws IOException {
821797    public  String  toString () {
822798        String  sSource  = "_na_" ;
823799        try  {
824-             if  (source . length () > MAX_SOURCE_LENGTH_IN_TOSTRING ) {
800+             if  (sourceContext . byteLength () > MAX_SOURCE_LENGTH_IN_TOSTRING ) {
825801                sSource  = "n/a, actual length: [" 
826-                     + ByteSizeValue .ofBytes (source . length ()).toString ()
802+                     + ByteSizeValue .ofBytes (sourceContext . byteLength ()).toString ()
827803                    + "], max length: " 
828804                    + ByteSizeValue .ofBytes (MAX_SOURCE_LENGTH_IN_TOSTRING ).toString ();
829805            } else  {
830-                 sSource  = XContentHelper .convertToJson (source , false );
806+                 sSource  = XContentHelper .convertToJson (sourceContext . bytes () , false );
831807            }
832808        } catch  (Exception  e ) {
833809            // ignore 
@@ -862,7 +838,7 @@ public long getAutoGeneratedTimestamp() {
862838
863839    @ Override 
864840    public  long  ramBytesUsed () {
865-         return  SHALLOW_SIZE  + RamUsageEstimator .sizeOf (id ) + ( source  ==  null  ?  0  :  source . length () );
841+         return  SHALLOW_SIZE  + RamUsageEstimator .sizeOf (id ) + sourceContext . byteLength ( );
866842    }
867843
868844    @ Override 
@@ -917,7 +893,7 @@ public Index getConcreteWriteIndex(IndexAbstraction ia, ProjectMetadata project)
917893
918894    @ Override 
919895    public  int  route (IndexRouting  indexRouting ) {
920-         return  indexRouting .indexShard (id , routing , contentType ,  source );
896+         return  indexRouting .indexShard (id , routing , sourceContext . contentType (),  sourceContext . bytes () );
921897    }
922898
923899    public  IndexRequest  setRequireAlias (boolean  requireAlias ) {
0 commit comments