Προγραμματισμός

Αναθεωρήθηκαν οι βιβλιοθήκες πελατών Java FTP

Ας φανταστούμε μια κατάσταση όπου θέλουμε να γράψουμε μια καθαρή εφαρμογή Java που πρέπει να κατεβάσει αρχεία από έναν απομακρυσμένο υπολογιστή που χρησιμοποιεί διακομιστή FTP. Θέλουμε επίσης να φιλτράρουμε τις λήψεις βάσει απομακρυσμένων πληροφοριών αρχείων όπως όνομα, ημερομηνία ή μέγεθος.

Αν και είναι δυνατόν, και ίσως διασκεδαστικό, να γράψετε ένα χειριστή πρωτοκόλλου για το FTP από το μηδέν, το να το κάνετε είναι επίσης δύσκολο, μακρύ και δυνητικά επικίνδυνο. Δεδομένου ότι δεν θα προτιμούσαμε να ξοδεύουμε το χρόνο, την προσπάθεια ή τα χρήματα για να γράψουμε μόνοι μας έναν χειριστή, προτιμούμε να χρησιμοποιήσουμε ένα υπάρχον στοιχείο λογισμικού. Και πολλές βιβλιοθήκες είναι διαθέσιμες στο World Wide Web. Με μια βιβλιοθήκη πελατών FTP, η λήψη ενός αρχείου μπορεί να γραφτεί σε Java με τον ίδιο τρόπο:

FTPClient ftpClient = νέο FTPClient (); ftpClient.connect ("ftp.foo.com", "user01", "pass1234"); ftpClient.download ("C: \ Temp \", "README.txt"); // Τελικά άλλες λειτουργίες εδώ ... ftpClient.disconnect (); 

Η αναζήτηση ποιοτικής βιβλιοθήκης πελατών Java FTP που να ανταποκρίνεται στις ανάγκες μας δεν είναι τόσο απλή όσο φαίνεται. μπορεί να είναι αρκετά οδυνηρό. Χρειάζεται λίγος χρόνος για να βρείτε μια βιβλιοθήκη πελατών Java FTP. Στη συνέχεια, αφού βρούμε όλες τις υπάρχουσες βιβλιοθήκες, ποια επιλέγουμε; Κάθε βιβλιοθήκη καλύπτει διαφορετικές ανάγκες. Οι βιβλιοθήκες έχουν άνιση ποιότητα και τα σχέδιά τους διαφέρουν ουσιαστικά. Καθένα προσφέρει ένα διαφορετικό σύνολο χαρακτηριστικών και χρησιμοποιεί διαφορετικούς τύπους ορολογίας για να τα περιγράψει.

Έτσι, η αξιολόγηση και η σύγκριση βιβλιοθηκών πελατών FTP μπορεί να αποδειχθεί δύσκολη και συγκεχυμένη. Η επαναχρησιμοποίηση υπαρχόντων στοιχείων είναι μια αξιέπαινη διαδικασία, αλλά σε αυτήν την περίπτωση, η εκκίνηση μπορεί να είναι αποθαρρυντική. Και αυτό είναι κρίμα: μετά την επιλογή μιας καλής βιβλιοθήκης FTP, τα υπόλοιπα είναι ρουτίνα.

Αυτό το άρθρο στοχεύει να κάνει τη διαδικασία επιλογής σύντομη, εύκολη και αξιόλογη. Καταγράφω πρώτα όλες τις διαθέσιμες βιβλιοθήκες πελατών FTP. Στη συνέχεια, ορίζω και περιγράφω μια λίστα σχετικών κριτηρίων που πρέπει να αντιμετωπίζουν οι βιβλιοθήκες με κάποιο τρόπο. Τέλος, παρουσιάζω μια μήτρα επισκόπησης που δίνει μια γρήγορη εικόνα για το πώς οι βιβλιοθήκες συσσωρεύονται μεταξύ τους. Όλες αυτές οι πληροφορίες παρέχουν όλα όσα χρειαζόμαστε για να πάρουμε μια γρήγορη, αξιόπιστη και μακροχρόνια απόφαση.

Υποστήριξη FTP στο JDK

Η προδιαγραφή αναφοράς για το FTP είναι Αίτημα για Σχόλια: 959 (RFC959). Η Sun Microsystems παρέχει μια εφαρμογή RFC959 στο JDK, αλλά είναι εσωτερική, χωρίς έγγραφα και δεν παρέχεται πηγή. Ενώ το RFC959 βρίσκεται στις σκιές, είναι στην πραγματικότητα το πίσω μέρος μιας δημόσιας διεπαφής που εφαρμόζει το RFC1738, την προδιαγραφή URL, όπως φαίνεται στο Σχήμα 1.

Μια εφαρμογή του RFC1738 προσφέρεται στάνταρ στο JDK. Κάνει μια λογική δουλειά για βασικές λειτουργίες μεταφοράς FTP. Είναι δημόσιο και τεκμηριωμένο και παρέχεται πηγαίος κώδικας. Για να το χρησιμοποιήσουμε, γράφουμε τα εξής:

URL url = νέο URL ("ftp: // user01: [email protected]/README.txt; type = i"); URLConnection urlc = url.openConnection (); Το InputStream είναι = urlc.getInputStream (); // Για λήψη του OutputStream os = urlc.getOutputStream (); // Για μεταφόρτωση 

Η υποστήριξη πελατών FTP στο JDK ακολουθεί αυστηρά την τυπική πρόταση, αλλά έχει πολλά μειονεκτήματα:

  • Διαφέρει ουσιαστικά από τις βιβλιοθήκες πελατών FTP τρίτων. αυτά εφαρμόζουν RFC959 και όχι RFC1738.
  • Το RFC959 εφαρμόζεται στα περισσότερα εργαλεία υπολογιστή-πελάτη FTP. Πολλοί προγραμματιστές Java χρησιμοποιούν αυτά τα εργαλεία για να συνδεθούν σε διακομιστές FTP. Όσον αφορά το γούστο, αυτά τα εργαλεία προτιμούν κατά πάσα πιθανότητα βιβλιοθήκες τύπου RFC959.
  • ο Διεύθυνση URL και Σύνδεση URLC τα μαθήματα ανοίγουν μόνο ροές για επικοινωνία. Η βιβλιοθήκη Sun δεν προσφέρει άμεση υποστήριξη για τη δομή των πρώτων απαντήσεων διακομιστή FTP σε πιο εύχρηστα αντικείμενα Java όπως Σειρά, Αρχείο, RemoteFile, ή Ημερολόγιο. Επομένως, πρέπει να γράψουμε περισσότερο κώδικα μόνο για να γράψουμε δεδομένα σε ένα αρχείο ή για να εκμεταλλευτούμε μια λίστα καταλόγων.
  • Όπως εξηγείται στην ενότητα 3.2.5 του RFC1738, "Βελτιστοποίηση", οι διευθύνσεις URL FTP απαιτούν τη σύνδεση (ελέγχου) να κλείνει μετά από κάθε λειτουργία. Αυτό είναι σπατάλη και δεν είναι αποτελεσματικό για τη μεταφορά πολλών μικρών αρχείων. Επιπλέον, εξαιρετικά περιοριστικοί διακομιστές FTP ενδέχεται να θεωρήσουν μια τέτοια επικοινωνία γενικά ως κακή επίθεση ή κατάχρηση δικτύου και να αρνηθούν περαιτέρω υπηρεσίες.
  • Τέλος, δεν διαθέτει πολλά χρήσιμα χαρακτηριστικά.

Για όλους ή για οποιονδήποτε από αυτούς τους λόγους, προτιμάται η χρήση βιβλιοθήκης τρίτων. Η ακόλουθη ενότητα παραθέτει τις διαθέσιμες εναλλακτικές λύσεις τρίτων.

Σύγκριση βιβλιοθήκης

Η παρακάτω λίστα περιγράφει τις βιβλιοθήκες που συγκρίνω σε αυτό το άρθρο. Όλοι ακολουθούν τις προδιαγραφές FTP αναφοράς. Παρακάτω, αναφέρω το όνομα του παρόχου και το όνομα της βιβλιοθήκης (με πλάγια γράμματα). Οι πόροι περιλαμβάνουν συνδέσμους προς κάθε ιστότοπο προϊόντος. Για να ξεκινήσω τη χρήση της βιβλιοθήκης, αναφέρομαι επίσης στην κύρια κατηγορία πελατών FTP.

  1. JScape, Εργοστάσιο iNet: com.jscape.inet.ftp.Ftp
  2. / n λογισμικό, IP * Λειτουργεί: ipworks.Ftp
  3. Επιχειρησιακές Κατανεμημένες Τεχνολογίες, Βιβλιοθήκη πελατών Java FTP: com.enterprisedt.net.ftp.FTPClient
  4. IBM alphaWorks, FTP Bean Σουίτα: com.ibm.network.ftp.protocol.FTPProtocol
  5. SourceForge, JFtp: net.sf.jftp.net.FtpConnection
  6. Το έργο Τζακάρτα, Τζακάρτα Commons / Net: org.apache.commons.net.ftp.FTP πελάτη
  7. JavaShop JNetBeans: jshop.jnet.FTPClient
  8. Ήλιος, JDK: sun.net.ftp.FtpClient
  9. Florent Cueto, API JavaFTP: com.cqs.ftp.FTP
  10. Bea Petrovicova, jFTP: cz.dhl.ftp.Ftp
  11. Το έργο Globus, Κιτ Java CoG: org.globus.io.ftp.FTP πελάτη

Σημειώσεις:

  • Τη στιγμή της σύνταξης αυτής, η IBM αξιολογεί την καταλληλότητα να προσφέρει το alphaWorks FTP Bean Suite στον ιστότοπό της. Προς το παρόν, η λήψη είναι κλειστή για όλους τους χρήστες.
  • Το Jakarta Commons / Net είναι ένα υποκατάστατο αντικατάστασης για το Savarese NetComponents, το οποίο δεν έχει πλέον αναπτυχθεί.
  • Το JavaShop JNetBeans φαίνεται να έχει εγκαταλειφθεί. Τη στιγμή αυτής της γραφής, ο ιστότοπος ήταν εκτός σύνδεσης για περισσότερο από ένα μήνα και δεν έλαβα ποτέ απαντήσεις στα αιτήματά μου για υποστήριξη.

Κριτήρια

Μέχρι στιγμής, έχω εισαγάγει το πλαίσιο και παραθέτω τις διαθέσιμες βιβλιοθήκες. Τώρα, παραθέτω τα σχετικά κριτήρια βάσει των οποίων θα αξιολογηθεί κάθε βιβλιοθήκη. Καταγράφω πιθανές τιμές για κάθε κριτήριο, μαζί με τη συντομογραφία (σε τολμηρός) χρησιμοποιείται στην τελική μήτρα σύγκρισης.

Υποστήριξη προιόντος

Οι βιβλιοθήκες παρέχουν υποστήριξη στους χρήστες μέσω της τεκμηρίωσης του προϊόντος, της σύνταξης Javadocs, του δείγματος κώδικα και ενός παραδείγματος εφαρμογής που μπορεί να περιλαμβάνει σχόλια και εξηγήσεις. Πρόσθετη υποστήριξη μπορεί να προσφερθεί στους χρήστες μέσω φόρουμ, λίστες αλληλογραφίας, μια διεύθυνση email επικοινωνίας ή ένα ηλεκτρονικό σύστημα εντοπισμού σφαλμάτων. / Το λογισμικό προσφέρει εκτεταμένη υποστήριξη με επιπλέον χρέωση.

Το κίνητρο του διαχειριστή υποστήριξης είναι ένας σημαντικός παράγοντας για γρήγορη υποστήριξη. Οι διαχειριστές υποστήριξης μπορούν να είναι:

  • Ένα εθελοντικό άτομο (Εγώ)
  • Μια εθελοντική ομάδα (σολ)
  • Μια επαγγελματική οντότητα που πληρώθηκε για να παρέχει υποστήριξη (Π)

Αδεια

Για εμπορικά έργα, μια άδεια προϊόντος είναι ένα σημαντικό ζήτημα που πρέπει να ληφθεί υπόψη από την αρχή. Ορισμένες βιβλιοθήκες μπορούν να αναδιανεμηθούν ελεύθερα σε εμπορικά προϊόντα και άλλες δεν μπορούν. Για παράδειγμα, η GPL (GNU General Public License) είναι μια ισχυρή, περιοριστική άδεια, ενώ η άδεια λογισμικού Apache απαιτεί μνεία μόνο σε αναδιανεμημένα προϊόντα.

Οι εμπορικές άδειες περιορίζουν τον αριθμό προγραμματισμού σταθμών ανάπτυξης με τη βιβλιοθήκη, αλλά η διανομή της ίδιας της βιβλιοθήκης δεν περιορίζεται.

Για μη εμπορικά έργα, η άδεια είναι περισσότερο θέμα φιλοσοφίας. ένα δωρεάν προϊόν είναι αισθητό.

Οι άδειες μπορούν να είναι:

  • Εμπορική (ντο)
  • GPL (σολ)
  • Ελεύθερος (φά); Ωστόσο, ελέγξτε μια δωρεάν άδεια για περιορισμούς

Ορισμένοι πάροχοι βιβλιοθηκών παρέχουν εναλλακτικές, λιγότερο περιοριστικές άδειες κατόπιν αιτήματος.

Παρέχεται πηγαίος κώδικας

Μια βιβλιοθήκη λογισμικού κλειστού κώδικα μπορεί να είναι ενοχλητική. Η ύπαρξη πηγαίου κώδικα μπορεί να είναι πιο άνετη για τους ακόλουθους λόγους:

  • Κατά τον εντοπισμό σφαλμάτων εκτέλεσης κώδικα εφαρμογής, η είσοδος στην πηγή κώδικα βιβλιοθήκης μπορεί να σας βοηθήσει να κατανοήσετε τη συμπεριφορά της βιβλιοθήκης
  • Ο πηγαίος κώδικας έχει χρήσιμα σχόλια
  • Ο πηγαίος κώδικας μπορεί να τροποποιηθεί γρήγορα ώστε να ταιριάζει με ειδικές ανάγκες
  • Ο υποδειγματικός πηγαίος κώδικας μπορεί να είναι εμπνευσμένος

Ηλικία

Οι βιβλιοθήκες έχουν δοκιμαστεί, εντοπιστεί σφάλματα και υποστηρίζονται από την πρώτη δημόσια κυκλοφορία τους. Καθώς η αρίθμηση έκδοσης ποικίλλει μεταξύ των βιβλιοθηκών, βασίζω αυτό το κριτήριο στο έτος της πρώτης δημόσιας έκδοσης.

Υποστήριξη καταλόγου καταλόγου

Η ανάκτηση απομακρυσμένων πληροφοριών αρχείου (όνομα, μέγεθος, ημερομηνία) από το διακομιστή είναι σημαντική στις περισσότερες εφαρμογές. Το πρωτόκολλο FTP προσφέρει το NLST εντολή για ανάκτηση μόνο των ονομάτων αρχείων. ο NLST Η εντολή έχει σχεδιαστεί ρητά για εκμετάλλευση από προγράμματα. ο ΛΙΣΤΑ Η εντολή προσφέρει περισσότερες πληροφορίες αρχείου. όπως σημειώνει το RFC959, "Δεδομένου ότι οι πληροφορίες σε ένα αρχείο ενδέχεται να διαφέρουν πολύ από σύστημα σε σύστημα, αυτές οι πληροφορίες μπορεί να είναι δύσκολο να χρησιμοποιηθούν αυτόματα σε ένα πρόγραμμα, αλλά μπορεί να είναι αρκετά χρήσιμες για έναν ανθρώπινο χρήστη." Καμία άλλη τυπική μέθοδος δεν ανακτά πληροφορίες αρχείου. Επομένως, οι βιβλιοθήκες πελατών προσπαθούν να εκμεταλλευτούν το ΛΙΣΤΑ απάντηση. Αλλά αυτό δεν είναι εύκολο έργο: δεδομένου ότι δεν υπάρχει έγκυρη σύσταση για το ΛΙΣΤΑ μορφή απόκρισης, οι διακομιστές FTP έχουν υιοθετήσει διάφορες μορφές:

  • Στυλ Unix: drwxr-xr-x 1 user01 ftp 512 29 Ιαν 23:32 prog
  • Εναλλακτικό στυλ Unix: drwxr-xr-x 1 user01 ftp 512 29 Ιανουαρίου 1997 prog
  • Εναλλακτικό στυλ Unix: drwxr-xr-x 1 1 1 512 29 Ιανουαρίου 23:32 prog
  • Ένας συμβολικός σύνδεσμος σε στυλ Unix: lrwxr-xr-x 1 χρήστης01 ftp 512 29 Ιανουαρίου 23:32 prog -> prog2000
  • Παράξενο στυλ Unix (χωρίς διάστημα μεταξύ χρήστη και ομάδας): drwxr-xr-x 1 όνομα χρήστηftp 512 29 Ιανουαρίου 23:32 prog
  • Στυλ MS-DOS: 01-29-97 11:32 μμ prog
  • Στυλ Macintosh: φάκελος drwxr-xr-x 0 29 Ιανουαρίου 23:32 prog
  • Στυλ OS / 2: 0 DIR 01-29-97 23:32 ΠΡΟΓΡΑΜΜΑ

Το στυλ Unix, τότε το στυλ MS-DOS, είναι οι πιο διαδεδομένες μορφές.

Οι βιβλιοθήκες πελατών Java FTP προσπαθούν να κατανοήσουν και να εντοπίσουν αυτόματα όσο το δυνατόν περισσότερες μορφές. Επιπλέον, προσφέρουν διάφορες εναλλακτικές λύσεις για τον χειρισμό απροσδόκητων απαντήσεων σε μορφή:

  • Μια πρόσθετη μέθοδος που επιστρέφει μια ακατέργαστη απόκριση FTP ως μία συμβολοσειρά (μικρό)
  • Μια πρόσθετη μέθοδος που επιστρέφει μια συλλογή ακατέργαστων συμβολοσειρών, μία συμβολοσειρά ανά γραμμή / αρχείο (ντο)
  • Ένα πλαίσιο που υποστηρίζει pluggable parsers (Π)

Οι περισσότερες βιβλιοθήκες αναλύονται ΛΙΣΤΑ αποκρίσεις και δομή πληροφοριών ακατέργαστου αρχείου σε αντικείμενα Java. Για παράδειγμα, με το JScape iNet Factory, ο ακόλουθος κώδικας ανακτά και εκμεταλλεύεται τις πληροφορίες αρχείων που λαμβάνονται σε μια λίστα καταλόγων:

java.util.Enumeration files = ftpClient.getDirListing (); ενώ (files.hasMoreElements ()) {FtpFile ftpFile = (FtpFile) files.nextElement (); System.out.println (ftpFile.getFilename ()); System.out.println (ftpFile.getFilesize ()); // κ.λπ. άλλες χρήσιμες μέθοδοι περιγράφονται αναλυτικά στο Javadoc} 

Η ενότητα "Λύσεις για τα υπόλοιπα προβλήματα" εξετάζει περαιτέρω τις καταχωρίσεις καταλόγων.

Ανάκτηση χρονικής σήμανσης

Σε πολλές περιπτώσεις, μας ενδιαφέρει η τελευταία χρονική σήμανση τροποποίησης ενός απομακρυσμένου αρχείου. Δυστυχώς, κανένα RFC δεν εισάγει μια τυπική εντολή FTP για την ανάκτηση αυτών των πληροφοριών. Υπάρχουν δύο de facto μέθοδοι:

  1. Ανακτήστε αυτές τις πληροφορίες από το ΛΙΣΤΑ απάντηση αναλύοντας την απάντηση του διακομιστή. Δυστυχώς, όπως μάθατε στην προηγούμενη ενότητα, το ΛΙΣΤΑ Η απόκριση ποικίλλει μεταξύ των διακομιστών FTP και οι πληροφορίες της χρονικής σήμανσης είναι μερικές φορές ελλιπείς. Στη μορφή Unix, η ανακρίβεια εμφανίζεται όταν το απομακρυσμένο αρχείο είναι άνω του ενός έτους: δίνονται μόνο η ημερομηνία και το έτος, αλλά όχι ώρες ή λεπτά.
  2. Χρησιμοποιήστε το μη τυποποιημένο MDTM εντολή, η οποία ανακτά συγκεκριμένα την τελευταία χρονική σήμανση τροποποίησης ενός απομακρυσμένου αρχείου. Δυστυχώς, δεν εφαρμόζουν όλοι οι διακομιστές FTP αυτήν την εντολή.

Μια περίπλοκη εναλλακτική λύση MDTM Η υποστήριξη εντολών είναι να στείλετε μια πρώτη MDTM εντολή και ανάλυση της απόκρισης. Οι περισσότερες βιβλιοθήκες παρέχουν μια μέθοδο για την αποστολή μιας αρχικής εντολής FTP, όπως:

Χρόνος συμβολοσειράςStampString = ftpClient.command ("MDTM README.txt"); 

Μια άλλη πιθανή ανησυχία είναι ότι οι διακομιστές FTP επιστρέφουν πληροφορίες χρόνου στο GMT (Greenwich Mean Time). Εάν η ζώνη ώρας διακομιστή είναι γνωστή εκτός από την επικοινωνία FTP, το java.util.TimeZone.getOffset () μέθοδος μπορεί να βοηθήσει στην προσαρμογή μιας ημερομηνίας μεταξύ των ζωνών ώρας. Ανατρέξτε στην τεκμηρίωση του JDK για περισσότερες πληροφορίες σχετικά με αυτήν τη μέθοδο.

Η ενότητα "Λύσεις για υπολείμματα προβλημάτων" εξετάζει περαιτέρω την ανάκτηση χρονικής σήμανσης αρχείου.

Τείχη προστασίας

Συνήθως, ένα τείχος προστασίας τοποθετείται μεταξύ ενός ιδιωτικού δικτύου επιχειρήσεων και ενός δημόσιου δικτύου όπως το Διαδίκτυο. Η πρόσβαση γίνεται από το ιδιωτικό δίκτυο στο δημόσιο δίκτυο, αλλά η πρόσβαση δεν επιτρέπεται από το δημόσιο δίκτυο στο ιδιωτικό δίκτυο.

Το Socks είναι ένα δημόσια διαθέσιμο πρωτόκολλο που αναπτύχθηκε για χρήση ως πύλη τείχους προστασίας για το Διαδίκτυο. Το JDK υποστηρίζει διακομιστές μεσολάβησης Socks 4 και Socks 5, οι οποίοι μπορούν να ελεγχθούν από ορισμένες βιβλιοθήκες. Εναλλακτικά, η γραμμή εντολών JVM μπορεί να ορίσει τις παραμέτρους διακομιστή μεσολάβησης Socks: java -DsocksProxyPort = 1080 -DsocksProxyHost = socks.foo.com -Djava.net.socks.username = user01 -Djava.net.socks.password = pass1234 ...

Μια άλλη κοινή εναλλακτική λύση για την υποστήριξη διακομιστή μεσολάβησης Socks είναι το "socksify" του υποκείμενου επιπέδου TCP / IP στον υπολογιστή-πελάτη. Ένα προϊόν όπως το κολίβριο μπορεί να κάνει αυτή τη δουλειά.

Το JDK υποστηρίζει επίσης σήραγγες HTTP. Αυτοί οι διαδεδομένοι διακομιστές μεσολάβησης δεν επιτρέπουν μεταφορτώσεις FTP. / Το λογισμικό IP * Works σας επιτρέπει να ορίσετε παραμέτρους σήραγγας HTTP.

Οι περισσότερες βιβλιοθήκες υποστηρίζουν ενεργές και παθητικές συνδέσεις: η παθητική σύνδεση είναι χρήσιμη όταν ο πελάτης βρίσκεται πίσω από ένα τείχος προστασίας που εμποδίζει τις εισερχόμενες συνδέσεις σε υψηλότερες θύρες. Το RFC1579 συζητά αυτήν τη λειτουργικότητα φιλική προς το τείχος προστασίας με περισσότερες λεπτομέρειες. Ορισμένα έγγραφα τεκμηρίωσης αναφέρονται σε ενεργές και παθητικές συνδέσεις ως ΛΙΜΑΝΙ και PASV εντολές, αντίστοιχα.

Παράλληλη μεταφορά

Σε μια εφαρμογή επιτραπέζιου υπολογιστή, όταν ξεκινά μια μεταφορά στο κύριο μονό νήμα, όλα παγώνουν. Ορισμένες βιβλιοθήκες εξυπηρετούν αυτόματα το βρόχο συμβάντος για παράλληλες μεταφορές σε ξεχωριστά νήματα, οπότε δεν χρειάζεται να δημιουργήσουμε και να διαχειριστούμε τα δικά μας νήματα.

Υποστήριξη προδιαγραφών JavaBean

Ορισμένες βιβλιοθήκες εφαρμόζουν την προδιαγραφή JavaBean. Η συμμόρφωση JavaBean επιτρέπει οπτικό προγραμματισμό, ο οποίος εμφανίζεται σε μεγάλα IDE Java.

$config[zx-auto] not found$config[zx-overlay] not found