2009-05-14 15 views
8

मुझे जेएक्स-डब्ल्यूएस में एक जावा वेब सेवा मिली है जो एक अन्य विधि से आउटपुटस्ट्रीम लौटाती है। मुझे यह पता लगाना प्रतीत नहीं होता है कि आउटपुटस्ट्रीम को लौटाए गए डेटाहैंडलर में अस्थायी फ़ाइल बनाने के अलावा किसी भी अन्य तरीके से स्ट्रीम करने के लिए, इसे लिखें, फिर इसे एक इनपुटस्ट्रीम के रूप में फिर से खोलें। यहाँ एक उदाहरण है:आप स्ट्रीमिंगडेटा हैंडलर को आउटपुटस्ट्रीम कैसे पाइप कर सकते हैं?

@MTOM 
@WebService 
class Example { 
    @WebMethod 
    public @XmlMimeType("application/octet-stream") DataHandler service() { 
     // Create a temporary file to write to 
     File fTemp = File.createTempFile("my", "tmp"); 
     OutputStream out = new FileOutputStream(fTemp); 

     // Method takes an output stream and writes to it 
     writeToOut(out); 
     out.close(); 

     // Create a data source and data handler based on that temporary file 
     DataSource ds = new FileDataSource(fTemp); 
     DataHandler dh = new DataHandler(ds); 
     return dh; 
    } 
} 

मुख्य मुद्दा यह है कि writeToOut() विधि डेटा है कि कंप्यूटर की स्मृति की तुलना में कहीं बड़े होते हैं लौट सकते है। यही कारण है कि विधि डेटा स्ट्रीम करने के लिए पहली जगह एमटीओएम का उपयोग कर रही है। मैं आउटपुटस्ट्रीम से सीधे डेटा को स्ट्रीम करने के तरीके के बारे में अपने सिर को लपेट नहीं सकता हूं, जिसे मुझे लौटाए गए डेटाहैंडलर (और अंत में क्लाइंट, जो स्ट्रीमिंगडेटा हैंडलर प्राप्त करता है) को प्रदान करने की आवश्यकता है।

मैंने PipedInputStream और PipedOutputStream के साथ खेलने की कोशिश की है, लेकिन मुझे काफी कुछ नहीं लगता है, क्योंकि PipedOutputStream को लिखने के बाद डेटाहैंडलर को वापस करने की आवश्यकता होगी।

कोई विचार?

+0

भी देखें [इस सवाल] (http: // stackoverflow।कॉम/प्रश्न/2830561/कैसे-टू-कन्वर्ट-ए-इनपुटस्ट्रीम-टू-ए-डाटाहैंडलर) – schnatterer

उत्तर

4

मैं इस सवाल का जवाब पता लगा, लाइनों है कि ईसाई (writeToOut() निष्पादित करने के लिए एक नया धागा बनाने) के बारे में बात कर रहा था के साथ:

@MTOM 
@WebService 
class Example { 
    @WebMethod 
    public @XmlMimeType("application/octet-stream") DataHandler service() { 
     // Create piped output stream, wrap it in a final array so that the 
     // OutputStream doesn't need to be finalized before sending to new Thread. 
     PipedOutputStream out = new PipedOutputStream(); 
     InputStream in = new PipedInputStream(out); 
     final Object[] args = { out }; 

     // Create a new thread which writes to out. 
     new Thread(
      new Runnable(){ 
       public void run() { 
        writeToOut(args); 
        ((OutputStream)args[0]).close(); 
       } 
      } 
     ).start(); 

     // Return the InputStream to the client. 
     DataSource ds = new ByteArrayDataSource(in, "application/octet-stream"); 
     DataHandler dh = new DataHandler(ds); 
     return dh; 
    } 
} 

यह एक बालक और अधिक final चर के कारण जटिल है, लेकिन जैसा कि जहां तक ​​मैं यह कह सकता हूं कि यह सही है। जब धागा शुरू होता है, तो यह पहली बार out.write() पर कॉल करने का प्रयास करता है; साथ ही, इनपुट स्ट्रीम क्लाइंट को वापस कर दी जाती है, जो डेटा को पढ़कर लिखने को अनब्लॉक करता है। (इस समाधान के मेरे पिछले कार्यान्वयन के साथ समस्या यह थी कि मैं स्ट्रीम को सही ढंग से बंद नहीं कर रहा था, और इस प्रकार त्रुटियों में चल रहा था।)

+0

मुझे वास्तव में इसके बारे में बहुत कुछ नहीं पता है, लेकिन सुनिश्चित करें कि पाइप * स्ट्रीम या तो थ्रेड सुरक्षित हैं या "सिंक्रनाइज़" कीवर्ड का उपयोग करें जिसे मैं अपरिचित हूं। – Christian

+0

कृपया ध्यान दें कि [javax.mail.util.ByteArrayDataSource'] का javadoc (http://docs.oracle.com/javaee/6/api/javax/mail/util/ByteArrayDataSource.html#ByteArrayDataSource%28java.io .putStream,% 20java.lang.String% 29) बताता है कि 'इनपुटस्ट्रीम' पूरी तरह से निर्माण पर स्मृति को पढ़ा जाता है। बड़ी फ़ाइलों से निपटने के दौरान इसका परिणाम 'आउटऑफमेमरी एरर' हो सकता है – schnatterer

1

रैपर पैटर्न? :-)।

कस्टम javax.activation.DataSource कार्यान्वयन (केवल 4 विधियों) ऐसा करने में सक्षम होने के लिए?

return new DataHandler(new DataSource() { 
    // implement getOutputStream to return the stream used inside writeToOut() 
    ... 
}); 

मेरे पास परीक्षण करने के लिए आईडीई उपलब्ध नहीं है इसलिए मैं केवल एक सुझाव कर रहा हूं। मुझे सामान्य लेआउट के लिए लिखने की भी आवश्यकता होगी :-)।

+0

[इस उत्तर] में एक कार्य कार्यान्वयन पाया जा सकता है (http://stackoverflow.com/a/10783565/1845976)। – schnatterer

3

क्षमा करें, मैंने केवल यह सी # के लिए किया है, न कि जावा, लेकिन मुझे लगता है कि आपकी विधि को "लिखने के लिए एक थ्रेड लॉन्च करना चाहिए"; पैरारल में। आपको एक विशेष धारा बनाने और इसे नए धागे में पास करने की आवश्यकता है जो उस स्ट्रीम को लिखने के लिए देता है। धागा शुरू करने के बाद आप उस कॉलर ऑब्जेक्ट को अपने कॉलर पर वापस कर देते हैं।

यदि आपके पास केवल एक विधि है जो एक स्ट्रीम को लिखती है और बाद में लौटाती है और दूसरी विधि जो धारा का उपभोग करती है और बाद में लौटाती है, तो कोई दूसरा रास्ता नहीं है।

कड़ी मेहनत के लिए इस तरह के एक-मल्टीथ्रेडिंग सुरक्षित-स्ट्रीम को पकड़ना है: यदि आंतरिक बफर बहुत भरा हुआ है तो यह प्रत्येक तरफ अवरुद्ध होगा।

पता नहीं है कि जावा-पाइप-स्ट्रीम उस के लिए काम करता है या नहीं।

+0

+1 - विचार सही है, और मैं आपको सही रास्ते पर रखने के लिए धन्यवाद देता हूं, लेकिन मेरे उत्तर में वास्तविक जावा समाधान है जो मैं चाहता हूं कि भविष्य में लोग एक ही समस्या में आने पर पहले ढूंढ सकें। –

0

मेरे आवेदन में मैं इनपुटस्ट्रीमडेटासोर्स कार्यान्वयन का उपयोग करता हूं जो इनपुटडेट्रीम को फ़ाइलडेटा स्रोत में फ़ाइल के बजाय कन्स्ट्रक्टर तर्क के रूप में लेता है । यह अब तक काम करता है।

public class InputStreamDataSource implements DataSource { 

ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
private final String name; 

public InputStreamDataSource(InputStream inputStream, String name) { 
    this.name = name; 
    try { 
     int nRead; 
     byte[] data = new byte[16384]; 
     while ((nRead = inputStream.read(data, 0, data.length)) != -1) { 
      buffer.write(data, 0, nRead); 
     } 

     buffer.flush(); 
     inputStream.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 

@Override 
public String getContentType() { 
    return new MimetypesFileTypeMap().getContentType(name); 
} 

@Override 
public InputStream getInputStream() throws IOException { 
    return new ByteArrayInputStream(buffer.toByteArray()); 
} 

@Override 
public String getName() { 
    return name; 
} 

@Override 
public OutputStream getOutputStream() throws IOException { 
    throw new IOException("Read-only data"); 
} 

}

संबंधित मुद्दे