--2762493:lib/xp-rt-5.7.4.xar:-- CCAglang/archive/Archive.class.php#"lang/archive/ArchiveClassLoader.class.php#"lang/archive/ArchiveReader.class.php?lang/archive/package-info.xp Tlang/ChainedException.class.php6Vlang/ClassCastException.class.php _lang/ClassFormatException.class.php`lang/ClassLoader.class.php0alang/ClassNotFoundException.class.phplang/CloneNotSupportedException.class.php@Wlang/Collection.class.php lang/DynamicClassLoader.class.phpRlang/ElementNotFoundException.class.phpolang/Enum.class.phplang/Error.class.phplang/FileSystemClassLoader.class.phpvQlang/FormatException.class.php lang/Generic.class.phplang/IClassLoader.class.php-lang/IllegalAccessException.class.phplang/IllegalArgumentException.class.phpv@lang/IllegalStateException.class.phplang/IllegalThreadStateException.class.php"lang/IndexOutOfBoundsException.class.phpqlang/MethodNotImplementedException.class.phpXlang/NullPointerException.class.phpWlang/Object.class.php- klang/package-info.xp$lang/Primitive.class.php3lang/Process.class.php')6Blang/reflect/Constructor.class.php ]klang/reflect/Field.class.phpcbtlang/reflect/InvocationHandler.class.phpŌlang/reflect/Method.class.phpg Mlang/reflect/Modifiers.class.phpz lang/reflect/package-info.xp.lang/reflect/Package.class.php%lang/reflect/Parameter.class.phpZ lang/reflect/Proxy.class.phplang/reflect/Routine.class.php"lang/reflect/TargetInvocationException.class.php0lang/Runnable.class.phpolang/Runtime.class.phpslang/RuntimeError.class.php2lang/RuntimeOptions.class.php 3lang/StackTraceElement.class.phpS ?lang/System.class.phpSKlang/SystemException.class.php[Yelang/Thread.class.phpglang/Throwable.class.php!}lang/Type.class.phpj Ǔlang/types/ArrayList.class.php1lang/types/Boolean.class.php0lang/types/Byte.class.php4lang/types/Bytes.class.phplang/types/Character.class.php lang/types/Double.class.php.lang/types/Float.class.phpGlang/types/Integer.class.php=[lang/types/Long.class.php6lang/types/Number.class.php!lang/types/package-info.xplang/types/Short.class.php:lang/types/String.class.php"lang/XPClass.class.phpOlang/XPException.class.php1^util/AbstractDeferredInvokationHandler.class.php`util/Binford.class.phpheutil/Calendar.class.phpPmutil/ChainedException.class.php^ ,util/cmd/Command.class.phplutil/cmd/Console.class.php_ util/cmd/package-info.xplUutil/cmd/ParamString.class.phputil/cmd/Runner.class.phpF,wutil/cmd/SingleProcess.class.phpNutil/collections/Arrays.class.php! util/collections/DJBX33AHashImplementation.class.php ,util/collections/HashImplementation.class.phputil/collections/HashProvider.class.phputil/collections/HashSet.class.php  util/collections/HashTable.class.php#util/collections/IList.class.php?util/collections/LRUBuffer.class.php Gutil/collections/Map.class.php6 -Sutil/collections/MD5HashImplementation.class.phpHc]util/collections/package-info.xpQ_util/collections/Queue.class.phpfutil/collections/Set.class.phpDyutil/collections/Stack.class.phputil/collections/Vector.class.php7%util/Comparator.class.phpoIutil/Component.class.phputil/Configurable.class.phputil/Date.class.php+}util/DateInterval.class.phputil/DateMath.class.php 8util/DateUtil.class.php util/DeferredInitializationException.class.phpSutil/Hashmap.class.phpM"+util/HashmapIterator.class.phpCx2util/Locale.class.php8util/log/BufferedAppender.class.phpFutil/log/ColoredConsoleAppender.class.phpXJutil/log/ConsoleAppender.class.php:LSutil/log/FileAppender.class.phpxVutil/log/LogAppender.class.phpXZutil/log/LogCategory.class.php V^util/log/Logger.class.php=util/log/LogLevel.class.phppțutil/log/LogObserver.class.php8util/log/package-info.xpV util/log/SmtpAppender.class.php0_util/log/StreamAppender.class.phputil/log/SyslogAppender.class.php"util/log/Traceable.class.phputil/MimeType.class.php].util/NoSuchElementException.class.phpnutil/Observable.class.php Uutil/Observer.class.phpuutil/package-info.xpk util/profiling/Timer.class.phputil/Properties.class.php3Mutil/PropertyManager.class.php8util/semaphore/Semaphore.class.phpAutil/semaphore/SessionSemaphore.class.phpE]Eutil/ServiceException.class.phpMutil/telephony/TelephonyAddress.class.phpTutil/telephony/TelephonyAddressParser.class.php@=Wutil/telephony/TelephonyCall.class.phputil/telephony/TelephonyException.class.phputil/telephony/TelephonyProvider.class.phpj util/telephony/TelephonyTerminal.class.phputil/TimeInterval.class.phpr٨util/TimeSpan.class.phpjKutil/TimeZone.class.phputil/TimeZoneTransition.class.php#util/Visitor.class.phputil/XPIterator.class.phpio/ByteOrder.class.phpuio/collections/ArchiveCollection.class.phpzio/collections/ArchiveElement.class.php $ io/collections/CollectionComposite.class.php< io/collections/FileCollection.class.php3#io/collections/FileElement.class.php 1io/collections/IOCollection.class.php;io/collections/IOElement.class.phpH>io/collections/iterate/AbstractCombinedFilter.class.phpv&Eio/collections/iterate/AbstractDateComparisonFilter.class.phpIio/collections/iterate/AbstractSizeComparisonFilter.class.php;Mio/collections/iterate/AccessedAfterFilter.class.phpLPio/collections/iterate/AccessedBeforeFilter.class.phpO%Sio/collections/iterate/AllOfFilter.class.php}tUio/collections/iterate/AnyOfFilter.class.php`Yio/collections/iterate/CollectionFilter.class.php Q^io/collections/iterate/CreatedAfterFilter.class.phpGZaio/collections/iterate/CreatedBeforeFilter.class.phpJcio/collections/iterate/ExtensionEqualsFilter.class.phpeio/collections/iterate/FilteredIOCollectionIterator.class.php jio/collections/iterate/IOCollectionIterator.class.phpqio/collections/iterate/IterationFilter.class.phpio/collections/iterate/ModifiedAfterFilter.class.phpL`io/collections/iterate/ModifiedBeforeFilter.class.phpOio/collections/iterate/NameEqualsFilter.class.phpio/collections/iterate/NameMatchesFilter.class.php ʌio/collections/iterate/NegationOfFilter.class.phpӐio/collections/iterate/RegexFilter.class.phpsio/collections/iterate/SizeBiggerThanFilter.class.php0io/collections/iterate/SizeEqualsFilter.class.php)Fio/collections/iterate/SizeSmallerThanFilter.class.php2oio/collections/package-info.xpio/dba/DBAFile.class.phpcio/dba/DBAIterator.class.php{%io/EncapsedStream.class.phpio/File.class.phpDio/FileNotFoundException.class.phpU!io/FilePermission.class.php"io/FileUtil.class.php#io/Folder.class.php~(io/IOException.class.phpOHio/OperationTimedOutException.class.phpYIio/package-info.xpUQKio/SearchableStream.class.phpPio/SpoolDirectory.class.phpYio/Stream.class.phpWjio/streams/BufferedInputStream.class.php-io/streams/BufferedOutputStream.class.php,<io/streams/ChannelInputStream.class.phpLhio/streams/ChannelOutputStream.class.phpio/streams/ConsoleInputStream.class.php|io/streams/ConsoleOutputStream.class.php0io/streams/FileInputStream.class.php/io/streams/FileOutputStream.class.phpưio/streams/InputStream.class.phpoSio/streams/InputStreamReader.class.phpv¸io/streams/MemoryInputStream.class.php8io/streams/MemoryOutputStream.class.phpVio/streams/OutputStream.class.phpoio/streams/OutputStreamWriter.class.phpmio/streams/package-info.xp~io/streams/Seekable.class.phpsio/streams/Streams.class.phpio/streams/StringReader.class.phpBio/streams/StringWriter.class.php io/sys/Ftok.class.phpio/sys/IPCMessage.class.php io/sys/IPCQueue.class.php^ io/sys/Semaphore.class.phpa n! io/sys/ShmSegment.class.php , io/sys/StdStream.class.php'z9 io/TempFile.class.phpU< io/ZipFile.class.phpOA sapi/cgi.sapi.phpEY sapi/class.sapi.php_ sapi/cli.sapi.phpZhb sapi/gui/gtk.sapi.phpf sapi/scriptlet/development.sapi.phpByl sapi/scriptlet/error400.htmln sapi/scriptlet/error403.htmls sapi/scriptlet/error404.htmlx sapi/scriptlet/error405.html} sapi/scriptlet/error406.html sapi/scriptlet/error500.html sapi/scriptlet/error503.html  sapi/scriptlet/production.sapi.php sapi/scriptlet/ScriptletRunner.class.php sapi/soap/client.sapi.php sapi/soap/service.sapi.php] sapi/strict.sapi.php6 sapi/synchronized.sapi.php1O sapi/xmlrpc/client.sapi.php sapi/xmlrpc/service.sapi.phpz peer/AuthenticationException.class.php peer/BSDSocket.class.phpC' peer/ConnectException.class.phpV* peer/ftp/collections/FtpCollection.class.php peer/ftp/collections/FtpElement.class.php peer/ftp/DefaultFtpListParser.class.php peer/ftp/FtpConnection.class.php. peer/ftp/FtpDir.class.php"Q3 peer/ftp/FtpDownload.class.phpU V peer/ftp/FtpEntry.class.phpzW` peer/ftp/FtpEntryList.class.phpy peer/ftp/FtpFile.class.php peer/ftp/FtpInputStream.class.php| peer/ftp/FtpListIterator.class.php peer/ftp/FtpListParser.class.phpu peer/ftp/FtpOutputStream.class.phpg peer/ftp/FtpTransfer.class.php3 peer/ftp/FtpTransferListener.class.php peer/ftp/FtpTransferStream.class.phpj peer/ftp/FtpUpload.class.php<  peer/ftp/package-info.xpO peer/ftp/server/FtpConnectionListener.class.php peer/ftp/server/FtpProtocol.class.php|S peer/ftp/server/FtpSession.class.phpA peer/ftp/server/FtpThread.class.php peer/ftp/server/interceptor/DefaultInterceptor.class.php peer/ftp/server/interceptor/EntrynameInterceptor.class.php peer/ftp/server/interceptor/InterceptorCondition.class.phpx peer/ftp/server/interceptor/PathCondition.class.phpe peer/ftp/server/interceptor/StorageActionInterceptor.class.php peer/ftp/server/storage/FilesystemStorage.class.php peer/ftp/server/storage/FilesystemStorageCollection.class.phpcN peer/ftp/server/storage/FilesystemStorageElement.class.php0 peer/ftp/server/storage/Storage.class.php~B peer/ftp/server/storage/StorageCollection.class.phpJH peer/ftp/server/storage/StorageElement.class.phpJ peer/ftp/server/storage/StorageEntry.class.phpN peer/ftp/WindowsFtpListParser.class.phpV peer/Header.class.php\ peer/http/BasicAuthorization.class.phppeer/server/ConnectionEvent.class.php?peer/server/ConnectionListener.class.php Bpeer/server/ForkingServer.class.phpWKpeer/server/PreforkingServer.class.php6Speer/server/protocol/ListenerWrapperProtocol.class.php opeer/server/Server.class.php wpeer/server/ServerProtocol.class.phppeer/ServerSocket.class.phppeer/sieve/SieveClient.class.php9 peer/sieve/SieveScript.class.phppeer/Socket.class.phppeer/SocketException.class.phpJpeer/SocketInputStream.class.phpIpeer/SocketOutputStream.class.phpB peer/SocketTimeoutException.class.phppeer/SSLSocket.class.phpepeer/TLSSocket.class.phpOpeer/UDPSocket.class.phpVfpeer/URL.class.php2&peer/webdav/WebdavClient.class.php@peer/webdav/WebdavConnection.class.php1^rdbms/Column.class.phpe%ordbms/ConnectionManager.class.phprdbms/ConnectionNotRegisteredException.class.phpQ+rdbms/Criteria.class.phpf#|rdbms/criterion/BetweenExpression.class.phprdbms/criterion/CountProjection.class.phpkrdbms/criterion/Criterion.class.php"|rdbms/criterion/LogicalExpression.class.phprdbms/criterion/NegationExpression.class.phphNrdbms/criterion/Projection.class.phprdbms/criterion/ProjectionList.class.phpv rdbms/criterion/Projections.class.phprdbms/criterion/Property.class.phprdbms/criterion/Restrictions.class.phpXrdbms/criterion/SimpleExpression.class.php Prdbms/criterion/SimpleProjection.class.php!rdbms/DataSet.class.phpA, rdbms/DBAdapter.class.phpLrdbms/DBConnection.class.phpvQrdbms/DBConstraint.class.php:lrdbms/DBEvent.class.phpnrdbms/DBForeignKeyConstraint.class.phprrdbms/DBIndex.class.phpjxrdbms/DBObserver.class.phpK}rdbms/DBTable.class.phprdbms/DBTableAttribute.class.phprdbms/DriverManager.class.phprdbms/DriverNotSupportedException.class.phpMrdbms/DSN.class.phpfrdbms/FieldType.class.phpSKrdbms/finder/Finder.class.phprdbms/finder/FinderAdapter.class.phprdbms/finder/FinderException.class.php\rdbms/finder/FinderMethod.class.phpyrdbms/finder/NoSuchEntityException.class.phpcrdbms/finder/package-info.xp rdbms/ibase/InterBaseConnection.class.php/rdbms/ibase/InterBaseDialect.class.php *$rdbms/ibase/InterBaseResultSet.class.php/rdbms/ibase/package-info.xp7rdbms/join/Fetchmode.class.php|9rdbms/join/JoinExtractable.class.php7=rdbms/join/JoinIterator.class.php Ardbms/join/JoinPart.class.phpLrdbms/join/JoinProcessor.class.php@_rdbms/join/JoinRelation.class.phpordbms/join/JoinTable.class.phpvrdbms/join/JoinTableAttribute.class.php{rdbms/mssql/MsSQLConnection.class.php&>rdbms/mssql/MsSQLDBAdapter.class.php.drdbms/mssql/MsSQLDialect.class.php rdbms/mssql/MsSQLResultSet.class.php rdbms/mssql/package-info.xprdbms/mysql/MySQLConnection.class.phprdbms/mysql/MySQLDBAdapter.class.php0rdbms/mysql/MysqlDialect.class.php 0)rdbms/mysql/MySQLResultSet.class.php 4rdbms/mysql/package-info.xp@rdbms/package-info.xp JBrdbms/Peer.class.php&Prdbms/pgsql/package-info.xpvrdbms/pgsql/PostgreSQLConnection.class.phpxrdbms/pgsql/PostgreSQLDBAdapter.class.phpnrdbms/pgsql/PostgreSQLDialect.class.php ardbms/pgsql/PostgreSQLResultSet.class.phpV "rdbms/query/DeleteQuery.class.phpxrdbms/query/Query.class.php Drdbms/query/QueryExecutable.class.phpW&rdbms/query/SelectQuery.class.php3 }rdbms/query/SelectQueryExecutable.class.phprdbms/query/SetOperation.class.phpmPrdbms/query/UpdateQuery.class.php3rdbms/Record.class.phprdbms/ResultIterator.class.phprdbms/ResultSet.class.phpT rdbms/SQLConnectException.class.phpqrdbms/SQLConnectionClosedException.class.php>rdbms/SQLDeadlockException.class.phprdbms/SQLDialect.class.phpxrdbms/SQLException.class.php7rdbms/SQLExpression.class.php|8rdbms/SQLFragment.class.phpe;rdbms/SQLFunction.class.php9=rdbms/SQLFunctions.class.php}NErdbms/sqlite/package-info.xprdbms/sqlite/SQLiteConnection.class.phpQrdbms/sqlite/SQLiteDBAdapter.class.phpdrdbms/sqlite/SQLiteDialect.class.php |rdbms/sqlite/SQLiteResultSet.class.phprdbms/SQLRenderable.class.php9rdbms/sqlsrv/package-info.xp rdbms/sqlsrv/SqlSrvConnection.class.phprdbms/sqlsrv/SqlSrvDialect.class.php rdbms/sqlsrv/SqlSrvResultSet.class.php rdbms/SQLStateException.class.phpQ'rdbms/SQLStatementFailedException.class.phpVxrdbms/Statement.class.phprdbms/StatementFormatter.class.phpQ%rdbms/sybase/package-info.xp/<rdbms/sybase/SybaseConnection.class.php>rdbms/sybase/SybaseDBAdapter.class.php.Vrdbms/sybase/SybaseDialect.class.php Grdbms/sybase/SybaseIOObserver.class.php}rdbms/sybase/SybaseResultSet.class.phpdrdbms/sybase/SybaseShowplanObserver.class.php Mrdbms/Transaction.class.php<rdbms/util/DBConstraintXmlGenerator.class.phpx Xrdbms/util/DBXmlGenerator.class.phprdbms/util/DBXMLNamingContext.class.php [rdbms/util/DBXMLNamingStrategy.class.phperdbms/util/DBXMLNamingStrategyDefault.class.phpXIscriptlet/Cookie.class.php7scriptlet/ErrorDocument.class.php scriptlet/HttpScriptlet.class.php8scriptlet/HttpScriptletException.class.php<>scriptlet/HttpScriptletRequest.class.php2!Gscriptlet/HttpScriptletResponse.class.phpDSescriptlet/HttpScriptletURL.class.phpescriptlet/HttpSession.class.phpscriptlet/HttpSessionInvalidException.class.phpscriptlet/LocaleNegotiator.class.php$mscriptlet/package-info.xp scriptlet/rpc/AbstractRpcMessage.class.phpscriptlet/rpc/AbstractRpcRequest.class.php7scriptlet/rpc/AbstractRpcResponse.class.php*scriptlet/rpc/AbstractRpcRouter.class.phpscriptlet/rpc/GenericRpcRequest.class.phpscriptlet/rpc/GenericRpcResponse.class.phpyscriptlet/rpc/RpcFault.class.phpy'scriptlet/rpc/RpcFaultException.class.phpZscriptlet/rpc/transport/AbstractRpcTransport.class.phpscriptlet/xml/OutputDocument.class.phpscriptlet/xml/portlet/AbstractPortlet.class.php< scriptlet/xml/portlet/Portlet.class.phpscriptlet/xml/portlet/PortletContainer.class.phpRscriptlet/xml/portlet/RunData.class.phpY !scriptlet/xml/workflow/AbstractAuthenticatedState.class.phpAe"scriptlet/xml/workflow/AbstractState.class.php($scriptlet/xml/workflow/AbstractXMLScriptlet.class.phpaMscriptlet/xml/workflow/casters/ParamCaster.class.phpEdscriptlet/xml/workflow/casters/ToBoolean.class.phpescriptlet/xml/workflow/casters/ToDate.class.phpUiscriptlet/xml/workflow/casters/ToEmailAddress.class.phpZ nscriptlet/xml/workflow/casters/ToFileData.class.phpzqscriptlet/xml/workflow/casters/ToFloat.class.phpGtscriptlet/xml/workflow/casters/ToInteger.class.phpdwscriptlet/xml/workflow/casters/ToTrimmedString.class.phpzzscriptlet/xml/workflow/casters/ToURL.class.php~scriptlet/xml/workflow/checkers/DateChecker.class.phpĀscriptlet/xml/workflow/checkers/DateRangeChecker.class.phpm scriptlet/xml/workflow/checkers/FileUploadPrechecker.class.phpPscriptlet/xml/workflow/checkers/IntegerRangeChecker.class.php ^scriptlet/xml/workflow/checkers/LengthChecker.class.phpiscriptlet/xml/workflow/checkers/NumberRangeChecker.class.php)scriptlet/xml/workflow/checkers/NumericChecker.class.phpscriptlet/xml/workflow/checkers/OptionChecker.class.phpݢscriptlet/xml/workflow/checkers/ParamChecker.class.phpscriptlet/xml/workflow/checkers/RegexpChecker.class.php;scriptlet/xml/workflow/checkers/WellformedXMLChecker.class.phpscriptlet/xml/workflow/checkers/WordCountChecker.class.phpscriptlet/xml/workflow/Context.class.phpeqscriptlet/xml/workflow/FileData.class.phprֻscriptlet/xml/workflow/generator/common.inc.xslHscriptlet/xml/workflow/generator/handler.xslscriptlet/xml/workflow/generator/wrapper.dtd[scriptlet/xml/workflow/generator/wrapper.xsdG scriptlet/xml/workflow/generator/wrapper.xsl"Dscriptlet/xml/workflow/Handler.class.phpR scriptlet/xml/workflow/IFormresultAggregate.class.phpf&scriptlet/xml/workflow/WorkflowScriptletRequest.class.php0(scriptlet/xml/workflow/Wrapper.class.php'O-scriptlet/xml/XMLScriptlet.class.phpTscriptlet/xml/XMLScriptletRequest.class.php9dtscriptlet/xml/XMLScriptletResponse.class.php%scriptlet/xml/XMLScriptletURL.class.phpCXxml/CData.class.phpxml/dom/Document.class.phpK\xml/DomXSLProcessor.class.phpj0xml/IXSLProcessor.class.php xml/meta/Marshaller.class.phpxml/meta/Unmarshaller.class.php"xml/Node.class.php#9xml/package-info.xpOq]xml/parser/FileInputSource.class.phpfcxml/parser/InputSource.class.php&hxml/parser/ParserCallback.class.php1 jxml/parser/StreamInputSource.class.phpbxml/rdf/RDFNewsFeed.class.phpT,[xml/Stylesheet.class.phpO xml/TransformerException.class.phpxml/Tree.class.phpxml/XML.class.phpfxml/XMLFormatException.class.phpxml/XPath.class.php xml/XPathException.class.phpFxml/XSLCallback.class.phpv xml/xslt/XSLDateCallback.class.php= xml/xslt/XSLStringCallback.class.phpLremote/beans/Bean.class.phpremote/beans/BeanInterface.class.phpremote/beans/HomeInterface.class.phpremote/beans/RemoteInterface.class.php*oremote/ClassReference.class.php/remote/ExceptionReference.class.phpremote/HandlerFactory.class.php8d!remote/HandlerInstancePool.class.php (remote/InvocationException.class.php2remote/mappings/java/util/GregorianCalendarMapping.class.php3remote/mappings/java/util/ZoneInfoMapping.class.php Fremote/NameNotFoundException.class.phpjrTremote/package-info.xp=Uremote/protocol/ArrayListMapping.class.php^remote/protocol/ByteArrayMapping.class.phperemote/protocol/ByteCountedString.class.php; jremote/protocol/ByteMapping.class.php~uremote/protocol/DateMapping.class.phpu\{remote/protocol/DoubleMapping.class.php]рremote/protocol/EnumMapping.class.php.remote/protocol/ExceptionMapping.class.php# Lremote/protocol/FloatMapping.class.phporemote/protocol/HashmapMapping.class.phpiremote/protocol/IntegerMapping.class.php\remote/protocol/LongMapping.class.php~remote/protocol/ProtocolHandler.class.phpjremote/protocol/RemoteInterfaceMapping.class.php remote/protocol/SerializedData.class.phpLremote/protocol/Serializer.class.php1[remote/protocol/SerializerMapping.class.phpDremote/protocol/ShortMapping.class.php2remote/protocol/StackTraceElementMapping.class.phpremote/protocol/UnknownProtocolException.class.phpjremote/protocol/XpProtocolConstants.class.phpremote/protocol/XpProtocolHandler.class.php(remote/reflect/BeanDescription.class.phpo9remote/reflect/ClassWrapper.class.phpIAremote/reflect/DescriptionList.class.phpWFremote/reflect/InterfaceDescription.class.php+Jremote/reflect/MethodDescription.class.phpl+Qremote/reflect/TransactionTypeDescription.class.php/aremote/Remote.class.phpK gremote/RemoteException.class.phpSuremote/RemoteInvocationHandler.class.phpdvremote/RemoteStackTraceElement.class.php>W{remote/server/container/BeanContainer.class.php}remote/server/container/BeanInjector.class.php^remote/server/container/StatelessSessionBeanContainer.class.php{ remote/server/ContainerInvocationHandler.class.phpremote/server/ContainerManager.class.phpXremote/server/deploy/Deployable.class.phpHremote/server/deploy/Deployer.class.php /remote/server/deploy/DeployException.class.phpRHremote/server/deploy/Deployment.class.php remote/server/deploy/IncompleteDeployment.class.phpremote/server/deploy/scan/DeploymentScanner.class.php! remote/server/deploy/scan/FileSystemScanner.class.php .remote/server/deploy/scan/SharedMemoryScanner.class.phpremote/server/EascProtocol.class.phpQremote/server/InstancePool.class.php{remote/server/message/EascCallMessage.class.phptjremote/server/message/EascExceptionMessage.class.phpremote/server/message/EascInitMessage.class.phpremote/server/message/EascLookupMessage.class.phpP,remote/server/message/EascMessage.class.php_|remote/server/message/EascMessageFactory.class.php5remote/server/message/EascValueMessage.class.phpremote/server/naming/NamingDirectory.class.phpremote/server/RemoteObjectMap.class.php|remote/server/ScannerThread.class.php> remote/server/ServerHandler.class.phpKremote/server/StatelessSessionBeanContainerInvocationHandler.class.php/remote/UnknownRemoteObject.class.phpremote/UserTransaction.class.phpLtext/Collator.class.php`!text/CSVGenerator.class.phpC'text/doclet/AnnotatedDoc.class.phpDS7text/doclet/AnnotationDoc.class.php =text/doclet/ClassDoc.class.phpE?text/doclet/ClassIterator.class.phpStext/doclet/Doc.class.phpi [text/doclet/Doclet.class.phpM-htext/doclet/FieldDoc.class.phpzptext/doclet/markup/CodeProcessor.class.phptutext/doclet/markup/CopyProcessor.class.phptext/doclet/markup/DefaultProcessor.class.php text/doclet/markup/DelegatingProcessor.class.php\\text/doclet/markup/MarkupBuilder.class.phptext/doclet/markup/MarkupProcessor.class.phptext/doclet/MethodDoc.class.phptext/doclet/ModelTag.class.php3text/doclet/ModelTaglet.class.php1text/doclet/PackageDoc.class.php´text/doclet/ParamTag.class.phptext/doclet/ParamTaglet.class.phpHPtext/doclet/ReturnTag.class.php)text/doclet/ReturnTaglet.class.php6text/doclet/RootDoc.class.php~Otext/doclet/SeeTag.class.phputext/doclet/SeeTaglet.class.php#(text/doclet/SimpleTaglet.class.phpKtext/doclet/Tag.class.phpxtext/doclet/Taglet.class.php H$text/doclet/TagletManager.class.php Q&text/doclet/TestTag.class.phpp/text/doclet/TestTaglet.class.php2text/doclet/ThrowsTag.class.phpL4text/doclet/ThrowsTaglet.class.phpa!7text/encode/Base57.class.php;text/encode/Base64.class.phpAtext/encode/CvsPassword.class.phpDtext/encode/QuotedPrintable.class.phpLtext/encode/UTF7.class.phpTtext/encode/UTF8.class.phpWtext/encode/UUCode.class.phpZtext/format/ArrayFormat.class.phptctext/format/BinaryFormat.class.phpftext/format/ChoiceFormat.class.phpjtext/format/DateFormat.class.phpntext/format/HashFormat.class.php$ttext/format/IFormat.class.phpqytext/format/MessageFormat.class.php0text/format/MoneyFormat.class.phptext/format/NumberFormat.class.phptext/format/PrintfFormat.class.phptext/parser/CSVParser.class.phptext/parser/DaemonMailParser.class.phpvtext/parser/DaemonMailParserAutoresponderException.class.php85text/parser/DaemonMailParserException.class.php18text/parser/DaemonMessage.class.php}:text/parser/DateParser.class.phpMBtext/parser/generic/AbstractLexer.class.php8Gtext/parser/generic/AbstractParser.class.phpItext/parser/generic/ParseException.class.php5Xtext/parser/generic/ParserMessage.class.phpYtext/parser/InternetAddressParser.class.php, y]text/parser/VFormatParser.class.phpQftext/PHPParser.class.php~text/PHPSyntaxHighlighter.class.php*text/PHPTokenizer.class.phpy text/regex/MatchResult.class.phpDtext/regex/package-info.xp text/regex/Pattern.class.phptext/spelling/SpellChecker.class.php;text/StreamTokenizer.class.php text/String.class.php< text/StringTokenizer.class.phpv; text/StringUtil.class.phpfD text/Tokenizer.class.php 8L text/util/RandomCodeGenerator.class.php?U text/util/RandomPasswordGenerator.class.phpFZ unittest/AssertionFailedError.class.php0#c unittest/package-info.xpSi unittest/PrerequisitesNotMetError.class.phpOn unittest/TestCase.class.phps unittest/TestFailure.class.phps݋ unittest/TestListener.class.phpP unittest/TestOutcome.class.phpe unittest/TestResult.class.php+ unittest/TestSkipped.class.phpx$ unittest/TestSuccess.class.php unittest/TestSuite.class.phpV/ unittest/web/Field.class.php unittest/web/Fields.class.phpt unittest/web/Form.class.phpL S unittest/web/InputField.class.php1 unittest/web/package-info.xp unittest/web/SelectField.class.php" unittest/web/TextAreaField.class.php unittest/web/WebTestCase.class.php+!webservices/json/IJsonDecoder.class.phpQ.!webservices/json/JsonDecoder.class.phpQ+0!webservices/json/JsonException.class.php3+\!webservices/json/JsonFactory.class.php^]!webservices/json/rpc/JsonClient.class.phpP_!webservices/json/rpc/JsonMessage.class.php Og!webservices/json/rpc/JsonRequestMessage.class.php)t!webservices/json/rpc/JsonResponseMessage.class.php#z!webservices/json/rpc/JsonRpcRequest.class.php!webservices/json/rpc/JsonRpcResponse.class.php!webservices/json/rpc/JsonRpcRouter.class.php]݇!webservices/json/rpc/transport/JsonRpcHttpTransport.class.php0 :!webservices/soap/CommonSoapFault.class.phpj!webservices/soap/interop/Round2BaseClient.class.phpD!webservices/soap/native/NativeSoapClient.class.phpʵ!webservices/soap/Parameter.class.php!webservices/soap/rpc/SoapRpcRequest.class.phpQ`!webservices/soap/rpc/SoapRpcResponse.class.php5!webservices/soap/rpc/SoapRpcRouter.class.php !webservices/soap/SoapDriver.class.phpg!webservices/soap/SOAPFaultException.class.phpC!webservices/soap/transport/SOAPHTTPTransport.class.php%!webservices/soap/types/SOAPBase64Binary.class.php"webservices/soap/types/SOAPDateTime.class.php"webservices/soap/types/SOAPDecimal.class.phpX"webservices/soap/types/SOAPDouble.class.php,."webservices/soap/types/SOAPHashMap.class.phpZ "webservices/soap/types/SOAPHexBinary.class.php$"webservices/soap/types/SOAPLong.class.php*"webservices/soap/types/SoapType.class.php K."webservices/soap/types/SOAPVector.class.php'U2"webservices/soap/xp/XPSoapClient.class.php|6"webservices/soap/xp/XPSoapHeader.class.phpF"webservices/soap/xp/XPSoapHeaderElement.class.php|H"webservices/soap/xp/XPSoapMapping.class.phpeYX"webservices/soap/xp/XPSoapMessage.class.phpUM^"webservices/soap/xp/XPSoapNode.class.php"webservices/uddi/Business.class.php"webservices/uddi/BusinessList.class.php&"webservices/uddi/FindBusinessesCommand.class.phpI "webservices/uddi/InquiryCommand.class.php."webservices/uddi/PublishCommand.class.php.>"webservices/uddi/UDDICommand.class.phpl"webservices/uddi/UDDIConstants.class.php1"webservices/uddi/UDDIServer.class.phpC,"webservices/wddx/transport/WddxHttpTransport.class.php> o#webservices/wddx/WddxClient.class.php8#webservices/wddx/WddxFaultException.class.php#webservices/wddx/WddxMessage.class.php#webservices/xmlrpc/rpc/XmlRpcRequest.class.php,#webservices/xmlrpc/rpc/XmlRpcResponse.class.php4/#webservices/xmlrpc/rpc/XmlRpcRouter.class.php"3#webservices/xmlrpc/transport/XmlRpcHttpTransport.class.php ;#webservices/xmlrpc/XmlRpcClient.class.php H#webservices/xmlrpc/XmlRpcDecoder.class.phpt R#webservices/xmlrpc/XmlRpcEncoder.class.php`#webservices/xmlrpc/XmlRpcFault.class.php|r#webservices/xmlrpc/XmlRpcFaultException.class.php3w#webservices/xmlrpc/XmlRpcMessage.class.phpr{#webservices/xmlrpc/XmlRpcRequestMessage.class.phpR &#webservices/xmlrpc/XmlRpcResponseMessage.class.phpI x#img/chart/BarChart.class.php, #img/chart/Chart.class.php#img/chart/LineChart.class.phpe #img/chart/PieChart.class.php6#img/chart/renderer/GraphRenderer.class.php#img/chart/renderer/ImageRenderer.class.phpO#img/chart/Series.class.php!$img/Color.class.phpM$$img/convert/GrayscaleConverter.class.php)$img/convert/ImageConverter.class.phpw2$img/convert/MatchingPaletteConverter.class.php{4$img/convert/PaletteConverter.class.php9$img/Drawable.class.php>$img/filter/ConvolveFilter.class.php ?$img/filter/ImageFilter.class.php_K$img/filter/Kernel.class.phpgM$img/filter/SharpenFilter.class.phpkT$img/fonts/BitmapFont.class.phpy\$img/fonts/TrueTypeFont.class.php_$img/graph/Graph.class.phpd$img/graph/PieChart.class.php g$img/graph/PieSlice.class.phpp$img/Image.class.phpr9Hv$img/ImagingException.class.php $img/ImgBrush.class.phpJİ$img/ImgStyle.class.php$img/io/GD2StreamReader.class.phpA$img/io/GD2StreamWriter.class.php$img/io/GDStreamReader.class.php?Ž$img/io/GDStreamWriter.class.php%$img/io/GifStreamReader.class.phpE)$img/io/GifStreamWriter.class.php n$img/io/ImageReader.class.php$img/io/ImageWriter.class.phpI$img/io/JpegStreamReader.class.phpG%$img/io/JpegStreamWriter.class.phpZl$img/io/PngStreamReader.class.phpE$img/io/PngStreamWriter.class.php& $img/io/StreamReader.class.php1$img/io/StreamWriter.class.php#$img/io/WBmpStreamReader.class.phpK $img/io/WBmpStreamWriter.class.phpjU$img/io/XbmStreamReader.class.phpE$img/io/XbmStreamWriter.class.phpe$img/shapes/Arc.class.phpi$img/shapes/Arc3D.class.phpiP%img/shapes/Line.class.php%img/shapes/Polygon.class.phpv=%img/shapes/Rectangle.class.php%img/shapes/Text.class.phpk%img/util/ExifData.class.phpC%img/util/ImageInfo.class.phpc%img/util/IptcData.class.phpd0t%security/auth/Authenticator.class.phpQ%security/auth/AuthenticatorException.class.php9R%security/auth/HtpasswdAuthenticator.class.php%security/auth/LdapAuthenticator.class.php)%security/auth/PropertyAuthenticator.class.phpY?%security/cert/Certificate.class.php %security/cert/CertificateException.class.phpv%security/cert/CSR.class.php .%security/cert/X509Certificate.class.php"L%security/checksum/Checksum.class.php~n%security/checksum/CRC16.class.php%security/checksum/CRC32.class.phpx%security/checksum/HMAC_MD5.class.php]%security/checksum/MD5.class.php'l%security/checksum/SHA1.class.php2%security/crypto/CryptoException.class.phpr&security/crypto/CryptoKey.class.php7&security/crypto/PrivateKey.class.php &security/crypto/PublicKey.class.php w&security/crypto/UnixCrypt.class.php &&security/KeyPair.class.php /&security/OpenSslUtil.class.php9&security/password/Algorithm.class.phpo<&security/password/PasswordStrength.class.phpR>&security/password/StandardAlgorithm.class.phpq@F&security/Permission.class.phpnX&security/Policy.class.phpA^&security/PolicyException.class.php-`x&security/Principal.class.php(y&security/sasl/DigestChallenge.class.php"&security/sasl/DigestResponse.class.php0d&security/SecurityException.class.phpA&gui/GuiException.class.phpռ&gui/WidgetNotFoundException.class.php8&VERSION& * $a= new Archive(new File('soap.xar')); * $a->open(ARCHIVE_CREATE); * $a->addFile( * 'webservices/soap/SOAPMessage.class.php' * new File($path, 'xml/soap/SOAPMessage.class.php') * ); * $a->create(); * * * Usage example (Extracting): * * $a= new Archive(new File('soap.xar')); * $bytes= $a->extract('webservices/soap/SOAPMessage.class.php'); * * * @test xp://net.xp_framework.unittest.archive.ArchiveTest * @purpose Provide archiving * @see http://java.sun.com/j2se/1.4/docs/api/java/util/jar/package-summary.html */ class Archive extends Object { public $file = NULL, $version = 2; public $_index = array(); /** * Constructor * * @param io.File file */ public function __construct($file) { $this->file= $file; } /** * Get URI * * @return string uri */ public function getURI() { return $this->file->getURI(); } /** * Add a file * * @param io.File file * @param string id the id under which this entry will be located * @return bool success * @deprecated Use addFile() instead */ public function add($file, $id) { $file->open(FILE_MODE_READ); $data= $file->read($file->size()); $file->close(); $this->_index[$id]= array(strlen($data), -1, $data); return TRUE; } /** * Add a file by its bytes * * @param string id the id under which this entry will be located * @param string path * @param string filename * @param string bytes * @deprecated Use addBytes() instead */ public function addFileBytes($id, $path, $filename, $bytes) { $this->_index[$id]= array(strlen($bytes), -1, $bytes); } /** * Add a file by its bytes * * @param string id the id under which this entry will be located * @param string bytes */ public function addBytes($id, $bytes) { $this->_index[$id]= array(strlen($bytes), -1, $bytes); } /** * Add a file * * @param string id the id under which this entry will be located * @param io.File file */ public function addFile($id, $file) { $file->open(FILE_MODE_READ); $bytes= $file->read($file->size()); $file->close(); $this->_index[$id]= array(strlen($bytes), -1, $bytes); } /** * Create CCA archive * * @return bool success */ public function create() { $this->file->truncate(); $this->file->write(pack( 'a3c1V1a248', 'CCA', $this->version, sizeof(array_keys($this->_index)), "\0" // Reserved for future use )); // Write index $offset= 0; foreach (array_keys($this->_index) as $id) { $this->file->write(pack( 'a240V1V1a8', $id, $this->_index[$id][0], $offset, "\0" // Reserved for future use )); $offset+= $this->_index[$id][0]; } // Write files foreach (array_keys($this->_index) as $id) { $this->file->write($this->_index[$id][2]); } $this->file->close(); return TRUE; } /** * Check whether a given element exists * * @param string id the element's id * @return bool TRUE when the element exists */ public function contains($id) { return isset($this->_index[$id]); } /** * Get entry (iterative use) * * $a= new Archive(new File('port.xar')); * $a->open(ARCHIVE_READ); * while ($id= $a->getEntry()) { * var_dump($id); * } * $a->close(); * * * @return string id or FALSE to indicate the pointer is at the end of the list */ public function getEntry() { $key= key($this->_index); next($this->_index); return $key; } /** * Rewind archive * */ public function rewind() { reset($this->_index); } /** * Extract a file's contents * * @param string id * @return string content * @throws lang.ElementNotFoundException in case the specified id does not exist */ public function extract($id) { if (!$this->contains($id)) { throw new ElementNotFoundException('Element "'.$id.'" not contained in this archive'); } // Calculate starting position $pos= ( ARCHIVE_HEADER_SIZE + sizeof(array_keys($this->_index)) * ARCHIVE_INDEX_ENTRY_SIZE + $this->_index[$id][1] ); try { $this->file->isOpen() || $this->file->open(FILE_MODE_READ); $this->file->seek($pos, SEEK_SET); $data= $this->file->read($this->_index[$id][0]); } catch (XPException $e) { throw new ElementNotFoundException('Element "'.$id.'" cannot be read: '.$e->getMessage()); } return $data; } /** * Fetches a stream to the file in the archive * * @param string id * @return io.Stream * @throws lang.ElementNotFoundException in case the specified id does not exist */ public function getStream($id) { if (!$this->contains($id)) { throw new ElementNotFoundException('Element "'.$id.'" not contained in this archive'); } // Calculate starting position $pos= ( ARCHIVE_HEADER_SIZE + sizeof(array_keys($this->_index)) * ARCHIVE_INDEX_ENTRY_SIZE + $this->_index[$id][1] ); return new EncapsedStream($this->file, $pos, $this->_index[$id][0]); } /** * Open this archive * * @param int mode default ARCHIVE_READ one of ARCHIVE_READ | ARCHIVE_CREATE * @return bool success * @throws lang.IllegalArgumentException in case an illegal mode was specified * @throws lang.FormatException in case the header is malformed */ public function open($mode) { static $unpack= array( 1 => 'a80id/a80*filename/a80*path/V1size/V1offset/a*reserved', 2 => 'a240id/V1size/V1offset/a*reserved' ); switch ($mode) { case ARCHIVE_READ: // Load $this->file->open(FILE_MODE_READ); // Read header $header= $this->file->read(ARCHIVE_HEADER_SIZE); $data= unpack('a3id/c1version/V1indexsize/a*reserved', $header); // Check header integrity if ('CCA' !== $data['id']) throw new FormatException(sprintf( 'Header malformed: "CCA" expected, have "%s"', substr($header, 0, 3) )); // Copy information $this->version= $data['version']; // Read index for ($i= 0; $i < $data['indexsize']; $i++) { $entry= unpack($unpack[$this->version], $this->file->read(ARCHIVE_INDEX_ENTRY_SIZE)); $this->_index[$entry['id']]= array($entry['size'], $entry['offset'], NULL); } return TRUE; case ARCHIVE_CREATE: // Create return $this->file->open(FILE_MODE_WRITE); } throw new IllegalArgumentException('Mode '.$mode.' not recognized'); } /** * Close this archive * * @return bool success */ public function close() { return $this->file->close(); } /** * Checks whether this archive is open * * @return bool TRUE when the archive file is open */ public function isOpen() { return $this->file->isOpen(); } /** * Returns a string representation of this object * * @return string */ public function toString() { return sprintf( '%s(version= %s, index size= %d) { %s }', $this->getClassName(), $this->version, sizeof($this->_index), xp::stringOf($this->file) ); } /** * Destructor * */ public function __destruct() { if ($this->isOpen()) $this->close(); } } ?> * $l= new ArchiveClassLoader(new Archive(new File('soap.xar'))); * try { * $class= $l->loadClass($argv[1]); * } catch (ClassNotFoundException $e) { * $e->printStackTrace(); * exit(-1); * } * * $obj= $class->newInstance(); * * * @test xp://net.xp_framework.unittest.io.ArchiveClassLoaderTest * @purpose Load classes from an archive * @see xp://lang.ClassLoader * @see xp://lang.archive.Archive * @ext tokenize */ class ArchiveClassLoader extends Object implements IClassLoader { protected $archive = NULL; /** * Constructor * * @param mixed archive either a string or a lang.archive.Archive instance */ public function __construct($archive) { $uri= $archive instanceof Archive ? $archive->getURI() : $archive; // Archive within an archive if (0 === strncmp('xar://', $uri, 6)) { $this->archive= 'xar://'.urlencode($uri).'?'; } else { $this->archive= 'xar://'.$uri.'?'; } } /** * Creates a string representation * * @return string */ public function toString() { return $this->getClassName(). '<'.$this->archive.'>'; } /** * Load class bytes * * @param string name fully qualified class name * @return string */ public function loadClassBytes($name) { return file_get_contents($this->archive.strtr($name, '.', '/').xp::CLASS_FILE_EXT); } /** * Load the class by the specified name * * @param string class fully qualified class name io.File * @return lang.XPClass * @throws lang.ClassNotFoundException in case the class can not be found * @throws lang.FormatException in case the class file is malformed */ public function loadClass($class) { return new XPClass($this->loadClass0($class)); } /** * Loads a class * * @param string class fully qualified class name * @return string class name of class loaded * @throws lang.ClassNotFoundException in case the class can not be found * @throws lang.ClassFormatException in case the class format is invalid */ public function loadClass0($class) { if (isset(xp::$registry['classloader.'.$class])) return xp::reflect($class); // Load class $package= NULL; xp::$registry['classloader.'.$class]= 'lang.archive.ArchiveClassLoader://'.substr($this->archive, 6, -1); xp::$registry['cl.level']++; $r= include($this->archive.strtr($class, '.', '/').xp::CLASS_FILE_EXT); xp::$registry['cl.level']--; if (FALSE === $r) { unset(xp::$registry['classloader.'.$class]); throw new FormatException('Cannot define class "'.$class.'"'); } // Register it $name= ($package ? strtr($package, '.', '').'' : '').substr($class, (FALSE === ($p= strrpos($class, '.')) ? 0 : $p + 1)); if (!class_exists($name, FALSE) && !interface_exists($name, FALSE)) { unset(xp::$registry['classloader.'.$class]); raise('lang.ClassFormatException', 'Class "'.$name.'" not declared in loaded file'); } xp::$registry['class.'.$name]= $class; method_exists($name, '__static') && xp::$registry['cl.inv'][]= array($name, '__static'); if (0 == xp::$registry['cl.level']) { $invocations= xp::$registry['cl.inv']; xp::$registry['cl.inv']= array(); foreach ($invocations as $inv) call_user_func($inv); } return $name; } /** * Loads a resource. * * @param string string name of resource * @return string * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResource($string) { if (FALSE !== ($r= file_get_contents($this->archive.$string))) { return $r; } return raise('lang.ElementNotFoundException', 'Could not load resource '.$string); } /** * Retrieve a stream to the resource * * @param string string name of resource * @return io.Stream * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResourceAsStream($string) { if (!file_exists($this->archive.$string)) { return raise('lang.ElementNotFoundException', 'Could not load resource '.$string); } return new File($this->archive.$string); } /** * Checks whether this loader can provide the requested class * * @param string class * @return bool */ public function providesClass($class) { return file_exists($this->archive.strtr($class, '.', '/').xp::CLASS_FILE_EXT); } /** * Checks whether this loader can provide the requested resource * * @param string filename * @return bool */ public function providesResource($filename) { return file_exists($this->archive.$filename); } /** * Checks whether this loader can provide the requested package * * @param string package * @return bool */ public function providesPackage($package) { $acquired= xarloader::acquire(urldecode(substr($this->archive, 6, -1))); $cmps= strtr($package, '.', '/').'/'; $cmpl= strlen($cmps); foreach (array_keys($acquired['index']) as $e) { if (strncmp($cmps, $e, $cmpl) === 0) return TRUE; } return FALSE; } /** * Fetch instance of classloader by the path to the archive * * @param string path * @param bool expand default TRUE whether to expand the path using realpath * @return lang.archive.ArchiveClassLoader */ public static function instanceFor($path, $expand= TRUE) { static $pool= array(); $path= $expand && 0 !== strncmp('xar%3A%2F%2F', $path, 12) ? realpath($path) : $path; if (!isset($pool[$path])) { $pool[$path]= new self($path); } return $pool[$path]; } /** * Get package contents * * @param string package * @return string[] filenames */ public function packageContents($package) { $contents= array(); $acquired= xarloader::acquire(urldecode(substr($this->archive, 6, -1))); $cmps= strtr($package, '.', '/'); $cmpl= strlen($cmps); foreach (array_keys($acquired['index']) as $e) { if (strncmp($cmps, $e, $cmpl) != 0) continue; $entry= 0 != $cmpl ? substr($e, $cmpl+ 1) : $e; // Check to see if we're getting something in a subpackage. Imagine the // following structure: // // archive.xar // - tests/ClassOne.class.php // - tests/classes/RecursionTest.class.php // - tests/classes/ng/NextGenerationRecursionTest.class.php // // When this method is invoked with "tests" as name, "ClassOne.class.php" // and "classes/" should be returned (but neither any of the subdirectories // nor their contents) if (FALSE !== ($p= strpos($entry, '/'))) { $entry= substr($entry, 0, $p); if (strstr($entry, '/')) continue; $entry.= '/'; } $contents[$entry]= NULL; } return array_keys($contents); } } ?> file= $filename; } /** * Get URI * * @return string uri */ public function getURI() { return $this->file; } /** * Check whether a given element exists * * @param string id the element's id * @return bool TRUE when the element exists */ public function contains($id) { return isset($this->_index[$id]); } /** * Get entry (iterative use) * * $a= new Archive(new File('port.xar')); * $a->open(ARCHIVE_READ); * while ($id= $a->getEntry()) { * var_dump($id); * } * $a->close(); * * * @return string id or FALSE to indicate the pointer is at the end of the list */ public function getEntry() { $key= key($this->_index); next($this->_index); return $key; } /** * Rewind archive * */ public function rewind() { reset($this->_index); } /** * Extract a file's contents * * @param string id * @return string content */ public function extract($id) { if (!$this->contains($id)) { return FALSE; } // Calculate starting position $pos= ( ARCHIVE_HEADER_SIZE + sizeof(array_keys($this->_index)) * ARCHIVE_INDEX_ENTRY_SIZE + $this->_index[$id][3] ); fseek($this->_hdl, $pos, SEEK_SET); $data= fread($this->_hdl, $this->_index[$id][2]); return $data; } /** * Fetches a stream to the file in the archive * * @param string id * @return io.Stream */ public function getStream($id) { if (!$this->contains($id)) { return FALSE; } // Calculate starting position $pos= ( ARCHIVE_HEADER_SIZE + sizeof(array_keys($this->_index)) * ARCHIVE_INDEX_ENTRY_SIZE + $this->_index[$id][3] ); // Load the class only at runtime to keep hardcoded dependencies to // external (ie. != "lang.") classes at a minimum to not affect // core startup time. $class= XPClass::forName('io.EncapsedStream'); $file= XPClass::forName('io.File')->newInstance($this->file); $file->open(FILE_MODE_READ); $s= $class->newInstance($file, $pos, $this->_index[$id][2]); return $s; } /** * Open this archive. * * Note: this light-weight implementation of an ArchiveReader * only supports opening the archive in ARCHIVE_READ mode. * * @param int mode default ARCHIVE_READ one of ARCHIVE_READ | ARCHIVE_CREATE * @return bool success */ public function open($mode) { switch ($mode) { case ARCHIVE_READ: // Load $this->_hdl= fopen($this->file, 'rb'); $header= fread($this->_hdl, ARCHIVE_HEADER_SIZE); $data= unpack('a3id/c1version/i1indexsize/a*reserved', $header); // Check header integrity if ('CCA' !== $data['id']) throw(new FormatException(sprintf( 'Header malformed: "CCA" expected, have "%s"', substr($header, 0, 3) ))); // Copy information $this->version = $data['version']; // Read index for ($i= 0; $i < $data['indexsize']; $i++) { $entry= unpack( 'a80id/a80filename/a80path/i1size/i1offset/a*reserved', fread($this->_hdl, ARCHIVE_INDEX_ENTRY_SIZE) ); $this->_index[$entry['id']]= array( $entry['filename'], $entry['path'], $entry['size'], $entry['offset'], NULL // Will not be read, use extract() ); } return TRUE; } return FALSE; } /** * Close this archive * * @return bool success */ public function close() { return fclose($this->_hdl); } /** * Checks whether this archive is open * * @return bool TRUE when the archive file is open */ public function isOpen() { return is_resource($this->_hdl); } /** * Returns a string representation of this object * * @return string */ public function toString() { return sprintf( '%s(version= %s, index size= %d) { %s }', $this->getClassName(), $this->version, sizeof($this->_index), xp::stringOf($this->_hdl) ); } } ?> cause= $cause; } /** * Set cause * * @param lang.Throwable cause */ public function setCause($cause) { $this->cause= $cause; } /** * Get cause * * @return lang.Throwable */ public function getCause() { return $this->cause; } /** * Return string representation of this exception * * @return string */ public function toString() { $s= $this->compoundMessage()."\n"; $tt= $this->getStackTrace(); $t= sizeof($tt); for ($i= 0; $i < $t; $i++) { $s.= $tt[$i]->toString(); } if (!$this->cause) return $s; $loop= $this->cause; while ($loop) { // String of cause $s.= 'Caused by '.$loop->compoundMessage()."\n"; // Find common stack trace elements $lt= $loop->getStackTrace(); for ($ct= $cc= sizeof($lt)- 1, $t= sizeof($tt)- 1; $ct > 0, $t > 0; $cc--, $t--) { if (!$lt[$cc]->equals($tt[$t])) break; } // Output uncommon elements only and one line how many common elements exist! for ($i= 0; $i < $cc; $i++) { $s.= xp::stringOf($lt[$i]); } if ($cc != $ct) $s.= ' ... '.($ct - $cc + 1)." more\n"; $loop= $loop instanceof ChainedException ? $loop->cause : NULL; } return $s; } } ?> *
  • Class file does not declare any classes
  • *
  • Class file does not declare class by file name
  • * * * @see xp://lang.ClassLoader#loadClass * @purpose Exception */ class ClassFormatException extends XPException { } ?> loadClass(). * * Given the following code * * $class= ClassLoader::getDefault()->loadClass($name); * * ...and the following include_path setting: *
       *   ".:/usr/local/lib/xp/xp-rt-5.4.0.xar:/home/classes/"
       * 
    * ...the classloader will ask the class loader delegates: *
       * - FileSystemClassLoader(.)
       * - ArchiveClassLoader(/usr/local/lib/xp/xp-rt-5.4.0.xar)
       * - FileSystemClassLoader(/home/classes/)
       * 
    * ...in the stated order. The first delegate to provide the class * will be asked to load it. In case none of the delegates are able * to provide the class, a ClassNotFoundException will be thrown. * * @test xp://net.xp_framework.unittest.reflection.ClassLoaderTest * @test xp://net.xp_framework.unittest.reflection.ResourcesTest * @test xp://net.xp_framework.unittest.reflection.PackageTest * @test xp://net.xp_framework.unittest.reflection.RuntimeClassDefinitionTest * @test xp://net.xp_framework.unittest.reflection.FullyQualifiedTest * @see xp://lang.XPClass#forName * @see xp://lang.reflect.Package#loadClass * @purpose Class loading */ final class ClassLoader extends Object implements IClassLoader { protected static $delegates = array(); static function __static() { xp::$registry['loader']= new self(); // Scan include-path, setting up classloaders for each element foreach (xp::$registry['classpath'] as $element) { $resolved= realpath($element); if (is_dir($resolved)) { self::registerLoader(FileSystemClassLoader::instanceFor($resolved, FALSE)); } else if (is_file($resolved)) { self::registerLoader(ArchiveClassLoader::instanceFor($resolved, FALSE)); } else { xp::error('[bootstrap] Classpath element ['.$element.'] not found'); } } } /** * Retrieve the default class loader * * @return lang.ClassLoader */ public static function getDefault() { return xp::$registry['loader']; } /** * Register a class loader from a path * * @param string element * @param bool before default FALSE whether to register this as the first loader * @return lang.IClassLoader the registered loader * @throws lang.ElementNotFoundException if the path cannot be found */ public static function registerPath($element, $before= FALSE) { $resolved= realpath($element); if (is_dir($resolved)) { return self::registerLoader(FileSystemClassLoader::instanceFor($resolved, $before)); } else if (is_file($resolved)) { return self::registerLoader(ArchiveClassLoader::instanceFor($resolved, $before)); } raise('lang.ElementNotFoundException', 'Element "'.$element.'" not found'); } /** * Register a class loader as a delegate * * @param lang.IClassLoader l * @param bool before default FALSE whether to register this as the first loader * @return lang.IClassLoader the registered loader */ public static function registerLoader(IClassLoader $l, $before= FALSE) { if ($before) { self::$delegates= array_merge(array($l->hashCode() => $l), self::$delegates); } else { self::$delegates[$l->hashCode()]= $l; } return $l; } /** * Unregister a class loader as a delegate * * @param lang.IClassLoader l * @return bool TRUE if the delegate was unregistered */ public static function removeLoader(IClassLoader $l) { if (!isset(self::$delegates[$l->hashCode()])) return FALSE; unset(self::$delegates[$l->hashCode()]); return TRUE; } /** * Get class loader delegates * * @return lang.IClassLoader[] */ public static function getLoaders() { return array_values(self::$delegates); } /** * Define a class with a given name * * @param string class fully qualified class name * @param string parent either sourcecode of the class or FQCN of parent * @param string[] interfaces FQCNs of implemented interfaces * @param string bytes default "{}" inner sourcecode of class (containing {}) * @return lang.XPClass * @throws lang.FormatException in case the class cannot be defined * @throws lang.ClassNotFoundException if given parent class does not exist */ public static function defineClass($class, $parent, $interfaces, $bytes= '{}') { $name= xp::reflect($class); if (!isset(xp::$registry['classloader.'.$class])) { $super= xp::reflect($parent); // Test for existance if (!class_exists($super)) { throw new ClassNotFoundException('Parent class "'.$parent.'" does not exist.'); } if (!empty($interfaces)) { $if= array_map(array('xp', 'reflect'), $interfaces); foreach ($if as $implemented) { if (interface_exists($implemented)) continue; throw new ClassNotFoundException('Implemented interface "'.$implemented.'" does not exist.'); } } with ($dyn= DynamicClassLoader::instanceFor(__METHOD__)); { $dyn->setClassBytes($class, sprintf( 'class %s extends %s%s %s', $name, $super, $interfaces ? ' implements '.implode(', ', $if) : '', $bytes )); return $dyn->loadClass($class); } } return new XPClass($name); } /** * Define an interface with a given name * * @param string class fully qualified class name * @param string[] parents FQCNs of parent interfaces * @param string bytes default "{}" inner sourcecode of class (containing {}) * @return lang.XPClass * @throws lang.FormatException in case the class cannot be defined * @throws lang.ClassNotFoundException if given parent class does not exist */ public static function defineInterface($class, $parents, $bytes= '{}') { $name= xp::reflect($class); $if= array(); if (!isset(xp::$registry['classloader.'.$class])) { if (!empty($parents)) { $if= array_map(array('xp', 'reflect'), (array)$parents); foreach ($if as $super) { if (interface_exists($super)) continue; throw new ClassNotFoundException('Superinterface "'.$super.'" does not exist.'); } } with ($dyn= DynamicClassLoader::instanceFor(__METHOD__)); { $dyn->setClassBytes($class, sprintf( 'interface %s%s %s', $name, sizeof($if) ? ' extends '.implode(', ', $if) : '', $bytes )); return $dyn->loadClass($class); } } return new XPClass($name); } /** * Loads a class * * @param string class fully qualified class name * @return string class name of class loaded * @throws lang.ClassNotFoundException in case the class can not be found * @throws lang.ClassFormatException in case the class format is invalud */ public function loadClass0($class) { if (isset(xp::$registry['classloader.'.$class])) return xp::reflect($class); // Ask delegates foreach (self::$delegates as $delegate) { if ($delegate->providesClass($class)) return $delegate->loadClass0($class); } throw new ClassNotFoundException(sprintf( 'No classloader provides class "%s" {%s}', $class, xp::stringOf(self::getLoaders()) )); } /** * Checks whether this loader can provide the requested class * * @param string class * @return bool */ public function providesClass($class) { foreach (self::$delegates as $delegate) { if ($delegate->providesClass($class)) return TRUE; } return FALSE; } /** * Checks whether this loader can provide the requested resource * * @param string filename * @return bool */ public function providesResource($filename) { foreach (self::$delegates as $delegate) { if ($delegate->providesResource($filename)) return TRUE; } return FALSE; } /** * Checks whether this loader can provide the requested package * * @param string package * @return bool */ public function providesPackage($package) { foreach (self::$delegates as $delegate) { if ($delegate->providesPackage($package)) return TRUE; } return FALSE; } /** * Find the class by the specified name * * @param string class fully qualified class name * @return lang.IClassLoader the classloader that provides this class */ public function findClass($class) { foreach (self::$delegates as $delegate) { if ($delegate->providesClass($class)) return $delegate; } return xp::null(); } /** * Find the package by the specified name * * @param string package fully qualified package name * @return lang.IClassLoader the classloader that provides this class */ public function findPackage($package) { foreach (self::$delegates as $delegate) { if ($delegate->providesPackage($package)) return $delegate; } return xp::null(); } /** * Load the class by the specified name * * @param string class fully qualified class name * @return lang.XPClass * @throws lang.ClassNotFoundException in case the class can not be found */ public function loadClass($class) { return new XPClass($this->loadClass0($class)); } /** * Find the resource by the specified name * * @param string name resource name * @return lang.IClassLoader the classloader that provides this resource */ public function findResource($name) { foreach (self::$delegates as $delegate) { if ($delegate->providesResource($name)) return $delegate; } return xp::null(); } /** * Loads a resource. * * @param string string name of resource * @return string * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResource($string) { foreach (self::$delegates as $delegate) { if ($delegate->providesResource($string)) return $delegate->getResource($string); } raise('lang.ElementNotFoundException', sprintf( 'No classloader provides resource "%s" {%s}', $string, xp::stringOf(self::getLoaders()) )); } /** * Retrieve a stream to the resource * * @param string string name of resource * @return io.Stream * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResourceAsStream($string) { foreach (self::$delegates as $delegate) { if ($delegate->providesResource($string)) return $delegate->getResourceAsStream($string); } raise('lang.ElementNotFoundException', sprintf( 'No classloader provides resource "%s" {%s}', $string, xp::stringOf(self::getLoaders()) )); } /** * Get package contents * * @param string package * @return string[] filenames */ public function packageContents($package) { $contents= array(); foreach (self::$delegates as $delegate) { $contents= array_merge($contents, $delegate->packageContents($package)); } return array_unique($contents); } } ?> * $coll= Collection::forClass('rdbms.DBConnection'); * * $coll->add(new SybaseConnection(...)); // Works * $coll->add(new MySQLConnection(...)); // Works, too * $coll->add(Date::now()); // Fails * $coll->add(1); // Fails * * * @deprecated Use lang.types.ArrayList or the classes from util.collections * @test xp://net.xp_framework.unittest.core.CollectionTest * @purpose "Type-safe" array */ class Collection extends Object { public $class = '', $list = array(); public $_name = ''; /** * Constructor * * @param string class */ protected function __construct($class) { $this->class= $class; $this->_name= xp::reflect($class); } /** * Returns a new Collection object for a specified class * * @param string class the fully qualified class name * @return lang.Collection * @throws lang.ClassNotFoundException */ public static function forClass($class) { if (!class_exists(xp::reflect($class))) { throw(new ClassNotFoundException('Class "'.$class.'" does not exist')); } return new self($class); } /** * Returns the number of elements in this list. * * @return int */ public function size() { return sizeof($this->list); } /** * Returns the element's class name * * @return string */ public function getElementClassName() { return $this->class; } /** * Returns the element's class name * * @return lang.XPClass */ public function getElementClass() { return XPClass::forName($this->class); } /** * Tests if this list has no elements. * * @return bool */ public function isEmpty() { return empty($this->list); } /** * Adds an element to this list * * @param lang.Object element * @return lang.Object the added element * @throws lang.IllegalArgumentException */ public function add($element) { if (!is($this->_name, $element)) { throw(new IllegalArgumentException(sprintf( 'Element is not a %s (but %s)', $this->class, xp::typeOf($element) ))); } $this->list[]= $element; return $element; } /** * Adds an element to the beginning of this list * * @param lang.Object element * @return lang.Object the prepended element * @throws lang.IllegalArgumentException */ public function prepend($element) { if (!is($this->_name, $element)) { throw(new IllegalArgumentException(sprintf( 'Element is not a %s (but %s)', $this->class, xp::typeOf($element) ))); } array_unshift($this->list, $element); return $element; } /** * Adds an array of elements to this list * * @param lang.Object[] array * @throws lang.IllegalArgumentException */ public function addAll($array) { $original= $this->list; for ($i= 0, $s= sizeof($array); $i < $s; $i++) { if (!is($this->_name, $array[$i])) { $this->list= $original; // Rollback throw(new IllegalArgumentException(sprintf( 'Element %d is not a %s (but %s)', $i, $this->class, xp::typeOf($array[$i]) ))); } $this->list[]= $array[$i]; } } /** * Prepend an array of elements to this list * * @param lang.Object[] array * @throws lang.IllegalArgumentException */ public function prependAll($array) { $original= $this->list; for ($i= 0, $s= sizeof($array); $i < $s; $i++) { if (!is($this->_name, $array[$i])) { $this->list= $original; // Rollback throw(new IllegalArgumentException(sprintf( 'Element %d is not a %s (but %s)', $i, $this->class, xp::typeOf($array[$i]) ))); } array_unshift($this->list, $array[$i]); } } /** * Replaces the element at the specified position in this list with * the specified element. * * @param int index * @param lang.Object element * @return lang.Object the element previously at the specified position. */ public function set($index, $element) { $orig= $this->list[$index]; $this->list[$index]= $element; return $orig; } /** * Returns the element at the specified position in this list. * * @param int index * @return lang.Object */ public function get($index) { return @$this->list[$index]; } /** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one * from their indices). * * @param int index * @return lang.Object the element that was removed from the list */ public function remove($index) { $element= $this->list[$index]; unset($this->list[$index]); $this->list= array_values($this->list); return $element; } /** * Removes all of the elements from this list. The list will be empty * after this call returns. * */ public function clear() { $this->list= array(); } /** * Returns an array of this list's elements * * @return lang.Object[] */ public function values() { return array_values($this->list); } /** * Checks if a value exists in this array * * @param lang.Object element * @return bool */ public function contains($element) { for ($i= 0, $s= sizeof($this->list); $i < $s; $i++) { if ($this->list[$i]->equals($element)) return TRUE; } return FALSE; } /** * Searches for the first occurence of the given argument * * @param lang.Object element * @return int offset where the element was found or FALSE */ public function indexOf($element) { // Note: array_search() does NOT work for objects: // // // if (Z_TYPE_PP(value) == IS_OBJECT) { // php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong datatype for first argument"); // RETURN_FALSE; // } // for ($i= 0, $s= sizeof($this->list); $i < $s; $i++) { if ($this->list[$i]->equals($element)) return $i; } return FALSE; } /** * Searches for the last occurence of the given argument * * @param lang.Object element * @return int offset where the element was found or FALSE */ public function lastIndexOf($element) { for ($i= sizeof($this->list)- 1; $i > -1; $i--) { if ($this->list[$i]->equals($element)) return $i; } return FALSE; } /** * Creates a string representation of this object * * @return string */ public function toString() { $r= $this->getClassName().'<'.$this->class.">@{\n"; for ($i= 0, $s= sizeof($this->list); $i < $s; $i++) { $r.= ' '.$i.': '.str_replace("\n", "\n ", xp::stringOf($this->list[$i]))."\n"; } return $r.'}'; } /** * Checks if a specified object is equal to this object. * * @param lang.Object collection * @return bool */ public function equals($collection) { if ( !$collection instanceof self || $this->size() != $collection->size() ) return FALSE; // Compare element by element for ($i= 0, $s= sizeof($this->list); $i < $s; $i++) { if ($this->list[$i]->equals($collection->list[$i])) continue; return FALSE; } return TRUE; } } ?> context= $context; } /** * Register new class' bytes * * @param string fqcn * @param string bytes */ public function setClassBytes($fqcn, $bytes) { self::$bytes[$fqcn]= ''; } /** * Checks whether this loader can provide the requested class * * @param string class * @return bool */ public function providesClass($class) { return isset(self::$bytes[$class]); } /** * Checks whether this loader can provide the requested resource * * @param string filename * @return bool */ public function providesResource($filename) { return FALSE; } /** * Checks whether this loader can provide the requested package * * @param string package * @return bool */ public function providesPackage($package) { return FALSE; } /** * Load class bytes * * @param string name fully qualified class name * @return string */ public function loadClassBytes($name) { return self::$bytes[$name]; } /** * Loads a class * * @param string class fully qualified class name * @return string class name of class loaded * @throws lang.ClassNotFoundException in case the class can not be found * @throws lang.ClassFormatException in case the class format is invalud */ public function loadClass0($class) { if (isset(xp::$registry['classloader.'.$class])) return xp::reflect($class); if (!isset(self::$bytes[$class])) { throw new ClassNotFoundException('Unknown class "'.$class.'"'); } // Load class $package= NULL; xp::$registry['classloader.'.$class]= 'lang.DynamicClassLoader://'.$this->context; xp::$registry['cl.level']++; $r= include('dyn://'.$class); xp::$registry['cl.level']--; if (FALSE === $r) { unset(xp::$registry['classloader.'.$class]); throw new FormatException('Cannot define class "'.$class.'"'); } // Register it $name= ($package ? strtr($package, '.', '').'' : '').substr($class, (FALSE === ($p= strrpos($class, '.')) ? 0 : $p + 1)); if (!class_exists($name, FALSE) && !interface_exists($name, FALSE)) { unset(xp::$registry['classloader.'.$class]); raise('lang.ClassFormatException', 'Class "'.$name.'" not declared in loaded file'); } xp::$registry['class.'.$name]= $class; method_exists($name, '__static') && xp::$registry['cl.inv'][]= array($name, '__static'); if (0 == xp::$registry['cl.level']) { $invocations= xp::$registry['cl.inv']; xp::$registry['cl.inv']= array(); foreach ($invocations as $inv) call_user_func($inv); } return $name; } /** * Load the class by the specified name * * @param string class fully qualified class name io.File * @return lang.XPClass * @throws lang.ClassNotFoundException in case the class can not be found */ public function loadClass($class) { return new XPClass($this->loadClass0($class)); } /** * Fetch instance of classloader by path * * @param string path the identifier * @return lang.IClassLoader */ public static function instanceFor($path) { static $pool= array(); if (!isset($pool[$path])) { $pool[$path]= new self($path); } return $pool[$path]; } /** * Get package contents * * @param string package * @return string[] filenames */ public function packageContents($package) { return array(); } /** * Loads a resource. * * @param string filename name of resource * @return string * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResource($filename) { raise('lang.ElementNotFoundException', 'Could not load resource '.$filename); } /** * Retrieve a stream to the resource * * @param string filename name of resource * @return io.File * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResourceAsStream($filename) { raise('lang.ElementNotFoundException', 'Could not load resource '.$filename); } /** * Stream wrapper method stream_open * * @param string path * @param int mode * @param int options * @param string opened_path * @return bool */ public function stream_open($path, $mode, $options, $opened_path) { sscanf($path, 'dyn://%[^$]', $this->current); if (!isset(self::$bytes[$this->current])) { raise('lang.ElementNotFoundException', 'Could not load '.$this->current); } return TRUE; } /** * Stream wrapper method stream_read * * @param int count * @return string */ public function stream_read($count) { $bytes= substr(self::$bytes[$this->current], $this->position, $count); $this->position+= strlen($bytes); return $bytes; } /** * Stream wrapper method stream_eof * * @return bool */ public function stream_eof() { // Leave function body empty to optimize speed // See http://bugs.php.net/40047 // // return $this->position >= strlen(self::$bytes[$this->current]); } /** * Stream wrapper method stream_stat * * @return array */ public function stream_stat() { return array( 'size' => strlen(self::$bytes[$this->current]) ); } /** * Stream wrapper method stream_seek * * @param int offset * @param int whence * @return bool */ public function stream_seek($offset, $whence) { switch ($whence) { case SEEK_SET: $this->position= $offset; break; case SEEK_CUR: $this->position+= $offset; break; case SEEK_END: $this->position= strlen(self::$bytes[$this->current]); break; } return TRUE; } /** * Stream wrapper method stream_tell * * @return int offset */ public function stream_tell() { return $this->position; } /** * Stream wrapper method stream_flush * * @return bool */ public function stream_flush() { return TRUE; } /** * Stream wrapper method stream_close * * @return bool */ public function stream_close() { return TRUE; } /** * Stream wrapper method url_stat * * @param string path * @return array */ public function url_stat($path) { list($name)= sscanf($path, 'dyn://%s'); return array( 'size' => strlen(self::$bytes[$name]) ); } } ?> ordinal= $ordinal; $this->name= $name; } /** * Returns the enumeration member uniquely identified by * * @param lang.XPClass class class object * @param string name enumeration member * @return lang.Enum * @throws lang.IllegalArgumentException in case the enum member does not exist or when the given class is not an enum */ public static function valueOf(XPClass $class, $name) { if (!$class->isEnum()) { throw new IllegalArgumentException('Argument class must be lang.XPClass'); } try { $prop= $class->_reflect->getStaticPropertyValue($name); if ($prop instanceof self && $class->isInstance($prop)) return $prop; } catch (ReflectionException $e) { throw new IllegalArgumentException($e->getMessage()); } throw new IllegalArgumentException('No such member "'.$name.'" in '.$class->getName()); } /** * Returns the enumeration member uniquely identified by * * @param lang.XPClass class class object * @return lang.Enum[] * @throws lang.IllegalArgumentException in case the given class is not an enum */ public static function valuesOf(XPClass $class) { if (!$class->isEnum()) { throw new IllegalArgumentException('Argument class must be lang.XPClass'); } $r= array(); foreach ($class->_reflect->getStaticProperties() as $prop) { $prop instanceof self && $class->isInstance($prop) && $r[]= $prop; } return $r; } /** * Clone interceptor - ensures enums cannot be cloned * * @throws lang.CloneNotSupportedException */ public final function __clone() { raise('lang.CloneNotSupportedException', 'Enums cannot be cloned'); } /** * Returns the name of this enum constant, exactly as declared in its * enum declaration. * * @return string */ public function name() { return $this->name; } /** * Returns the ordinal of this enumeration constant (its position in * its enum declaration, where the initial constant is assigned an * ordinal of zero). * * @return int */ public function ordinal() { return $this->ordinal; } /** * Create a string representation of this enum * * @return string */ public function toString() { return $this->name; } /** * Returns all members for a given enum. * * @param string class * @return lang.Enum[] */ protected static function membersOf($class) { $r= array(); $c= new ReflectionClass($class); foreach ($c->getStaticProperties() as $prop) { $prop instanceof self && $c->isInstance($prop) && $r[]= $prop; } return $r; } } ?> path= rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } /** * Checks whether two class loaders are equal * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $cmp->path === $this->path; } /** * Creates a string representation * * @return string */ public function toString() { return $this->getClassName(). '<'.$this->path.'>'; } /** * Load class bytes * * @param string name fully qualified class name * @return string */ public function loadClassBytes($name) { return file_get_contents($this->path.strtr($name, '.', DIRECTORY_SEPARATOR).xp::CLASS_FILE_EXT); } /** * Checks whether this loader can provide the requested class * * @param string class * @return bool */ public function providesClass($class) { return is_file($this->path.strtr($class, '.', DIRECTORY_SEPARATOR).xp::CLASS_FILE_EXT); } /** * Checks whether this loader can provide the requested resource * * @param string filename * @return bool */ public function providesResource($filename) { return is_file($this->path.$filename); } /** * Checks whether this loader can provide the requested package * * @param string package * @return bool */ public function providesPackage($package) { return is_dir($this->path.strtr($package, '.', DIRECTORY_SEPARATOR)); } /** * Load the class by the specified name * * @param string class fully qualified class name io.File * @return lang.XPClass * @throws lang.ClassNotFoundException in case the class can not be found */ public function loadClass($class) { return new XPClass($this->loadClass0($class)); } /** * Load the class by the specified name * * @param string class fully qualified class name io.File * @return string class name * @throws lang.ClassNotFoundException in case the class can not be found * @throws lang.ClassFormatException in case the class format is invalud */ public function loadClass0($class) { if (isset(xp::$registry['classloader.'.$class])) return xp::reflect($class); // Load class $package= NULL; xp::$registry['classloader.'.$class]= 'lang.FileSystemClassLoader://'.$this->path; xp::$registry['cl.level']++; $r= include($this->path.strtr($class, '.', DIRECTORY_SEPARATOR).xp::CLASS_FILE_EXT); xp::$registry['cl.level']--; if (FALSE === $r) { unset(xp::$registry['classloader.'.$class]); throw new ClassNotFoundException('Class "'.$class.'" not found'); } // Register it $name= ($package ? strtr($package, '.', '').'' : '').substr($class, (FALSE === ($p= strrpos($class, '.')) ? 0 : $p + 1)); if (!class_exists($name, FALSE) && !interface_exists($name, FALSE)) { unset(xp::$registry['classloader.'.$class]); raise('lang.ClassFormatException', 'Class "'.$name.'" not declared in loaded file'); } xp::$registry['class.'.$name]= $class; method_exists($name, '__static') && xp::$registry['cl.inv'][]= array($name, '__static'); if (0 == xp::$registry['cl.level']) { $invocations= xp::$registry['cl.inv']; xp::$registry['cl.inv']= array(); foreach ($invocations as $inv) call_user_func($inv); } return $name; } /** * Loads a resource. * * @param string filename name of resource * @return string * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResource($filename) { if (!is_file($this->path.strtr($filename, '/', DIRECTORY_SEPARATOR))) { return raise('lang.ElementNotFoundException', 'Could not load resource '.$filename); } return file_get_contents($this->path.$filename); } /** * Retrieve a stream to the resource * * @param string filename name of resource * @return io.File * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResourceAsStream($filename) { if (!is_file($this->path.strtr($filename, '/', DIRECTORY_SEPARATOR))) { return raise('lang.ElementNotFoundException', 'Could not load resource '.$filename); } return new File($this->path.$filename); } /** * Fetch instance of classloader by the path to the archive * * @param string path * @param bool expand default TRUE whether to expand the path using realpath * @return lang.FileSystemClassLoader */ public static function instanceFor($path, $expand= TRUE) { static $pool= array(); $path= $expand ? realpath($path) : $path; if (!isset($pool[$path])) { $pool[$path]= new self($path); } return $pool[$path]; } /** * Get package contents * * @param string package * @return string[] filenames */ public function packageContents($package) { $contents= array(); if ($d= @dir($this->path.strtr($package, '.', DIRECTORY_SEPARATOR))) { while ($e= $d->read()) { if ('.' != $e{0}) $contents[]= $e.(is_dir($d->path.DIRECTORY_SEPARATOR.$e) ? '/' : ''); } $d->close(); } return $contents; } } ?> * [fully-qualified-class-name]@[serialized-object] * * * Example: * * lang.Object@class object { * var $__id = '0.06823200 1062749651'; * } * * * @return string */ public function toString(); } ?> method= $method; } /** * Return compound message of this exception. * * @return string */ public function compoundMessage() { return sprintf( 'Exception %s (method %s(): %s)', $this->getClassName(), $this->method, $this->message ); } } ?> __id) $this->__id= microtime(); $this->__id= microtime(); } /** * Returns a hashcode for this object * * @return string */ public function hashCode() { if (!$this->__id) $this->__id= microtime(); return $this->__id; } /** * Indicates whether some other object is "equal to" this one. * * @param lang.Object cmp * @return bool TRUE if the compared object is equal to this object */ public function equals($cmp) { if (!$this->__id) $this->__id= microtime(); if (!$cmp->__id) $cmp->__id= microtime(); return $this === $cmp; } /** * Returns the fully qualified class name for this class * (e.g. "io.File") * * @return string fully qualified class name */ public function getClassName() { return xp::nameOf(get_class($this)); } /** * Returns the runtime class of an object. * * @return lang.XPClass runtime class * @see xp://lang.XPClass */ public function getClass() { return new XPClass($this); } /** * Creates a string representation of this object. In general, the toString * method returns a string that "textually represents" this object. The result * should be a concise but informative representation that is easy for a * person to read. It is recommended that all subclasses override this method. * * Per default, this method returns: * * [fully-qualified-class-name] '{' [members-and-value-list] '}' * * * Example: * * lang.Object { * __id => "0.43080500 1158148350" * } * * * @return string */ public function toString() { if (!$this->__id) $this->__id= microtime(); return xp::stringOf($this); } } ?> *
  • public string hashCode()
  • *
  • public bool equals(lang.Object cmp)
  • *
  • public string getClassName()
  • *
  • public lang.XPClass getClass()
  • *
  • public string toString()
  • * * * Note: getClassName() is not only a shorthand for getClass()->getName() * but also significantly faster than the latter. * * Classes and reflection * ====================== * Every object has an XPClass instance associated with it, providing * reflective information about the runtime class. This includes a fully * qualified class name (e.g. "util.Date"), annotations support, class * fields, methods, constructors and their modifiers as well as methods * to dynamically access these. * * Class loading * ============= * The lang package contains the default classloader class which takes * care of loading classes from the file system. Loading classes from * archive files (xars) is supported by the lang.archive package. * * Process control * =============== * The Process and Thread classes implement process execution and * control. They are complemented with the System class which provides * information about the underlying operating system. * * Chained exceptions * ================== * Not all exceptions in the framework have a cause. Exceptions that * choose to have a cause may extend the lang.ChainedException class. * * Example (abbreviated): * * class FinderException extends ChainedException { } * * class NewsFinder extends Finder { * public function findByPK($pk) { * try { * $r= $this->conn->query('select * from news where news_id= %d', $pk)->next(); * } catch (SQLException $e) { * throw new FinderException('Error while finding news id #'.$pk, $e); * } * if (FALSE === $r) { * throw new FinderException( * 'News id #'.$pk.' does not exist', * new ElementNotFoundException($pk) * ); * } * return $r; * } * } * * $news= new NewsFinder(); * try { * $news->findByPK(10250); * } catch (FinderException $e) { * Console::writeLine('*** ', $e->getMessage(), ' caused by: ', $e->getCause()); * } * * * Classes loaded per default * ========================== * These classes are guaranteed to be loaded at any given time: * * lang.Object, lang.StackTraceElement, lang.Throwable, lang.Error, * lang.XPException, lang.Type, lang.reflect.Routine, lang.reflect.Parameter, * lang.reflect.TargetInvocationException, lang.reflect.Method, * lang.reflect.Field, lang.reflect.Constructor, lang.reflect.Modifiers, * lang.reflect.Package, lang.XPClass, lang.FileSystemClassLoader, * lang.DynamicClassLoader, lang.archive.ArchiveClassLoader, lang.ClassLoader * * These exceptions are guaranteed to be loaded at any given time: * * lang.ChainedException, lang.NullPointerException, lang.IllegalAccessException, * lang.IllegalArgumentException, lang.IllegalStateException, * lang.FormatException, lang.ClassNotFoundException, * * @see http://news.xp-framework.net/article/11/2004/11/23/ * @see xp://lang.Throwable * @see xp://lang.Object * @see xp://lang.Generic * @see xp://lang.XPClass * @see xp://lang.Process * @purpose Core */ package lang { } *
  • string
  • *
  • integer
  • *
  • double
  • *
  • boolean
  • *
  • array
  • * * * @test xp://net.xp_framework.unittest.reflection.PrimitiveTest * @see xp://lang.Type * @purpose Type implementation */ class Primitive extends Type { public static $STRING = NULL, $INTEGER = NULL, $DOUBLE = NULL, $BOOLEAN = NULL, $ARRAY = NULL; static function __static() { self::$STRING= new self('string'); self::$INTEGER= new self('integer'); self::$DOUBLE= new self('double'); self::$BOOLEAN= new self('boolean'); self::$ARRAY= new self('array'); } /** * Returns the wrapper class for this primitive * * @see http://en.wikipedia.org/wiki/Wrapper_class * @return lang.XPClass */ public function wrapperClass() { switch ($this) { case self::$STRING: return XPClass::forName('lang.types.String'); case self::$INTEGER: return XPClass::forName('lang.types.Integer'); case self::$DOUBLE: return XPClass::forName('lang.types.Double'); case self::$BOOLEAN: return XPClass::forName('lang.types.Boolean'); case self::$ARRAY: return XPClass::forName('lang.types.ArrayList'); } } /** * Boxes a type - that is, turns Generics into primitives * * @param mixed in * @return mixed the primitive if not already primitive * @throws lang.IllegalArgumentException in case in cannot be unboxed. */ public static function unboxed($in) { if ($in instanceof String) return $in->toString(); if ($in instanceof Double) return $in->floatValue(); if ($in instanceof Integer) return $in->intValue(); if ($in instanceof Boolean) return $in->value; if ($in instanceof ArrayList) return $in->values; if ($in instanceof Generic) { throw new IllegalArgumentException('Cannot unbox '.xp::typeOf($in)); } return $in; // Already primitive } /** * Boxes a type - that is, turns primitives into Generics * * @param mixed in * @return lang.Generic the Generic if not already generic * @throws lang.IllegalArgumentException in case in cannot be boxed. */ public static function boxed($in) { if (NULL === $in || $in instanceof Generic) return $in; $t= gettype($in); if ('string' === $t) return new String($in); if ('integer' === $t) return new Integer($in); if ('double' === $t) return new Double($in); if ('boolean' === $t) return new Boolean($in); if ('array' === $t) return ArrayList::newInstance($in); throw new IllegalArgumentException('Cannot box '.xp::typeOf($in)); } /** * Get a type instance for a given name * * @param string name * @return lang.Type * @throws lang.IllegalArgumentException if the given name does not correspond to a primitive */ public static function forName($name) { switch ($name) { case 'string': return self::$STRING; case 'integer': return self::$INTEGER; case 'double': return self::$DOUBLE; case 'boolean': return self::$BOOLEAN; case 'array': return self::$ARRAY; default: throw new IllegalArgumentException('Not a primitive: '.$name); } } } ?> * $p= new Process('uptime'); * $uptime= $p->out->readLine(); * $p->close(); * * var_dump($uptime); * * * @test xp://net.xp_framework.unittest.core.ProcessTest * @see xp://lang.Runtime#getExecutable * @see php://proc_open * @purpose Execute external programs */ class Process extends Object { public $in = NULL, $out = NULL, $err = NULL, $exitv = -1; protected static $escape = ''; protected $_proc = NULL, $status = array(); static function __static() { $e= escapeshellarg(''); self::$escape= (0 === strlen($e) ? '"' : $e{0}); } /** * Escape and argument * * @param string arg * @return string escaped */ protected function escape($arg) { return strstr($arg, ' ') && !strstr($arg, self::$escape) ? escapeshellarg($arg) : $arg; } /** * Constructor * * @param string command default NULL * @param string[] arguments default [] * @param string cwd default NULL the working directory * @param array default NULL the environment * @throws io.IOException in case the command could not be executed */ public function __construct($command= NULL, $arguments= array(), $cwd= NULL, $env= NULL) { static $spec= array( 0 => array('pipe', 'r'), // stdin 1 => array('pipe', 'w'), // stdout 2 => array('pipe', 'w') // stderr ); // For `new self()` used in getProcessById() if (NULL === $command) return; // Check whether the given command is executable. $binary= $this->resolve($command); if (!is_file($binary) || !is_executable($binary)) { throw new IOException('Command "'.$binary.'" is not an executable file'); } // Build command line $cmd= $this->escape($command); foreach ($arguments as $arg) { $cmd.= ' '.$this->escape($arg); } // Open process if (!is_resource($this->_proc= proc_open($cmd, $spec, $pipes, $cwd, $env, array('bypass_shell' => TRUE)))) { throw new IOException('Could not execute "'.$cmd.'"'); } $this->status= proc_get_status($this->_proc); $this->status['exe']= $binary; $this->status['arguments']= NULL; // Assign in, out and err members $this->in= new File($pipes[0]); $this->out= new File($pipes[1]); $this->err= new File($pipes[2]); } /** * Create a new instance of this process. * * @param string[] arguments default [] * @param string cwd default NULL the working directory * @param array default NULL the environment * @throws io.IOException in case the command could not be executed */ public function newInstance($arguments= array(), $cwd= NULL, $env= NULL) { return new self($this->status['exe'], $arguments, $cwd, $env); } /** * Resolve path for a command * * @param string command * @return string executable * @throws io.IOException in case the command could not be found */ public function resolve($command) { clearstatcache(); // PATHEXT is in form ".{EXT}[;.{EXT}[;...]]" $extensions= array('') + explode(PATH_SEPARATOR, getenv('PATHEXT')); // If the command is in fully qualified form and refers to a file // that does not exist (e.g. "C:\DoesNotExist.exe", "\DoesNotExist.com" // or /usr/bin/doesnotexist), do not attempt to search for it. if ( (strncasecmp(PHP_OS, 'Win', 3) === 0 && ':' === $command{1}) || (DIRECTORY_SEPARATOR === $command{0}) ) { foreach ($extensions as $ext) { $q= $command.$ext; if (file_exists($q) && !is_dir($q)) return realpath($q); } throw new IOException('"'.$command.'" does not exist'); } // Check the PATH environment setting for possible locations of the // executable if its name is not a fully qualified path name. $paths= explode(PATH_SEPARATOR, getenv('PATH')); foreach ($paths as $path) { foreach ($extensions as $ext) { $q= $path.DIRECTORY_SEPARATOR.$command.$ext; if (file_exists($q) && !is_dir($q)) return realpath($q); } } throw new IOException('Could not find "'.$command.'" in path'); } /** * Get a process by process ID * * @param int pid process id * @param string exe * @return lang.Process * @throws lang.IllegalStateException */ public static function getProcessById($pid, $exe= NULL) { $self= new self(); $self->status= array( 'pid' => $pid, 'running' => TRUE, 'exe' => $exe, 'command' => '', 'arguments' => NULL ); // Determine executable and command line: // * On Windows, use Windows Management Instrumentation API - see // http://en.wikipedia.org/wiki/Windows_Management_Instrumentation // // * On systems with a /proc filesystem, use information from /proc/self // See http://en.wikipedia.org/wiki/Procfs // // * Fall back to use the "_" environment variable and /bin/ps to retrieve // the command line (please note unfortunately any quote signs have been // lost and it can thus be only used for display purposes) // // Note: It would be really nice to have a getmyexe() function in PHP // complementing getmypid(). if (strncasecmp(PHP_OS, 'Win', 3) === 0) { try { $c= new com('winmgmts:'); $p= $c->get('//./root/cimv2:Win32_Process.Handle="'.$pid.'"'); $self->status['exe']= $p->executablePath; $self->status['command']= $p->commandLine; } catch (Exception $e) { throw new IllegalStateException('Cannot find executable: '.$e->getMessage()); } } else if (file_exists($proc= '/proc/'.$pid)) { foreach (array('/exe', '/file') as $alt) { if (!file_exists($proc.$alt)) continue; $self->status['exe']= readlink($proc.$alt); break; } $self->status['command']= strtr(file_get_contents($proc.'/cmdline'), "\0", ' '); } else if ($exe) { try { $self->status['exe']= $self->resolve($exe); $self->status['command']= exec('ps -p '.$pid.' -ocommand'); } catch (IOException $e) { throw new IllegalStateException($e->getMessage()); } } else if ($_= getenv('_')) { $self->status['exe']= $self->resolve($_); $self->status['command']= exec('ps -p '.$pid.' -ocommand'); } else { throw new IllegalStateException('Cannot find executable'); } $self->in= xp::null(); $self->out= xp::null(); $self->err= xp::null(); return $self; } /** * Get process ID * * @return int */ public function getProcessId() { return $this->status['pid']; } /** * Get filename of executable * * @return string */ public function getFilename() { return $this->status['exe']; } /** * Get command line * * @return string */ public function getCommandLine() { return $this->status['command']; } /** * Parse command line arguments * * @see xp://lang.Process#getArguments * @param string cmd * @return string[] arguments */ public static function parseCommandLine($cmd) { // Remove executable from command line. If it's quoted, handle this // accordingly (with either single and double quotes). If the command // line exists entirely of the command, return an empty array if ('"' === $cmd{0}) { $cmd= substr($cmd, strpos($cmd, '"', 1)+ 2); } else if ("'" === $cmd{0}) { $cmd= substr($cmd, strpos($cmd, "'", 1)+ 2); } else if (FALSE !== ($end= strpos($cmd, ' '))) { $cmd= substr($cmd, $end+ 1); } else { return array(); } // Parse arguments. These also may be quoted (again, either with " or '), // or even partially quoted, so handle this, too. $arguments= array(); $o= 0; while (FALSE !== ($p= strcspn($cmd, ' ', $o))) { $option= substr($cmd, $o, $p); if (1 === substr_count($option, '"')) { $l= $o+ $p; $qp= strpos($cmd, '"', $l)+ 1; $option.= substr($cmd, $l, $qp- $l); $o= $qp+ 1; } else if (1 === substr_count($option, "'")) { $l= $o+ $p; $qp= strpos($cmd, "'", $l)+ 1; $option.= substr($cmd, $l, $qp- $l); $o= $qp+ 1; } else { $o+= $p+ 1; } $arguments[]= $option; } return $arguments; } /** * Get command line arguments * * @return string[] */ public function getArguments() { if (NULL === $this->status['arguments']) { $this->status['arguments']= self::parseCommandLine($this->status['command']); } return $this->status['arguments']; } /** * Get error stream * * @return io.File STDERR */ public function getErrorStream() { return $this->err; } /** * Get input stream * * @return io.File STDIN */ public function getInputStream() { return $this->in; } /** * Get output stream * * @return io.File STDOUT */ public function getOutputStream() { return $this->out; } /** * Returns the exit value for the process * * @return int */ public function exitValue() { return $this->exitv; } /** * Close this process * * @return int exit value of process */ public function close() { $this->in->isOpen() && $this->in->close(); $this->out->isOpen() && $this->out->close(); $this->err->isOpen() && $this->err->close(); $this->exitv= proc_close($this->_proc); return $this->exitv; } } ?> * $constructor= XPClass::forName('utl.Binford')->getConstructor(); * * var_dump($constructor->newInstance()); * * * @param mixed[] args * @return lang.Generic * @throws lang.IllegalAccessException in case the constructor is not public or if it is abstract * @throws lang.reflect.TargetInvocationException in case the constructor throws an exception */ public function newInstance(array $args= array()) { // Check whether class is abstract $class= new ReflectionClass($this->_class); if ($class->isAbstract()) { throw new IllegalAccessException('Cannot instantiate abstract class '.$this->_class); } // Check modifers $m= $this->_reflect->getModifiers(); if (!($m & MODIFIER_PUBLIC)) { throw new IllegalAccessException(sprintf( 'Cannot invoke %s constructor of class %s', Modifiers::stringOf($this->getModifiers()), $this->_class )); } $paramstr= ''; for ($i= 0, $m= sizeof($args); $i < $m; $i++) { $paramstr.= ', $args['.$i.']'; } try { return eval('return new '.$this->_class.'('.substr($paramstr, 2).');'); } catch (Throwable $e) { throw new TargetInvocationException($this->_class.'::', $e); } } /** * Retrieve return type * * @return lang.Type */ public function getReturnType() { return XPClass::forName(xp::nameOf($this->_class)); } /** * Retrieve return type * * @return string */ public function getReturnTypeName() { return xp::nameOf($this->_class); } } ?> _class= $class; $this->_reflect= $reflect; } /** * Get field's name. * * @return string */ public function getName() { return $this->_reflect->getName(); } /** * Gets field type * * @return string */ public function getType() { if ($details= XPClass::detailsForField($this->_class, $this->_reflect->getName())) { if (isset($details[DETAIL_ANNOTATIONS]['type'])) return $details[DETAIL_ANNOTATIONS]['type']; } return NULL; } /** * Check whether an annotation exists * * @param string name * @param string key default NULL * @return bool */ public function hasAnnotation($name, $key= NULL) { $details= XPClass::detailsForField($this->_class, $this->_reflect->getName()); return $details && ($key ? array_key_exists($key, (array)@$details[DETAIL_ANNOTATIONS][$name]) : array_key_exists($name, (array)@$details[DETAIL_ANNOTATIONS]) ); } /** * Retrieve annotation by name * * @param string name * @param string key default NULL * @return mixed * @throws lang.ElementNotFoundException */ public function getAnnotation($name, $key= NULL) { $details= XPClass::detailsForField($this->_class, $this->_reflect->getName()); if (!$details || !($key ? array_key_exists($key, @$details[DETAIL_ANNOTATIONS][$name]) : array_key_exists($name, @$details[DETAIL_ANNOTATIONS]) )) return raise( 'lang.ElementNotFoundException', 'Annotation "'.$name.($key ? '.'.$key : '').'" does not exist' ); return ($key ? $details[DETAIL_ANNOTATIONS][$name][$key] : $details[DETAIL_ANNOTATIONS][$name] ); } /** * Retrieve whether this field has annotations * * @return bool */ public function hasAnnotations() { $details= XPClass::detailsForField($this->_class, $this->_reflect->getName()); return $details ? !empty($details[DETAIL_ANNOTATIONS]) : FALSE; } /** * Retrieve all of this field's annotations * * @return array annotations */ public function getAnnotations() { $details= XPClass::detailsForField($this->_class, $this->_reflect->getName()); return $details ? $details[DETAIL_ANNOTATIONS] : array(); } /** * Returns the XPClass object representing the class or interface * that declares the field represented by this Field object. * * @return lang.XPClass */ public function getDeclaringClass() { return new XPClass($this->_reflect->getDeclaringClass()->getName()); } /** * Returns the value of the field represented by this Field, on the * specified object. * * @param lang.Object instance * @return mixed * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class * @throws lang.IllegalAccessException in case this field is not public */ public function get($instance) { // Verify the field is public if (!($this->_reflect->getModifiers() & MODIFIER_PUBLIC)) { throw new IllegalAccessException('Cannot read '.$this->toString()); } // Short-circuit further checks for static members if ($this->_reflect->isStatic()) { return $this->_reflect->getValue(NULL); } // Verify given instance is instance of the class declaring this // property if (!($instance instanceof $this->_class)) { throw new IllegalArgumentException(sprintf( 'Passed argument is not a %s class (%s)', xp::nameOf($this->_class), xp::typeOf($instance) )); } return $this->_reflect->getValue($instance); } /** * Changes the value of the field represented by this Field, on the * specified object. * * @param lang.Object instance * @param mixed value * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class * @throws lang.IllegalAccessException in case this field is not public */ public function set($instance, $value) { // Verify the field is public if (!($this->_reflect->getModifiers() & MODIFIER_PUBLIC)) { throw new IllegalAccessException('Cannot write '.$this->toString()); } // Short-circuit further checks for static members if ($this->_reflect->isStatic()) { return $this->_reflect->setValue(NULL, $value); } // Verify given instance is instance of the class declaring this // property if (!($instance instanceof $this->_class)) { throw new IllegalArgumentException(sprintf( 'Passed argument is not a %s class (%s)', xp::nameOf($this->_class), xp::typeOf($instance) )); } $this->_reflect->setValue($instance, $value); } /** * Retrieve this field's modifiers * * @see xp://lang.reflect.Modifiers * @return int */ public function getModifiers() { return $this->_reflect->getModifiers(); } /** * Creates a string representation of this field * * @return string */ public function toString() { $t= $this->getType(); return sprintf( '%s%s %s::$%s', Modifiers::stringOf($this->getModifiers()), $t ? ' '.$t : '', $this->getDeclaringClass()->getName(), $this->getName() ); } } ?> * $method= XPClass::forName('lang.Object')->getMethod('toString'); * * var_dump($method->invoke(new Object())); * * * Example (passing arguments) * * $method= XPClass::forName('lang.types.String')->getMethod('concat'); * * var_dump($method->invoke(new String('Hello'), array('World'))); * * * Example (static invokation): * * $method= XPClass::forName('util.log.Logger')->getMethod('getInstance'); * * var_dump($method->invoke(NULL)); * * * @param lang.Object obj * @param mixed[] args default array() * @return mixed * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class * @throws lang.IllegalAccessException in case the method is not public or if it is abstract */ public function invoke($obj, $args= array()) { if (NULL !== $obj && !($obj instanceof $this->_class)) { throw new IllegalArgumentException(sprintf( 'Passed argument is not a %s class (%s)', xp::nameOf($this->_class), xp::typeOf($obj) )); } // Check modifers $m= $this->_reflect->getModifiers(); if (!($m & MODIFIER_PUBLIC) || $m & MODIFIER_ABSTRACT) { throw new IllegalAccessException(sprintf( 'Cannot invoke %s %s::%s', Modifiers::stringOf($this->getModifiers()), $this->_class, $this->_reflect->getName() )); } try { return $this->_reflect->invokeArgs($obj, (array)$args); } catch (Throwable $e) { throw new TargetInvocationException($this->_class.'::'.$this->_reflect->getName().'() ~ '.$e->getMessage(), $e); } catch (ReflectionException $e) { // This should never occur, we checked everything beforehand... throw new TargetInvocationException($this->_class.'::'.$this->_reflect->getName().'() ~ '.$e->getMessage(), new XPException($e->getMessage())); } } } ?> * [access] static abstract final * * [access] is one on public, private or protected. * * @param int m modifiers bitfield * @return string[] */ public static function namesOf($m) { $names= array(); switch ($m & (MODIFIER_PUBLIC | MODIFIER_PROTECTED | MODIFIER_PRIVATE)) { case MODIFIER_PRIVATE: $names[]= 'private'; break; case MODIFIER_PROTECTED: $names[]= 'protected'; break; case MODIFIER_PUBLIC: default: $names[]= 'public'; break; } if ($m & MODIFIER_STATIC) $names[]= 'static'; if ($m & MODIFIER_ABSTRACT) $names[]= 'abstract'; if ($m & MODIFIER_FINAL) $names[]= 'final'; return $names; } /** * Retrieves modifier names as a string * * @param int m modifiers bitfield * @return string */ public static function stringOf($m) { return implode(' ', self::namesOf($m)); } } ?> getClass(), XPClass::forName() * or by ClassLoader methods. * * Common use-cases * ================ * Instantiating a class by its name: * * $now= XPClass::forName('util.Date')->newInstance(); * * * Invoking a method by its name: * * $c= XPClass::forName('util.Binford'); * $c->getMethod('setPoweredBy')->invoke($c->newInstance(), array(6100)); * * * Retrieving annotations: * * $s= $service->getClass()->getMethod($invoked)->getAnnotation('security'); * if (!in_array($role, $s['roles'])) { * throw new IllegalAccessException('Access denied to '.$invoked); * } * * * Dynamic Proxies * =============== * The proxy class serves the purpose of dynamically creating instances * of interfaces. Use cases are remote method invocations, deferred * initialization or debugging. * * Around-Invoke: * * // Exchange the following: * $account= new Account(); * * // ...with this: * $account= Proxy::newProxyInstance( * ClassLoader::getDefault(), * array(XPClass::forName('com.acme.banking.IAccount')), * newinstance('lang.reflect.InvocationHandler', array(new Account()), '{ * public function __construct($wrapped) { * $this->wrapped= $wrapped; * } * * public function invoke($proxy, $method, $args) { * if ("transfer" == $method && $args[0] > 1000000) { * throw new IllegalAccessException("Too much money"); * } * return call_user_func_array(array($this->wrapped, $method), $args); * } * }') * ); * * $account->transfer(50); * $account->transfer(1000001); // BLAM * * * @see http://developer.xp-framework.net/xml/rfc/view?0030 * @see xp://lang.Generic#getClass * @see xp://lang.XPClass#forName * @see xp://lang.ClassLoader#loadClass * @see xp://lang.ClassLoader#defineClass * @see xp://lang.reflect.Proxy * @purpose Reflection */ package lang.reflect { } name; } /** * Returns simple name * * @return string */ public function getSimpleName() { return substr($this->name, strrpos($this->name, '.')+ 1); } /** * Checks if a specific class is provided by this package * * @param string name * @return bool */ public function providesClass($name) { return ClassLoader::getDefault()->providesClass($this->name.'.'.$name); } /** * Checks if a specific subpackage is provided by this package * * @param string name * @return bool */ public function providesPackage($name) { return ClassLoader::getDefault()->providesPackage($this->name.'.'.$name); } /** * Checks if a specific resource is provided by this package * * @param string name * @return bool */ public function providesResource($name) { return ClassLoader::getDefault()->providesResource(strtr($this->name, '.', '/').'/'.$name); } /** * Get all classes in this package. Loads classes if not already * loaded. * * @return lang.XPClass[] */ public function getClasses() { return array_map(array(xp::reflect('lang.XPClass'), 'forName'), $this->getClassNames()); } /** * Get the names of classes in this package, not loading them. * * @return string[] */ public function getClassNames() { $classes= array(); foreach (ClassLoader::getDefault()->packageContents($this->name) as $file) { if (xp::CLASS_FILE_EXT == substr($file, -10)) $classes[]= ltrim($this->name.'.'.substr($file, 0, -10), '.'); } return $classes; } /** * Load a specific class by its name, which may be either locally * qualified (without dots) or fully qualified (with dots). * * @param string name * @return lang.XPClass * @throws lang.IllegalArgumentException */ public function loadClass($name) { // Handle fully qualified names if (FALSE !== ($p= strrpos($name, '.'))) { if (substr($name, 0, $p) != $this->name) { throw new IllegalArgumentException('Class '.$name.' is not in '.$this->name); } $name= substr($name, $p+ 1); } return XPClass::forName($this->name.'.'.$name); } /** * Returns a list of subpackages in this package. * * @return lang.reflect.Package[] */ public function getPackages() { return array_map(array(xp::reflect('lang.reflect.Package'), 'forName'), $this->getPackageNames()); } /** * Returns a list of subpackages in this package. * * @return string[] */ public function getPackageNames() { $packages= array(); foreach (ClassLoader::getDefault()->packageContents($this->name) as $file) { if ('/' == substr($file, -1)) $packages[]= ltrim($this->name.'.'.substr($file, 0, -1), '.'); } return $packages; } /** * Returns a list of resources in this package. * * @return string[] */ public function getResources() { $resources= array(); foreach (ClassLoader::getDefault()->packageContents($this->name) as $file) { if ('/' == substr($file, -1) || xp::CLASS_FILE_EXT == substr($file, -10)) continue; $resources[]= strtr($this->name, '.', '/').'/'.$file; } return $resources; } /** * Get a specific subpackage of this package by its name, which * may be either locally qualified (without dots) or fully * qualified (with dots). * * @param string name * @return lang.reflect.Package * @throws lang.IllegalArgumentException */ public function getPackage($name) { // Handle fully qualified names if (FALSE !== ($p= strrpos($name, '.'))) { if (substr($name, 0, $p) != $this->name) { throw new IllegalArgumentException('Package '.$name.' is not in '.$this->name); } $name= substr($name, $p+ 1); } return self::forName($this->name.'.'.$name); } /** * Returns a Package object for a given fully qualified name. * * @param string name * @return lang.reflect.Package * @throws lang.ElementNotFoundException */ public static function forName($name) { $p= new self(); $p->name= rtrim($name, '.'); // Normalize if (!ClassLoader::getDefault()->providesPackage($p->name)) { raise('lang.ElementNotFoundException', 'No classloaders provide '.$name); } return $p; } /** * Loads a resource. * * @param string filename name of resource * @return string * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResource($filename) { // Handle fully qualified names if (FALSE !== ($p= strrpos($filename, '/'))) { if (substr($filename, 0, $p) != strtr($this->name, '.', '/')) { throw new IllegalArgumentException('Resource '.$filename.' is not in '.$this->name); } $filename= substr($filename, $p+ 1); } return ClassLoader::getDefault()->getResource(strtr($this->name, '.', '/').'/'.$filename); } /** * Retrieve a stream to the resource * * @param string filename name of resource * @return io.File * @throws lang.ElementNotFoundException in case the resource cannot be found */ public function getResourceAsStream($filename) { // Handle fully qualified names if (FALSE !== ($p= strrpos($filename, '/'))) { if (substr($filename, 0, $p) != strtr($this->name, '.', '/')) { throw new IllegalArgumentException('Resource '.$filename.' is not in '.$this->name); } $filename= substr($filename, $p+ 1); } return ClassLoader::getDefault()->getResourceAsStream(strtr($this->name, '.', '/').'/'.$filename); } /** * Creates a string representation of this package * * Example: *
         *   lang.reflect.Package
         * 
    * * @return string */ public function toString() { return $this->getClassName().'<'.$this->name.'>'; } /** * Checks whether a given object is equal to this Package instance. * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->name === $cmp->name; } /** * Creates a hashcode for this package * * @return string */ public function hashCode() { return 'P['.$this->name; } } ?> _reflect= $reflect; $this->_details= $details; } /** * Get parameter's name. * * @return string */ public function getName() { return $this->_reflect->getName(); } /** * Get parameter's type. * * @return lang.Type */ public function getType() { if ( !($details= XPClass::detailsForMethod($this->_details[0], $this->_details[1])) || !isset($details[DETAIL_ARGUMENTS][$this->_details[2]]) ) { // Unknown or unparseable, return ANYTYPE return Type::$ANY; } return Type::forName(ltrim($details[DETAIL_ARGUMENTS][$this->_details[2]], '&')); } /** * Get parameter's type. * * @return string */ public function getTypeName() { if ( !($details= XPClass::detailsForMethod($this->_details[0], $this->_details[1])) || !isset($details[DETAIL_ARGUMENTS][$this->_details[2]]) ) { // Unknown or unparseable, return ANYTYPE return '*'; } return ltrim($details[DETAIL_ARGUMENTS][$this->_details[2]], '&'); } /** * Get parameter's type restriction. * * @return lang.Type or NULL if there is no restriction */ public function getTypeRestriction() { if ($this->_reflect->isArray()) { return Primitive::$ARRAY; } else if ($c= $this->_reflect->getClass()) { return new XPClass($c); } else { return NULL; } } /** * Retrieve whether this argument is optional * * @return bool */ public function isOptional() { return $this->_reflect->isOptional(); } /** * Get default value. * * @throws lang.IllegalStateException in case this argument is not optional * @return mixed */ public function getDefaultValue() { if ($this->_reflect->isOptional()) { return $this->_reflect->getDefaultValue(); } throw new IllegalStateException('Parameter "'.$this->_reflect->getName().'" has no default value'); } /** * Creates a string representation * * @return string */ public function toString() { return sprintf( '%s<%s %s%s>', $this->getClassName(), $this->getType()->toString(), $this->_reflect->getName(), $this->_reflect->isOptional() ? '= '.xp::stringOf($this->_reflect->getDefaultValue()) : '' ); } } ?> _h= $handler; } /** * Returns the XPClass object for a proxy class given a class loader * and an array of interfaces. The proxy class will be defined by the * specified class loader and will implement all of the supplied * interfaces (also loaded by the classloader). * * @param lang.ClassLoader classloader * @param lang.XPClass[] interfaces names of the interfaces to implement * @return lang.XPClass * @throws lang.IllegalArgumentException */ public static function getProxyClass($classloader, $interfaces) { static $num= 0; static $cache= array(); // Calculate cache key (composed of the names of all interfaces) $key= $classloader->hashCode().':'.implode(';', array_map( create_function('$i', 'return $i->getName();'), $interfaces )); if (isset($cache[$key])) return $cache[$key]; // Create proxy class' name, using a unique identifier and a prefix $name= PROXY_PREFIX.($num++); $bytes= 'class '.$name.' extends '.xp::reflect('lang.reflect.Proxy').' implements '; $added= array(); for ($j= 0, $t= sizeof($interfaces); $j < $t; $j++) { $bytes.= xp::reflect($interfaces[$j]->getName()).', '; } $bytes= substr($bytes, 0, -2)." {\n"; for ($j= 0, $t= sizeof($interfaces); $j < $t; $j++) { $if= $interfaces[$j]; // Verify that the Class object actually represents an interface if (!$if->isInterface()) { throw new IllegalArgumentException($if->getName().' is not an interface'); } // Implement all the interface's methods foreach ($if->getMethods() as $m) { // Check for already declared methods, do not redeclare them if (isset($added[$m->getName()])) continue; $added[$m->getName()]= TRUE; // Build signature and argument list if ($m->hasAnnotation('overloaded')) { $signatures= $m->getAnnotation('overloaded', 'signatures'); $max= 0; $cases= array(); foreach ($signatures as $signature) { $args= sizeof($signature); $max= max($max, $args- 1); if (isset($cases[$args])) continue; $cases[$args]= ( 'case '.$args.': '. 'return $this->_h->invoke($this, \''.$m->getName(TRUE).'\', array('. ($args ? '$_'.implode(', $_', range(0, $args- 1)) : '').'));' ); } // Create method $bytes.= ( 'function '.$m->getName().'($_'.implode('= NULL, $_', range(0, $max)).'= NULL) { '. 'switch (func_num_args()) {'.implode("\n", $cases). ' default: throw new IllegalArgumentException(\'Illegal number of arguments\'); }'. '}'."\n" ); } else { $signature= $args= ''; foreach ($m->getParameters() as $param) { $restriction= $param->getTypeRestriction(); $signature.= ', '.($restriction ? xp::reflect($restriction->getName()) : '').' $'.$param->getName(); $args.= ', $'.$param->getName(); $param->isOptional() && $signature.= '= '.var_export($param->getDefaultValue(), TRUE); } $signature= substr($signature, 2); $args= substr($args, 2); // Create method $bytes.= ( 'function '.$m->getName().'('.$signature.') { '. 'return $this->_h->invoke($this, \''.$m->getName(TRUE).'\', array('.$args.')); '. '}'."\n" ); } } } $bytes.= ' }'; // Define the generated class try { $dyn= DynamicClassLoader::instanceFor(__METHOD__); $dyn->setClassBytes($name, $bytes); $class= $dyn->loadClass($name); } catch (FormatException $e) { throw new IllegalArgumentException($e->getMessage()); } // Update cache and return XPClass object $cache[$key]= $class; return $class; } /** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation * handler. * * @param lang.ClassLoader classloader * @param lang.XPClass[] interfaces * @param lang.reflect.InvocationHandler handler * @return lang.XPClass * @throws lang.IllegalArgumentException */ public static function newProxyInstance($classloader, $interfaces, $handler) { return self::getProxyClass($classloader, $interfaces)->newInstance($handler); } } ?> _class= $class; $this->_reflect= $reflect; } /** * Get routine's name. * * @return string */ public function getName() { return $this->_reflect->getName(); } /** * Retrieve this method's modifiers * * @see xp://lang.reflect.Modifiers * @return int */ public function getModifiers() { // Note: ReflectionMethod::getModifiers() returns whatever PHP reflection // returns, but the numeric value changed since 5.0.0 as the zend_function // struct's fn_flags now contains not only ZEND_ACC_(PPP, STATIC, FINAL, // ABSTRACT) but also some internal information about how this method needs // to be called. // // == List of fn_flags we don't want to return from this method == // #define ZEND_ACC_IMPLEMENTED_ABSTRACT 0x08 // #define ZEND_ACC_IMPLICIT_PUBLIC 0x1000 // #define ZEND_ACC_CTOR 0x2000 // #define ZEND_ACC_DTOR 0x4000 // #define ZEND_ACC_CLONE 0x8000 // #define ZEND_ACC_ALLOW_STATIC 0x10000 // #define ZEND_ACC_SHADOW 0x20000 // #define ZEND_ACC_DEPRECATED 0x40000 // == return $this->_reflect->getModifiers() & ~0x7f008; } /** * Returns this method's parameters * * @return lang.reflect.Parameter[] */ public function getParameters() { $r= array(); foreach ($this->_reflect->getParameters() as $offset => $param) { $r[]= new langreflectParameter($param, array($this->_class, $this->_reflect->getName(), $offset)); } return $r; } /** * Retrieve one of this method's parameters by its offset * * @param int offset * @return lang.reflect.Parameter or NULL if it does not exist */ public function getParameter($offset) { $list= $this->_reflect->getParameters(); return isset($list[$offset]) ? new langreflectParameter($list[$offset], array($this->_class, $this->_reflect->getName(), $offset)) : NULL ; } /** * Retrieve how many parameters this method declares (including optional * ones) * * @return int */ public function numParameters() { return $this->_reflect->getNumberOfParameters(); } /** * Retrieve return type * * @return string */ public function getReturnType() { if (!($details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()))) return Type::$ANY; return Type::forName(ltrim($details[DETAIL_RETURNS], '&')); } /** * Retrieve return type name * * @return string */ public function getReturnTypeName() { if (!($details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()))) return NULL; return ltrim($details[DETAIL_RETURNS], '&'); } /** * Retrieve exception names * * @return string[] */ public function getExceptionNames() { $details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()); return $details ? $details[DETAIL_THROWS] : array(); } /** * Retrieve exception types * * @return lang.XPClass[] */ public function getExceptionTypes() { $details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()); return $details ? array_map(array(xp::reflect('lang.XPClass'), 'forName'), $details[DETAIL_THROWS]) : array(); } /** * Returns the XPClass object representing the class or interface * that declares the method represented by this Method object. * * @return lang.XPClass */ public function getDeclaringClass() { return new XPClass($this->_reflect->getDeclaringClass()); } /** * Retrieves the api doc comment for this method. Returns NULL if * no documentation is present. * * @return string */ public function getComment() { if (!($details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()))) return NULL; return $details[DETAIL_COMMENT]; } /** * Check whether an annotation exists * * @param string name * @param string key default NULL * @return bool */ public function hasAnnotation($name, $key= NULL) { $details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()); return $details && ($key ? array_key_exists($key, (array)@$details[DETAIL_ANNOTATIONS][$name]) : array_key_exists($name, (array)@$details[DETAIL_ANNOTATIONS]) ); } /** * Retrieve annotation by name * * @param string name * @param string key default NULL * @return mixed * @throws lang.ElementNotFoundException */ public function getAnnotation($name, $key= NULL) { $details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()); if (!$details || !($key ? array_key_exists($key, @$details[DETAIL_ANNOTATIONS][$name]) : array_key_exists($name, @$details[DETAIL_ANNOTATIONS]) )) return raise( 'lang.ElementNotFoundException', 'Annotation "'.$name.($key ? '.'.$key : '').'" does not exist' ); return ($key ? $details[DETAIL_ANNOTATIONS][$name][$key] : $details[DETAIL_ANNOTATIONS][$name] ); } /** * Retrieve whether a method has annotations * * @return bool */ public function hasAnnotations() { $details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()); return $details ? !empty($details[DETAIL_ANNOTATIONS]) : FALSE; } /** * Retrieve all of a method's annotations * * @return array annotations */ public function getAnnotations() { $details= XPClass::detailsForMethod($this->_class, $this->_reflect->getName()); return $details ? $details[DETAIL_ANNOTATIONS] : array(); } /** * Returns whether an object is equal to this routine * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return ( $cmp instanceof self && $cmp->_reflect->getName() === $this->_reflect->getName() && $cmp->getDeclaringClass()->equals($this->getDeclaringClass()) ); } /** * Returns a hashcode for this routine * * @return string */ public function hashCode() { return 'R['.$this->_reflect->getDeclaringClass().$this->_reflect->getName(); } /** * Retrieve string representation. Examples: * *
         *   public lang.XPClass getClass()
         *   public static util.Date now()
         *   public open(string $mode) throws io.FileNotFoundException, io.IOException
         * 
    * * @return string */ public function toString() { $signature= ''; foreach ($this->getParameters() as $param) { if ($param->isOptional()) { $signature.= ', ['.$param->getTypeName().' $'.$param->getName().'= '.xp::stringOf($param->getDefaultValue()).']'; } else { $signature.= ', '.$param->getTypeName().' $'.$param->getName(); } } if ($exceptions= $this->getExceptionNames()) { $throws= ' throws '.implode(', ', $exceptions); } else { $throws= ''; } return sprintf( '%s %s %s(%s)%s', Modifiers::stringOf($this->getModifiers()), $this->getReturnTypeName(), $this->getName(), substr($signature, 2), $throws ); } } ?> ., . if (file_exists($lib= $path.'php_'.$filename)) { // E.g. php_sybase_ct.dll } else if (file_exists($lib= $path.$filename)) { // E.g. sybase_ct.so } else { throw new ElementNotFoundException('Cannot find library "'.$name.'" in "'.$path.'"'); } // Found library, try to load it. dl() expects given argument to not contain // a path and will fail with "Temporary module name should contain only // filename" if it does. if (!dl(basename($lib))) { throw new RuntimeError('dl() failed for '.$lib); } return TRUE; } /** * Returns the total amount of memory available to the runtime. If there * is no limit zero will be returned. * * @return int bytes */ public function memoryLimit() { return (int)ini_get('memory_limit'); } /** * Returns the amount of memory currently allocated by the runtime * * @see php://memory_get_peak_usage * @return int bytes */ public function memoryUsage() { return memory_get_usage(TRUE); } /** * Returns the peak of of memory that has been allocated by the * runtime up until now. * * @see php://memory_get_usage * @return int bytes */ public function peakMemoryUsage() { return memory_get_peak_usage(TRUE); } /** * Check whether a given extension is available * * @see php://extension_loaded * @param string name * @return bool */ public function extensionAvailable($name) { return extension_loaded($name); } /** * Register a shutdown hook - a piece of code that will be run before * the runtime shuts down (e.g. with exit). * * @see php://register_shutdown_function * @param lang.Runnable r * @return lang.Runnable the given runnable */ public function addShutdownHook(Runnable $r) { register_shutdown_function(array($r, 'run')); return $r; } /** * Parse command line, stopping at first argument without "-" * or at "--" (php [options] -- [args...]) * * @param string[] arguments * @return array * @throws lang.FormatException in case an unrecognized argument is encountered */ public static function parseArguments($arguments) { $return= array('options' => new RuntimeOptions(), 'bootstrap' => NULL, 'main' => NULL); while (NULL !== ($argument= array_shift($arguments))) { if ('-' !== $argument{0}) { $return['bootstrap']= trim($argument, '"\'');; break; } else if ('--' === $argument) { $return['bootstrap']= trim(array_shift($arguments), '"\''); break; } switch ($argument{1}) { case 'q': // quiet case 'n': // No php.ini file will be used case 'C': { // [cgi] Do not chdir to the script's directory $return['options']->withSwitch($argument{1}); break; } case 'd': { sscanf($argument, "-d%[^=]=%[^\r]", $setting, $value); $setting= ltrim($setting, ' '); $return['options']->withSetting($setting, $value, TRUE); break; } default: { throw new FormatException('Unrecognized argument "'.$argument.'"'); } } } if ($main= array_shift($arguments)) { $return['main']= XPClass::forName($main); } return $return; } /** * Get startup options * * @return lang.RuntimeOptions */ public function startupOptions() { if (NULL === $this->startup) { // Lazy-init $this->startup= self::parseArguments($this->getExecutable()->getArguments()); } return clone $this->startup['options']; } /** * Get bootstrap script's filename * * @param string which default NULL * @return string */ public function bootstrapScript($which= NULL) { if (NULL === $this->startup) { // Lazy-init $this->startup= self::parseArguments($this->getExecutable()->getArguments()); } if ($which) { return dirname($this->startup['bootstrap']).DIRECTORY_SEPARATOR.$which.'.php'; } return $this->startup['bootstrap']; } /** * Get entry point class * * @return lang.XPClass */ public function mainClass() { if (NULL === $this->startup) { // Lazy-init $this->startup= self::parseArguments($this->getExecutable()->getArguments()); } return $this->startup['main']; } /** * Retrieve the executable associated with this runtime. * * @return string */ public function getExecutable() { if (NULL === $this->executable) { // Lazy-init $this->executable= Process::getProcessById(getmypid(), getenv('XP_RT')); } return $this->executable; } } ?> backing default array() */ public function __construct($backing= array()) { $this->backing= $backing; } /** * Set switch (e.g. "-q") * * @param string name switch name without leading dash * @return lang.RuntimeOptions this object */ public function withSwitch($name) { $this->backing["\0".$name]= TRUE; return $this; } /** * Get switch (e.g. "-q") * * @param string name switch name without leading dash * @param bool default default FALSE * @return bool */ public function getSwitch($name, $default= FALSE) { $key= "\0".$name; return isset($this->backing[$key]) ? $this->backing[$key] : $default ; } /** * Get setting (e.g. "include_path") * * @param string name * @param string[] default default NULL * @return string[] values */ public function getSetting($name, $default= NULL) { $key= 'd'.$name; return isset($this->backing[$key]) ? $this->backing[$key] : $default ; } /** * Set setting (e.g. "include_path") * * @param string setting * @param var value either a number, a string or an array of either * @param bool add default FALSE * @return lang.RuntimeOptions this object */ public function withSetting($setting, $value, $add= FALSE) { $key= 'd'.$setting; if ($add && isset($this->backing[$key])) { $this->backing[$key]= array_merge($this->backing[$key], (array)$value); } else { $this->backing[$key]= (array)$value; } return $this; } /** * Return an array suitable for passing to lang.Process' constructor * * @return string[] */ public function asArguments() { $s= array(); foreach ($this->backing as $key => $value) { if ("\0" === $key{0}) { $s[]= '-'.substr($key, 1); } else { foreach ($value as $v) { $s[]= '-'.$key.'='.$v; } } } return $s; } /** * Creates a string representation of these options * * @return string */ public function toString() { return $this->getClassName().'@'.xp::stringOf($this->asArguments()); } /** * Returns whether another object is equal to these options * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->backing === $cmp->backing; } } ?> file = $file; $this->class = $class; $this->method = $method; $this->line = $line; $this->args = $args; $this->message = $message; } /** * Returns qualified class name * * @param string class unqualified name * @return string */ protected function qualifiedClassName($class) { return xp::nameOf($class); } /** * Create string representation * * @return string */ public function toString() { $args= array(); if (isset($this->args)) { for ($j= 0, $a= sizeof($this->args); $j < $a; $j++) { if (is_array($this->args[$j])) { $args[]= 'array['.sizeof($this->args[$j]).']'; } else if (is_object($this->args[$j])) { $args[]= $this->qualifiedClassName(get_class($this->args[$j])).'{}'; } else if (is_string($this->args[$j])) { $display= str_replace('%', '%%', addcslashes(substr($this->args[$j], 0, min( (FALSE === $p= strpos($this->args[$j], "\n")) ? 0x40 : $p, 0x40 )), "\0..\17")); $args[]= ( '(0x'.dechex(strlen($this->args[$j])).")'". $display. "'" ); } else if (is_null($this->args[$j])) { $args[]= 'NULL'; } else if (is_scalar($this->args[$j])) { $args[]= (string)$this->args[$j]; } else if (is_resource($this->args[$j])) { $args[]= (string)$this->args[$j]; } else { $args[]= '<'.gettype($this->args[$j]).'>'; } } } return sprintf( " at %s::%s(%s) [line %d of %s] %s\n", isset($this->class) ? $this->qualifiedClassName($this->class) : '
    ', isset($this->method) ? $this->method : '
    ', implode(', ', $args), $this->line, basename(isset($this->file) ? $this->file : __FILE__), $this->message ); } /** * Compares this stacktrace element to another object * * @param lang.Object cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->toString() == $cmp->toString(); } } ?> * php.version PHP version * php.api PHP api * os.name Operating system name * os.tempdir System-wide temporary directory * host.name Host name * host.arch Host architecture * user.home Current user's home directory * user.name Current user's name * file.separator File separator ("/" on UNIX) * path.separator Path separator (":" on UNIX) * * * @param string name * @return mixed */ public static function getProperty($name) { static $prop= array(); if (!isset($prop[$name])) switch ($name) { case 'php.version': $prop[$name]= PHP_VERSION; break; case 'php.api': $prop[$name]= PHP_SAPI; break; case 'os.name': $prop[$name]= PHP_OS; break; case 'os.tempdir': $prop[$name]= self::tempDir(); break; case 'host.name': if (extension_loaded('posix')) { $uname= posix_uname(); $prop[$name]= $uname['nodename'].(isset ($uname['domainname']) ? '.'.$uname['domainname'] : '' ); break; } $prop[$name]= self::_env('HOSTNAME', 'COMPUTERNAME'); break; case 'host.arch': if (extension_loaded('posix')) { $uname= posix_uname(); $prop[$name]= $uname['machine']; break; } $prop[$name]= self::_env('HOSTTYPE', 'PROCESSOR_ARCHITECTURE'); break; case 'user.home': if (extension_loaded('posix')) { $pwuid= posix_getpwuid(posix_getuid()); $prop[$name]= $pwuid['dir']; break; } $prop[$name]= str_replace('\\', DIRECTORY_SEPARATOR, self::_env('HOME', 'HOMEPATH')); break; case 'user.name': $prop[$name]= get_current_user(); break; case 'file.separator': return DIRECTORY_SEPARATOR; case 'path.separator': return PATH_SEPARATOR; } return $prop[$name]; } /** * Sets an environment variable * * @param string name * @param mixed var * @return bool success */ public static function putEnv($name, $var) { return putenv($name.'='.$var); } /** * Returns the contents of an environment variable, or in case it does * not exist, FALSE. * * @param string name * @return mixed var */ public static function getEnv($name) { return getenv($name); } /** * Retrieve location of temporary directory. This method looks at the * environment variables TEMP and TMP, and, if these cannot be found, * uses '/tmp' as location on Un*x systems, c:\ on Windows. * * @see php://tempnam * @return string */ public static function tempDir() { if (getenv('TEMP')) { $dir= getenv('TEMP'); } else if (getenv('TMP')) { $dir= getenv('TMP'); } else { $dir= (0 == strcasecmp(substr(PHP_OS, 0, 3), 'WIN')) ? 'c:\\' : '/tmp'; } return rtrim($dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } /** * Execute an external program * * Copied from man bash, some information on the exit code *
         * EXIT STATUS
         * For  the  shell's  purposes,  a command which exits with a
         * zero exit status has succeeded.  An exit  status  of  zero
         * indicates success.  A non-zero exit status indicates fail
         * ure.  When a command terminates on a fatal signal N,  bash
         * uses the value of 128+N as the exit status.
         *
         * If  a  command  is not found, the child process created to
         * execute it returns a status of 127.  If a command is found
         * but is not executable, the return status is 126.
         *
         * If a command fails because of an error during expansion or
         * redirection, the exit status is greater than zero.
         *
         * Shell builtin commands return a status of 0 (true) if suc
         * cessful,  and  non-zero  (false)  if an error occurs while
         * they execute.  All builtins return an exit status of 2  to
         * indicate incorrect usage.
         *
         * Bash  itself  returns  the exit status of the last command
         * executed, unless a syntax error occurs, in which  case  it
         * exits  with  a  non-zero value.  See also the exit builtin
         * command below.
         * 
    * * @param string cmdLine the command * @param string redirect default '2>&1' redirection * @param bool background * @return array lines * @throws lang.SystemException in case the return code is not zero * @see php://exec * @see xp://lang.Process */ public static function exec($cmdLine, $redirect= '2>&1', $background= FALSE) { $cmdLine= escapeshellcmd($cmdLine).' '.$redirect.($background ? ' &' : ''); if (!($pd= popen($cmdLine, 'r'))) throw(new XPException( 'cannot execute "'.$cmdLine.'"' )); $buf= array(); while ( (!feof($pd)) && (FALSE !== ($line= fgets($pd, 4096))) ) { $buf[]= chop($line); } $retCode= (pclose($pd) >> 8) & 0xFF; if ($retCode != 0) throw(new SystemException( 'System.exec('.$cmdLine.') err #'.$retCode.' ['.implode('', $buf).']', $retCode )); return $buf; } } ?> code= $code; } } ?> * uses('lang.Thread'); * * class TimerThread extends Thread { * public * $ticks = 0, * $timeout = 0; * * public function __construct($timeout) { * $this->timeout= $timeout; * parent::__construct('timer.'.$timeout); * } * * public function run() { * while ($this->ticks < $this->timeout) { * Thread::sleep(1000); * $this->ticks++; * printf("<%s> tick\n", $this->name); * } * printf("<%s> time's up!\n", $this->name); * } * } * * $t[0]= new TimerThread(5); * $t[0]->start(); * $t[1]= new TimerThread(2); * $t[1]->start(); * * for ($i= 0; $i < 3; $i++) { * echo "
    Waiting...\n"; * sleep(1); * } * * $t[0]->join(); * $t[1]->join(); * * * @ext pcntl * @ext posix * @see http://news.xp-framework.net/article/168/2007/04/05/ * @see xp://lang.Runnable * @purpose Base class */ class Thread extends Object { public $name = '', $running = FALSE; protected $target = NULL, $_id = -1, $_pid = -1; /** * Constructor * * Implementation by subclassing: * * class ComputeThread extends Thread { * public function run() { * // ... * } * } * * $thread= new ComputeThread('computr1'); * $thread->start(); * * * Implementation by passing a Runnable: * * $thread= new Thread(newinstance('lang.Runnable', array(), '{ * public function run() { * // ... * } * }')); * $thread->start(); * * * @param mixed arg default NULL */ public function __construct($arg= NULL) { if ($arg instanceof Runnable) { $this->target= $arg; $this->name= $arg->getClassName(); } else { $this->target= $this; $this->name= $arg ? $arg : $this->getClassName(); } } /** * Returns whether this thread is running * * @return bool */ public function isRunning() { return $this->running; } /** * Set Name * * @param string name */ public function setName($name) { $this->name= $name; } /** * Get Name * * @return string */ public function getName() { return $this->name; } /** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds. * * @param int millis */ public static function sleep($millis) { usleep($millis * 1000); } /** * Starts thread execution * * @throws lang.IllegalThreadStateException if this thread is already running * @throws lang.SystemException if the thread cannot be started */ public function start() { if ($this->isRunning()) { throw new IllegalThreadStateException('Already running'); } $parent= getmypid(); $pid= pcntl_fork(); if (-1 == $pid) { // Cannot fork throw new SystemException('Cannot fork'); } else if ($pid) { // Parent $this->running= TRUE; $this->_id= $pid; $this->_pid= $parent; } else { // Child $this->running= TRUE; $this->_id= getmypid(); $this->_pid= $parent; call_user_func(array($this->target, 'run')); exit(); } } /** * Join this thread. The optional parameter wait may be set to FALSE to * return immediately if this thread hasn't terminated yet. * * @param bool wait default TRUE * @return int status * @see php://pcntl_waitpid */ public function join($wait= TRUE) { if (!$this->isRunning()) { throw new IllegalThreadStateException('Cannot join no longer running thread.'); } if (0 == pcntl_waitpid($this->_id, $status, $wait ? WUNTRACED : WNOHANG)) return -1; $this->running= FALSE; return $status; } /** * Stop this thread * * @param int signal default SIGINT * @throws lang.IllegalThreadStateException */ public function stop($signal= SIGINT) { if (!$this->isRunning()) { throw new IllegalThreadStateException('Cannot stop no longer running thread.'); } posix_kill($this->_id, $signal); $this->running= FALSE; } /** * Returns thread id of running or already stopped thread * * @return int */ public function getId() { return $this->_id; } /** * Returns thread's parent id * * @return int */ public function getParentId() { return $this->_pid; } /** * Creates a string representation * * @return string */ public function toString() { return sprintf('%s[%s%d]@%s', $this->getClassName(), $this->running() ? 'R' : 'S', $this->_id, xp::stringOf($this)); } /** * Subclasses of Thread should override this method. * */ public function run() { } } ?> 1, 'call_user_func' => 1, 'object' => 1 ); $this->__id= microtime(); $this->message= $message; $errors= xp::$registry['errors']; foreach (debug_backtrace() as $trace) { if (!isset($trace['function']) || isset($except[$trace['function']])) continue; if (isset($trace['object']) && '__construct' == $trace['function'] && $trace['object'] instanceof self) continue; // Not all of these are always set: debug_backtrace() should // initialize these - at least - to NULL, IMO => Workaround. $this->addStackTraceFor( isset($trace['file']) ? $trace['file'] : NULL, isset($trace['class']) ? $trace['class'] : NULL, isset($trace['function']) ? $trace['function'] : NULL, isset($trace['line']) ? $trace['line'] : NULL, isset($trace['args']) ? $trace['args'] : NULL, array(array('' => 1)) ); } // Remaining error messages foreach ($errors as $file => $list) { $this->addStackTraceFor($file, NULL, NULL, NULL, array(), $list); } } /** * Adds new stacktrace elements to the internal list of stacktrace * elements, each for one error. * * @param string file * @param string class * @param string function * @param int originalline * @param mixed[] args * @param mixed[] errors */ protected function addStackTraceFor($file, $class, $function, $originalline, $args, $errors) { foreach ($errors as $line => $errormsg) { foreach ($errormsg as $message => $details) { if (is_array($details)) { $class= $details['class']; $function= $details['method']; $amount= $details['cnt']; } else { $amount= $details; } $this->trace[]= new StackTraceElement( $file, $class, $function, $originalline ? $originalline : $line, $args, $message.($amount > 1 ? ' (... '.($amount - 1).' more)' : '') ); } } } /** * Return an array of stack trace elements * * @return lang.StackTraceElement[] array of stack trace elements * @see xp://lang.StackTraceElement */ public function getStackTrace() { return $this->trace; } /** * Print "stacktrace" to standard error * * @see xp://lang.Throwable#toString * @param resource fd default STDERR */ public function printStackTrace($fd= STDERR) { fputs($fd, $this->toString()); } /** * Return compound message of this exception. In this default * implementation, returns the following: * *
         *   Exception [FULLY-QUALIFIED-CLASSNAME] ([MESSAGE])
         * 
    * * May be overriden by subclasses * * @return string */ public function compoundMessage() { return sprintf( 'Exception %s (%s)', $this->getClassName(), $this->message ); } /** * Return compound message followed by the formatted output of this * exception's stacktrace. * * Example: *
         * Exception lang.ClassNotFoundException (class "" [] not found)
         *   at lang.ClassNotFoundException::__construct((0x15)'class "" [] not found') \
         *   [line 79 of StackTraceElement.class.php] 
         *   at lang.ClassLoader::loadclass(NULL) [line 143 of XPClass.class.php] 
         *   at lang.XPClass::forname(NULL) [line 6 of base_test.php] \
         *   Undefined variable:  nam
         * 
    * * Usually not overridden by subclasses unless stacktrace format * should differ - otherwise overwrite compoundMessage() instead!. * * @return string */ public function toString() { $s= $this->compoundMessage()."\n"; for ($i= 0, $t= sizeof($this->trace); $i < $t; $i++) { $s.= $this->trace[$i]->toString(); } return $s; } /** * Returns a hashcode for this object * * @return string */ public function hashCode() { return $this->__id; } /** * Indicates whether some other object is "equal to" this one. * * @param lang.Object cmp * @return bool TRUE if the compared object is equal to this object */ public function equals($cmp) { return $this === $cmp; } /** * Returns the fully qualified class name for this class * (e.g. "io.File") * * @return string fully qualified class name */ public function getClassName() { return xp::nameOf(get_class($this)); } /** * Returns the runtime class of an object. * * @return lang.XPClass runtime class * @see xp://lang.XPClass */ public function getClass() { return new XPClass($this); } } ?> name= $name; } /** * Retrieves the fully qualified class name for this class. * * @return string name - e.g. "io.File", "rdbms.mysql.MySQL" */ public function getName() { return $this->name; } /** * Creates a string representation of this object * * @return string */ public function toString() { return $this->getClassName().'<'.$this->name.'>'; } /** * Checks whether a given object is equal to this type * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $cmp->name === $this->name; } /** * Returns a hashcode for this object * * @return string */ public function hashCode() { return get_class($this).':'.$this->name; } /** * Gets a type for a given name * * Checks for: *
      *
    • Primitive types (string, integer, double, boolean, array)
    • *
    • Array notations (string[] or string*)
    • *
    • Resources
    • *
    • Any type (mixed or *)
    • *
    • Generic notations (util.collections.HashTable)
    • *
    • Anything else will be passed to XPClass::forName()
    • *
    * * @param string name * @return lang.Type */ public static function forName($name) { switch ($name) { case 'string': case 'char': return Primitive::$STRING; case 'integer': case 'int': return Primitive::$INTEGER; case 'double': case 'float': return Primitive::$DOUBLE; case 'boolean': case 'bool': return Primitive::$BOOLEAN; case '*': case 'mixed': return self::$ANY; case 'array': case '*' == substr($name, -1): case '[]' === substr($name, -2): return Primitive::$ARRAY; case 'resource': // XXX FIXME return Primitive::$INTEGER; case 'void': return self::$VOID; case FALSE !== ($p= strpos($name, '<')): $base= substr($name, 0, $p); return 'array' == $base ? Primitive::$ARRAY : XPClass::forName($base); case FALSE === strpos($name, '.'): return new XPClass(new ReflectionClass($name)); default: return XPClass::forName($name); } } } ?> values or an int => size * @return lang.types.ArrayList */ public static function newInstance($arg) { if (is_array($arg)) { $self= new self(); $self->values= array_values($arg); $self->length= sizeof($self->values); } else { $self= new self(); $self->length= (int)$arg; } return $self; } /** * Returns a hashcode for this number * * @return string */ public function hashCode() { return $this->length.'['.serialize($this->values); } /** * Constructor * * @param mixed* values */ public function __construct() { if (0 != ($this->length= func_num_args())) { $this->values= func_get_args(); } } /** * Returns an iterator for use in foreach() * * @see php://language.oop5.iterations * @return php.Iterator */ public function getIterator() { if (!$this->iterator) $this->iterator= newinstance('Iterator', array($this), '{ private $i= 0, $v; public function __construct($v) { $this->v= $v; } public function current() { return $this->v->values[$this->i]; } public function key() { return $this->i; } public function next() { $this->i++; } public function rewind() { $this->i= 0; } public function valid() { return $this->i < $this->v->length; } }'); return $this->iterator; } /** * = list[] overloading * * @param int offset * @return mixed * @throws lang.IndexOutOfBoundsException if key does not exist */ public function offsetGet($offset) { if ($offset >= $this->length || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } return $this->values[$offset]; } /** * list[]= overloading * * @param int offset * @param mixed value * @throws lang.IllegalArgumentException if key is neither numeric (set) nor NULL (add) */ public function offsetSet($offset, $value) { if (!is_int($offset)) { throw new IllegalArgumentException('Incorrect type '.gettype($offset).' for index'); } if ($offset >= $this->length || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } $this->values[$offset]= $value; } /** * isset() overloading * * @param int offset * @return bool */ public function offsetExists($offset) { return ($offset >= 0 && $offset < $this->length); } /** * unset() overloading * * @param int offset */ public function offsetUnset($offset) { throw new IllegalArgumentException('Cannot remove from immutable list'); } /** * Helper method to compare two arrays recursively * * @param array a1 * @param array a2 * @return bool */ protected function arrayequals($a1, $a2) { if (sizeof($a1) != sizeof($a2)) return FALSE; foreach (array_keys((array)$a1) as $k) { switch (TRUE) { case !array_key_exists($k, $a2): return FALSE; case is_array($a1[$k]): if (!$this->arrayequals($a1[$k], $a2[$k])) return FALSE; break; case $a1[$k] instanceof Generic: if (!$a1[$k]->equals($a2[$k])) return FALSE; break; case $a1[$k] !== $a2[$k]: return FALSE; } } return TRUE; } /** * Checks whether a given object is equal to this arraylist * * @param lang.Object cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->arrayequals($this->values, $cmp->values); } /** * Returns a string representation of this object * * @return string */ public function toString() { return ( $this->getClassName().'['.sizeof($this->values)."]@{". implode(', ', array_map(array('xp', 'stringOf'), $this->values)). '}' ); } } ?> value= (bool)$value; } /** * Returns the value of this number as an int. * * @return int */ public function intValue() { return (int)$this->value; } /** * Returns a hashcode for this number * * @return string */ public function hashCode() { return $this->value ? 'true' : 'false'; } /** * Returns a string representation of this number object * * @return string */ public function toString() { return $this->getClassName().'('.$this->value.')'; } /** * Indicates whether some other object is "equal to" this one. * * @param lang.Object cmp * @return bool TRUE if the compared object is equal to this object */ public function equals($cmp) { return $cmp instanceof self && $this->value === $cmp->value; } } ?> value) : $in{0}) ; } /** * Constructor * * @param mixed initial default NULL * @throws lang.IllegalArgumentException in case argument is of incorrect type. */ public function __construct($initial= NULL) { if (NULL === $initial) { // Intentionally empty } else if (is_array($initial)) { $this->buffer= implode('', array_map(array($this, 'asByte'), $initial)); } else if (is_string($initial)) { $this->buffer= $initial; } else { throw new IllegalArgumentException('Expected either Byte[], char[], int[] or string'); } $this->size= strlen($this->buffer); } /** * Returns an iterator for use in foreach() * * @see php://language.oop5.iterations * @return php.Iterator */ public function getIterator() { if (!$this->iterator) $this->iterator= newinstance('Iterator', array($this), '{ private $i= 0, $v; public function __construct($v) { $this->v= $v; } public function current() { $n= ord($this->v->buffer{$this->i}); return new Byte($n < 128 ? $n : $n - 256); } public function key() { return $this->i; } public function next() { $this->i++; } public function rewind() { $this->i= 0; } public function valid() { return $this->i < $this->v->size; } }'); return $this->iterator; } /** * = list[] overloading * * @param int offset * @return lang.types.Byte * @throws lang.IndexOutOfBoundsException if offset does not exist */ public function offsetGet($offset) { if ($offset >= $this->size || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } $n= ord($this->buffer{$offset}); return new Byte($n < 128 ? $n : $n - 256); } /** * list[]= overloading * * @param int offset * @param mixed value * @throws lang.IllegalArgumentException if key is neither numeric (set) nor NULL (add) * @throws lang.IndexOutOfBoundsException if key does not exist */ public function offsetSet($offset, $value) { if (NULL === $offset) { $this->buffer.= $this->asByte($value); $this->size++; } else if ($offset >= $this->size || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } else { $this->buffer{$offset}= $this->asByte($value); } } /** * isset() overloading * * @param int offset * @return bool */ public function offsetExists($offset) { return ($offset >= 0 && $offset < $this->size); } /** * unset() overloading * * @param int offset * @throws lang.IndexOutOfBoundsException if offset does not exist */ public function offsetUnset($offset) { if ($offset >= $this->size || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } $this->buffer= ( substr($this->buffer, 0, $offset). substr($this->buffer, $offset+ 1, $this->size) ); $this->size--; } /** * Returns this byte list's size * * @return string */ public function size() { return $this->size; } /** * Returns whether a given object is equal to this object * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return ( $cmp instanceof self && $this->size === $cmp->size && $this->buffer === $cmp->buffer ); } /** * Returns a hashcode for this bytes object * * @return string */ public function hashCode() { return md5($this->buffer); } /** * Returns a string representation of this string. * * @return string */ public function toString() { return $this->getClassName().'('.$this->size.')@{'.addcslashes($this->buffer, "\0..\37\177..\377").'}'; } /** * String conversion overloading. This is for use with fwrite() * * @return string */ public function __toString() { return $this->buffer; } } ?> * $c= new Character(8364); // The EUR symbol (U+20AC) * $c= new Character(0x20AC); // ...same, using hexadecimal * $c= new Character('', 'ISO-8859-1'); // The German Umlaut A (capital) * * $s= new String('bercoder', 'ISO-8859-1'); * $c= $s->charAt(0); // The German Umlaut U (capital) * $c= $s[0]; // ...same, via [] operator * * $c= $s->charAt(1); // "b" * $c= $s[1]; // "b" * * * @ext iconv * @test xp://net.xp_framework.unittest.core.types.CharacterTest * @purpose Wrapper type */ class Character extends Object { protected $buffer= ''; /** * Constructor * * @param mixed arg either a string or an int * @param string charset default NULL */ public function __construct($arg, $charset= NULL) { if (is_int($arg)) { $this->buffer= iconv('UCS-4BE', 'UTF-8', pack('N', $arg)); return; } $charset= strtoupper($charset ? $charset : iconv_get_encoding('input_encoding')); // Convert the input to internal encoding $this->buffer= iconv($charset, 'UTF-8', $arg); if (xp::errorAt(__FILE__, __LINE__ - 1)) { $message= key(xp::$registry['errors'][__FILE__][__LINE__ - 2]); xp::gc(); throw new FormatException($message.($charset == 'UTF-8' ? ' with charset '.$charset : $message.' while converting input from '.$charset.' to '.'UTF-8' )); } if (1 != ($l= iconv_strlen($this->buffer, 'UTF-8'))) { throw new IllegalArgumentException('Given argument is too long ('.$l.')'); } } /** * Returns whether a given object is equal to this object * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->buffer === $cmp->buffer; } /** * Returns a hashcode for this string object * * @return string */ public function hashCode() { return $this->buffer; } /** * Returns a string representation of this string. Uses the current * output encoding and transliteration. * * @return string */ public function toString() { return iconv('UTF-8', iconv_get_encoding('output_encoding').'//TRANSLIT', $this->buffer); } /** * Returns a string representation of this string. Uses the current * output encoding and transliteration. * * @return string */ public function __toString() { return iconv(STR_ENC, iconv_get_encoding('output_encoding').'//TRANSLIT', $this->buffer); } /** * Returns the bytes representing this character * * @param string charset default NULL * @return lang.types.Bytes */ public function getBytes($charset= NULL) { $charset= strtoupper($charset ? $charset : iconv_get_encoding('input_encoding')); return new Bytes(STR_ENC === $charset ? $this->buffer : iconv(STR_ENC, $charset, $this->buffer) ); } } ?> value= (string)$value; } /** * Returns the value of this number as an int. * * @return int */ public function intValue() { return (int)$this->value; } /** * Returns the value of this number as a float. * * @return float */ public function floatValue() { return (float)$this->value; } /** * Returns a hashcode for this number * * @return string */ public function hashCode() { return $this->value; } /** * Returns a string representation of this number object * * @return string */ public function toString() { return $this->getClassName().'('.$this->value.')'; } /** * Indicates whether some other object is "equal to" this one. * * @param lang.Object cmp * @return bool TRUE if the compared object is equal to this object */ public function equals($cmp) { return $cmp instanceof $this && $this->value === $cmp->value; } } ?> *
  • Byte
  • *
  • Float
  • *
  • Long
  • *
  • Short
  • *
  • Integer
  • * * ...and map to whatever the "remote" type is defined as. They all take * strings as arguments to preserve the value exactly. The respective * classes extend from the base class lang.reflect.Number. * * ArrayList * ========= * This class represents a zero-indexed list of elements of any type. * It is used to give marshalling utilities an easy way to see whether * an array is "numeric" or not (PHP's array types can be either numeric, * hashes or a mix of both and aren't necessarily zero-indexed). * * @see http://news.xp-framework.net/article/52/2005/05/29/ * @see http://news.xp-framework.net/article/54/2005/06/12/ * @see http://developer.xp-framework.net/xml/rfc/view?0038 * @see xp://lang.types.Number * @see xp://lang.types.ArrayList * @purpose Type wrappers */ package lang.types { } buffer; } else if ($arg instanceof Character) { return $arg->getBytes(STR_ENC)->buffer; } else if (is_string($arg) || $arg instanceof Bytes) { $charset= strtoupper($charset ? $charset : iconv_get_encoding('input_encoding')); // Convert the input to internal encoding $buffer= iconv($charset, STR_ENC, $arg); if (xp::errorAt(__FILE__, __LINE__ - 1)) { $message= key(xp::$registry['errors'][__FILE__][__LINE__ - 2]); xp::gc(); throw new FormatException($message.($charset == STR_ENC ? ' with charset '.$charset : $message.' while converting input from '.$charset.' to '.STR_ENC )); } return $buffer; } else { return (string)$arg; } } /** * Constructor * * @param string initial default '' * @param string charset default NULL */ public function __construct($initial= '', $charset= NULL) { $this->buffer= $this->asIntern($initial, $charset); $this->length= iconv_strlen($this->buffer, STR_ENC); } /** * = list[] overloading * * @param int offset * @return lang.types.Character * @throws lang.IndexOutOfBoundsException if key does not exist */ public function offsetGet($offset) { return $this->charAt($offset); } /** * list[]= overloading * * @param int offset * @param mixed value * @throws lang.IllegalArgumentException if key is neither numeric (set) nor NULL (add) */ public function offsetSet($offset, $value) { if (!is_int($offset)) { throw new IllegalArgumentException('Incorrect type '.gettype($offset).' for index'); } if ($offset >= $this->length || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } $char= $this->asIntern($value); if (1 != iconv_strlen($char, STR_ENC)) { throw new IllegalArgumentException('Set only allows to set one character!'); } $this->buffer= ( iconv_substr($this->buffer, 0, $offset, STR_ENC). $char. iconv_substr($this->buffer, $offset+ 1, $this->length, STR_ENC) ); } /** * isset() overloading * * @param int offset * @return bool */ public function offsetExists($offset) { return ($offset >= 0 && $offset < $this->length); } /** * unset() overloading * * @param int offset */ public function offsetUnset($offset) { if ($offset >= $this->length || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } $this->buffer= ( iconv_substr($this->buffer, 0, $offset, STR_ENC). iconv_substr($this->buffer, $offset+ 1, $this->length, STR_ENC) ); $this->length= iconv_strlen($this->buffer, STR_ENC); } /** * Returns the string's length (the number of characters in this * string, not the number of bytes) * * @return string */ public function length() { return $this->length; } /** * Returns the character at the given position * * @param int offset * @return lang.types.Character * @throws lang.IndexOutOfBoundsException if key does not exist */ public function charAt($offset) { if ($offset >= $this->length || $offset < 0) { raise('lang.IndexOutOfBoundsException', 'Offset '.$offset.' out of bounds'); } return new Character(iconv_substr($this->buffer, $offset, 1, STR_ENC), STR_ENC); } /** * Returns the index within this string of the first occurrence of * the specified substring. * * @param mixed arg either a string or a String * @param int start default 0 * @return bool */ public function indexOf($arg, $start= 0) { $r= iconv_strpos($this->buffer, $this->asIntern($arg), $start, STR_ENC); return FALSE === $r ? -1 : $r; } /** * Returns the index within this string of the last occurrence of * the specified substring. * * @param mixed arg either a string or a String * @return bool */ public function lastIndexOf($arg) { $r= iconv_strrpos($this->buffer, $this->asIntern($arg), STR_ENC); return FALSE === $r ? -1 : $r; } /** * Returns a new string that is a substring of this string. * * @param int start * @param int length default 0 * @return lang.types.String */ public function substring($start, $length= 0) { if (0 === $length) $length= $this->length; return new self(iconv_substr($this->buffer, $start, $length, STR_ENC), STR_ENC); } /** * Returns whether a given substring is contained in this string * * @param mixed arg * @return bool */ public function contains($arg) { return -1 != $this->indexOf($arg); } /** * Returns whether a given substring is contained in this string * * @param mixed old * @param mixed new default '' * @return lang.types.String this string */ public function replace($old, $new= '') { $this->buffer= str_replace($this->asIntern($old), $this->asIntern($new), $this->buffer); $this->length= iconv_strlen($this->buffer, STR_ENC); return $this; } /** * Concatenates the given argument to the end of this string and returns * this String so it can be used in chained calls: * * * $s= new String('Hello'); * $s->concat(' ')->concat('World'); * * * @param mixed arg * @return lang.types.String this string */ public function concat($arg) { $this->buffer.= $this->asIntern($arg); $this->length= iconv_strlen($this->buffer, STR_ENC); return $this; } /** * Returns whether this string starts with a given argument. * * @param mixed arg either a string or a String * @return bool */ public function startsWith($arg) { return 0 == $this->indexOf($arg); } /** * Returns whether this string starts with a given argument. * * @param mixed arg either a string or a String * @return bool */ public function endsWith($arg) { $bytes= $this->asIntern($arg); return ( iconv_strlen($this->buffer, STR_ENC) - iconv_strlen($bytes, STR_ENC) === iconv_strrpos($this->buffer, $bytes, STR_ENC) ); } /** * Returns whether a given object is equal to this object * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->buffer === $cmp->buffer; } /** * Returns a hashcode for this string object * * @return string */ public function hashCode() { return md5($this->buffer); } /** * Returns a string representation of this string. Uses the current * output encoding and transliteration. * * @return string */ public function toString() { return iconv(STR_ENC, iconv_get_encoding('output_encoding').'//TRANSLIT', $this->buffer); } /** * Returns a string representation of this string. Uses the current * output encoding and transliteration. * * @return string */ public function __toString() { return iconv(STR_ENC, iconv_get_encoding('output_encoding').'//TRANSLIT', $this->buffer); } /** * Returns the bytes representing this string * * @param string charset default 'UTF-8' * @return lang.types.Bytes */ public function getBytes($charset= NULL) { $charset= strtoupper($charset ? $charset : iconv_get_encoding('input_encoding')); return new Bytes(STR_ENC === $charset ? $this->buffer : iconv(STR_ENC, $charset, $this->buffer) ); } } ?> getClass() syntax or the static method * $class= XPClass::forName('fully.qualified.Name') * * Examples * ======== * To retrieve the fully qualified name of a class, use this: * * $o= new File('...'); * echo 'The class name for $o is '.$o->getClass()->getName(); * * * Create an instance of a class: * * $instance= XPClass::forName('util.Binford')->newInstance(); * * * Invoke a method by its name: * * try { * $instance->getClass()->getMethod('connect')->invoke($instance); * } catch (TargetInvocationException $e) { * $e->getCause()->printStackTrace(); * } * * * @see xp://lang.Object#getClass * @see xp://lang.XPClass#forName * @test xp://net.xp_framework.unittest.reflection.ReflectionTest * @test xp://net.xp_framework.unittest.reflection.ClassDetailsTest * @purpose Reflection */ class XPClass extends Type { protected $_class = NULL; public $_reflect = NULL; /** * Constructor * * @param mixed ref either a class name, a ReflectionClass instance or an object */ public function __construct($ref) { if ($ref instanceof ReflectionClass) { $this->_class= $ref->getName(); $this->_reflect= $ref; } else if (is_object($ref)) { $this->_class= get_class($ref); $this->_reflect= new ReflectionClass($ref); } else { $this->_class= $ref; $this->_reflect= new ReflectionClass($ref); } parent::__construct(xp::nameOf($this->_class)); } /** * Returns simple name * * @return string */ public function getSimpleName() { return FALSE === ($p= strrpos($this->name, '.')) ? $this->name // Already unqualified : substr($this->name, $p+ 1) // Full name ; } /** * Retrieves the package associated with this class * * @return lang.reflect.Package */ public function getPackage() { return Package::forName(substr($this->name, 0, strrpos($this->name, '.'))); } /** * Creates a new instance of the class represented by this Class object. * The class is instantiated as if by a new expression with an empty argument list. * * Example * ======= * * try { * $o= XPClass::forName($name)->newInstance(); * } catch (ClassNotFoundException $e) { * // handle it! * } * * * Example (passing arguments) * =========================== * * try { * $o= XPClass::forName('peer.Socket')->newInstance('localhost', 6100); * } catch (ClassNotFoundException $e) { * // handle it! * } * * * @param mixed* args * @return lang.Object * @throws lang.IllegalAccessException in case this class cannot be instantiated */ public function newInstance() { if ($this->_reflect->isInterface()) { throw new IllegalAccessException('Cannot instantiate interfaces'); } else if ($this->_reflect->isAbstract()) { throw new IllegalAccessException('Cannot instantiate abstract classes'); } try { if (!$this->hasConstructor()) return $this->_reflect->newInstance(); $args= func_get_args(); return $this->_reflect->newInstanceArgs($args); } catch (ReflectionException $e) { throw new IllegalAccessException($e->getMessage()); } } /** * Gets class methods for this class * * @return lang.reflect.Method[] */ public function getMethods() { $list= array(); foreach ($this->_reflect->getMethods() as $m) { if (0 == strncmp('__', $m->getName(), 2)) continue; $list[]= new Method($this->_class, $m); } return $list; } /** * Gets a method by a specified name. * * @param string name * @return lang.reflect.Method * @see xp://lang.reflect.Method * @throws lang.ElementNotFoundException */ public function getMethod($name) { if ($this->hasMethod($name)) { return new Method($this->_class, $this->_reflect->getMethod($name)); } raise('lang.ElementNotFoundException', 'No such method "'.$name.'" in class '.$this->name); } /** * Checks whether this class has a method named "$method" or not. * * Note * ==== * Since in PHP, methods are case-insensitive, calling hasMethod('toString') * will provide the same result as hasMethod('tostring') * * @param string method the method's name * @return bool TRUE if method exists */ public function hasMethod($method) { return ((0 === strncmp('__', $method, 2)) ? FALSE : $this->_reflect->hasMethod($method) ); } /** * Retrieve if a constructor exists * * @return bool */ public function hasConstructor() { return $this->_reflect->hasMethod('__construct'); } /** * Retrieves this class' constructor. * * @return lang.reflect.Constructor * @see xp://lang.reflect.Constructor * @throws lang.ElementNotFoundException */ public function getConstructor() { if ($this->hasConstructor()) { return new Constructor($this->_class, $this->_reflect->getMethod('__construct')); } raise('lang.ElementNotFoundException', 'No constructor in class '.$this->name); } /** * Retrieve a list of all member variables * * @return lang.reflect.Field[] array of field objects */ public function getFields() { $f= array(); foreach ($this->_reflect->getProperties() as $p) { if ('__id' === $p->getName()) continue; $f[]= new Field($this->_class, $p); } return $f; } /** * Retrieve a field by a specified name. * * @param string name * @return lang.reflect.Field * @throws lang.ElementNotFoundException */ public function getField($name) { if ($this->hasField($name)) { return new Field($this->_class, $this->_reflect->getProperty($name)); } raise('lang.ElementNotFoundException', 'No such field "'.$name.'" in class '.$this->name); } /** * Checks whether this class has a field named "$field" or not. * * @param string field the fields's name * @return bool TRUE if field exists */ public function hasField($field) { return '__id' == $field ? FALSE : $this->_reflect->hasProperty($field); } /** * Retrieve the parent class's class object. Returns NULL if there * is no parent class. * * @return lang.XPClass class object */ public function getParentclass() { return ($parent= $this->_reflect->getParentClass()) ? new self($parent) : NULL; } /** * Checks whether this class has a constant named "$constant" or not * * @param string constant * @return bool */ public function hasConstant($constant) { return $this->_reflect->hasConstant($constant); } /** * Retrieve a constant by a specified name. * * @param string constant * @return mixed * @throws lang.ElementNotFoundException in case constant does not exist */ public function getConstant($constant) { if ($this->hasConstant($constant)) { return $this->_reflect->getConstant($constant); } raise('lang.ElementNotFoundException', 'No such constants "'.$constant.'" in class '.$this->name); } /** * Cast a given object to the class represented by this object * * @param lang.Generic expression * @return lang.Generic the given expression * @throws lang.ClassCastException */ public function cast(Generic $expression= NULL) { if (NULL === $expression) { return xp::null(); } else if (is($this->name, $expression)) { return $expression; } raise('lang.ClassCastException', 'Cannot cast '.xp::typeOf($expression).' to '.$this->name); } /** * Tests whether this class is a subclass of a specified class. * * @param * class either a string or an XPClass object * @return bool */ public function isSubclassOf($class) { if (!($class instanceof self)) $class= XPClass::forName($class); if ($class->name == $this->name) return FALSE; // Catch bordercase (ZE bug?) return $this->_reflect->isSubclassOf($class->_reflect); } /** * Determines whether the specified object is an instance of this * class. This is the equivalent of the is() core functionality. * * Examples * ======== * * uses('io.File', 'io.TempFile'); * $class= XPClass::forName('io.File'); * * var_dump($class->isInstance(new TempFile())); // TRUE * var_dump($class->isInstance(new File())); // TRUE * var_dump($class->isInstance(new Object())); // FALSE * * * @param lang.Object obj * @return bool */ public function isInstance($obj) { return is($this->name, $obj); } /** * Determines if this XPClass object represents an interface type. * * @return bool */ public function isInterface() { return $this->_reflect->isInterface(); } /** * Determines if this XPClass object represents an interface type. * * @return bool */ public function isEnum() { $e= xp::reflect('lang.Enum'); return class_exists($e) && $this->_reflect->isSubclassOf($e); } /** * Retrieve interfaces this class implements * * @return lang.XPClass[] */ public function getInterfaces() { $r= array(); foreach ($this->_reflect->getInterfaces() as $iface) { $r[]= new self($iface->getName()); } return $r; } /** * Retrieves the api doc comment for this class. Returns NULL if * no documentation is present. * * @return string */ public function getComment() { if (!($details= self::detailsForClass($this->name))) return NULL; return $details['class'][DETAIL_COMMENT]; } /** * Retrieves this class' modifiers * * @see xp://lang.reflect.Modifiers * @return int */ public function getModifiers() { $r= MODIFIER_PUBLIC; // Map PHP reflection modifiers to generic form $m= $this->_reflect->getModifiers(); $m & ReflectionClass::IS_EXPLICIT_ABSTRACT && $r |= MODIFIER_ABSTRACT; $m & ReflectionClass::IS_IMPLICIT_ABSTRACT && $r |= MODIFIER_ABSTRACT; $m & ReflectionClass::IS_FINAL && $r |= MODIFIER_FINAL; return $r; } /** * Check whether an annotation exists * * @param string name * @param string key default NULL * @return bool */ public function hasAnnotation($name, $key= NULL) { $details= self::detailsForClass($this->name); return $details && ($key ? @array_key_exists($key, @$details['class'][DETAIL_ANNOTATIONS][$name]) : @array_key_exists($name, @$details['class'][DETAIL_ANNOTATIONS]) ); } /** * Retrieve annotation by name * * @param string name * @param string key default NULL * @return mixed * @throws lang.ElementNotFoundException */ public function getAnnotation($name, $key= NULL) { $details= self::detailsForClass($this->name); if (!$details || !($key ? @array_key_exists($key, @$details['class'][DETAIL_ANNOTATIONS][$name]) : @array_key_exists($name, @$details['class'][DETAIL_ANNOTATIONS]) )) return raise( 'lang.ElementNotFoundException', 'Annotation "'.$name.($key ? '.'.$key : '').'" does not exist' ); return ($key ? $details['class'][DETAIL_ANNOTATIONS][$name][$key] : $details['class'][DETAIL_ANNOTATIONS][$name] ); } /** * Retrieve whether a method has annotations * * @return bool */ public function hasAnnotations() { $details= self::detailsForClass($this->name); return $details ? !empty($details['class'][DETAIL_ANNOTATIONS]) : FALSE; } /** * Retrieve all of a method's annotations * * @return array annotations */ public function getAnnotations() { $details= self::detailsForClass($this->name); return $details ? $details['class'][DETAIL_ANNOTATIONS] : array(); } /** * Retrieve the class loader a class was loaded with * * @return lang.IClassLoader */ public function getClassLoader() { return self::_classLoaderFor($this->name); } /** * Fetch a class' classloader by its name * * @param string name fqcn of class * @return lang.IClassLoader */ protected static function _classLoaderFor($name) { sscanf(xp::$registry['classloader.'.$name], '%[^:]://%[^$]', $cl, $argument); return call_user_func(array(xp::reflect($cl), 'instanceFor'), $argument); } /** * Retrieve details for a specified class. Note: Results from this * method are cached! * * @param string class fully qualified class name * @return array or NULL to indicate no details are available */ public static function detailsForClass($class) { if (!$class) return NULL; // Border case if (isset(xp::$registry['details.'.$class])) return xp::$registry['details.'.$class]; // Retrieve class' sourcecode if (!($bytes= self::_classLoaderFor($class)->loadClassBytes($class))) return NULL; $details= array(array(), array()); $annotations= array(); $comment= NULL; $members= TRUE; $tokens= token_get_all($bytes); for ($i= 0, $s= sizeof($tokens); $i < $s; $i++) { switch ($tokens[$i][0]) { case T_DOC_COMMENT: $comment= $tokens[$i][1]; break; case T_COMMENT: if ('#' === $tokens[$i][1]{0}) { // Annotations if ('[' === $tokens[$i][1]{1}) { $annotations[0]= substr($tokens[$i][1], 2); } else { $annotations[0].= substr($tokens[$i][1], 1); } if (']' == substr(rtrim($tokens[$i][1]), -1)) { $annotations= eval('return array('.preg_replace( array('/@([a-z_]+),/i', '/@([a-z_]+)\(\'([^\']+)\'\)/ie', '/@([a-z_]+)\(/i', '/([^a-z_@])([a-z_]+) *= */i'), array('\'$1\' => NULL,', '"\'$1\' => urldecode(\'".urlencode(\'$2\')."\')"', '\'$1\' => array(', '$1\'$2\' => '), trim($annotations[0], "[]# \t\n\r").',' ).');'); } } break; case T_CLASS: case T_INTERFACE: $details['class']= array( DETAIL_COMMENT => trim(preg_replace('/\n \* ?/', "\n", "\n".substr( $comment, 4, // "/**\n" strpos($comment, '* @')- 2 // position of first details token ))), DETAIL_ANNOTATIONS => $annotations ); $annotations= array(); $comment= NULL; break; case T_VARIABLE: if (!$members) break; // Have a member variable $name= substr($tokens[$i][1], 1); $details[0][$name]= array( DETAIL_ANNOTATIONS => $annotations ); $annotations= array(); break; case T_FUNCTION: $members= FALSE; while (T_STRING !== $tokens[$i][0]) $i++; $m= $tokens[$i][1]; $details[1][$m]= array( DETAIL_ARGUMENTS => array(), DETAIL_RETURNS => 'void', DETAIL_THROWS => array(), DETAIL_COMMENT => trim(preg_replace('/\n \* ?/', "\n", "\n".substr( $comment, 4, // "/**\n" strpos($comment, '* @')- 2 // position of first details token ))), DETAIL_ANNOTATIONS => $annotations, DETAIL_NAME => $tokens[$i][1] ); $matches= NULL; preg_match_all( '/@([a-z]+)\s*([^<\r\n]+<[^>]+>|[^\r\n ]+) ?([^\r\n ]+)?/', $comment, $matches, PREG_SET_ORDER ); $annotations= array(); $comment= NULL; foreach ($matches as $match) { switch ($match[1]) { case 'param': $details[1][$m][DETAIL_ARGUMENTS][]= $match[2]; break; case 'return': $details[1][$m][DETAIL_RETURNS]= $match[2]; break; case 'throws': $details[1][$m][DETAIL_THROWS][]= $match[2]; break; } } break; default: // Empty } } // Return details for specified class xp::$registry['details.'.$class]= $details; return $details; } /** * Retrieve details for a specified class and method. Note: Results * from this method are cached! * * @param string class unqualified class name * @param string method * @return array */ public static function detailsForMethod($class, $method) { while ($details= self::detailsForClass(xp::nameOf($class))) { if (isset($details[1][$method])) return $details[1][$method]; $class= get_parent_class($class); } return NULL; } /** * Retrieve details for a specified class and field. Note: Results * from this method are cached! * * @param string class unqualified class name * @param string method * @return array */ public static function detailsForField($class, $field) { while ($details= self::detailsForClass(xp::nameOf($class))) { if (isset($details[0][$field])) return $details[0][$field]; $class= get_parent_class($class); } return NULL; } /** * Returns the XPClass object associated with the class with the given * string name. Uses the default classloader if none is specified. * * @param string name - e.g. "io.File", "rdbms.mysql.MySQL" * @param lang.IClassLoader classloader default NULL * @return lang.XPClass class object * @throws lang.ClassNotFoundException when there is no such class */ public static function forName($name, IClassLoader $classloader= NULL) { if (NULL === $classloader) { $classloader= ClassLoader::getDefault(); } return $classloader->loadClass($name); } /** * Returns an array containing class objects representing all the * public classes * * @return lang.XPClass[] class objects */ public static function getClasses() { $ret= array(); foreach (get_declared_classes() as $name) { if (xp::registry('class.'.$name)) $ret[]= new self($name); } return $ret; } } ?> _instance)) { try { $this->_instance= $this->initialize(); } catch (Throwable $e) { $this->_instance= NULL; throw(new DeferredInitializationException($method, $e)); } } return call_user_func_array(array($this->_instance, $method), $args); } } ?> setPoweredBy($poweredBy); } /** * Set the power * * @param int p power * @throws lang.IllegalArgumentException in case the parameter p contains an illegal value */ public function setPoweredBy($p) { if (!($x= log10($p / 6.1)) || (floor($x) != $x)) { throw(new IllegalArgumentException($p.' not allowed')); } $this->poweredBy= $p; } /** * Retrieve the power * * @return int power */ public function getPoweredBy() { return $this->poweredBy; } /** * Retrieve string representation of this object * * @return string */ public function toString() { return $this->getClassName().'('.$this->poweredBy.')'; } /** * Returns whether another object is equal to this object. * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->poweredBy == $cmp->poweredBy; } /** * Retrieve header suited for HTTP/Mail * * Example: *
         *   X-Binford: 6100 (more power)
         * 
    * * @return peer.Header */ public function getHeader() { return new Header('X-Binford', $this->poweredBy.' (more power)'); } } ?> getTimeZone(); $date= Date::create($year->getYear(), 1, 1, 0, 0, 0); break; } default: { switch ($method) { default: case CAL_DST_EU: $tz= new TimeZone('Europe/Berlin'); break; case CAL_DST_US: $tz= new TimeZone('America/New_York'); break; } $date= ($year == -1 ? Date::now() : Date::create($year, 1, 1, 0, 0, 0) ); break; } } $transition= TimeZoneTransition::nextTransition($tz, $date); while (!$transition->isDst()) { $transition->next(); } return $transition->getDate(); } /** * Calculates end of DST (daylight savings time) * This is the last Sunday of October * * @param int year default -1 Year, defaults to current year * @return util.Date */ public static function dstEnd($year= -1) { $date= ($year == -1 ? Date::now() : Date::create($year, 1, 1, 0, 0, 0) ); $transition= TimeZoneTransition::nextTransition(new TimeZone('Europe/Berlin'), $date); while ($transition->isDst()) { $transition->next(); } return $transition->getDate(); } /** * Retrieve whether a given date object is in daylight savings time. * * @param util.Date date * @param int method default CAL_DST_EU Method to calculate (CAL_DST_EU|CAL_DST_US) * @return bool */ public static function inDst(Date $date) { return (bool)$date->toString('I'); } /** * Calculates the amount of workdays between to dates. Workdays are * defined as Monday through Friday. * * This method takes an optional argument, an array of the following * form: * * * $holidays[gmmktime(...)]= TRUE; * * * @param util.Date start * @param util.Date end * @param array holidays default array() holidays to be included in calculation * @return int number of workdays */ public static function workdays($start, $end, $holidays= array()) { $s= $start->getTime(); $e= $end->getTime(); // For holidays, we have to compare to midnight // else, don't calculate this if (!empty($holidays)) $s-= $s % CAL_SEC_DAY; // Is there a more intelligent way of doing this? $diff= floor(($e - $s) / CAL_SEC_DAY); for ($i= $s; $i <= $e; $i+= CAL_SEC_DAY) { $diff-= ((date('w', $i)+ 6) % 7 > 4 || isset($holidays[$i])); } return $diff+ 1; } /** * Return midnight of a given date * * @param util.Date date * @return util.Date */ public static function midnight($date) { return Date::create( $date->getYear(), $date->getMonth(), $date->getDay(), 0, 0, 0, $date->getTimeZone() ); } /** * Return beginning of month for a given date. E.g., given a date * 2003-06-08, the function will return 2003-06-01 00:00:00. * * @param util.Date date * @return util.Date */ public static function monthBegin($date) { return Date::create( $date->getYear(), $date->getMonth(), 1, 0, 0, 0, $date->getTimeZone() ); } /** * Return end of month for a given date. E.g., given a date * 2003-06-08, the function will return 2003-06-30 23:59:59. * * @param util.Date date * @return util.Date */ public static function monthEnd($date) { return Date::create( $date->getYear(), $date->getMonth() + 1, 0, 23, 59, 59, $date->getTimeZone() ); } /** * Helper method for Calendar::week * * @param int stamp * @param int year * @return int */ protected static function caldiff($stamp, $year) { $d4= mktime(0, 0, 0, 1, 4, $year); return floor(1.05 + ($stamp- $d4) / CAL_SEC_WEEK+ ((date('w', $d4)+ 6) % 7) / 7); } /** * Returns calendar week for a day * * @param util.Date date * @return int calendar week * @see http://www.salesianer.de/util/kalwoch.html */ public static function week($date) { $d= $date->getTime(); $y= $date->getYear() + 1; do { $w= Calendar::caldiff($d, $y); $y--; } while ($w < 1); return (int)$w; } /** * Get first of advent for given year * * @param int year default -1 year, defaults to this year * @return util.Date for date of the first of advent * @see http://www.salesianer.de/util/kalfaq.html */ public static function advent($year= -1) { if (-1 == $year) $year= date('Y'); $s= mktime(0, 0, 0, 11, 26, $year); while (0 != date('w', $s)) { $s+= CAL_SEC_DAY; } return new Date($s); } /** * Get easter date for given year * * @param int year default -1 Year, defaults to this year * @return util.Date date for Easter date * @see http://www.koenigsmuenster.de/rsk/epakte.htm * @see http://www.salesianer.de/util/kalfaq.html * @see php://easter-date#user_contrib */ public static function easter($year= -1) { if (-1 == $year) $year= date('Y'); $g = $year % 19; $c = (int)($year / 100); $h = (int)($c - ($c / 4) - ((8* $c + 13) / 25) + 19 * $g + 15) % 30; $i = (int)$h - (int)($h / 28) * (1 - (int)($h / 28)* (int)(29 / ($h+ 1)) * ((int)(21 - $g) / 11)); $j = ($year + (int)($year / 4) + $i + 2 - $c + (int)($c / 4)) % 7; $l = $i - $j; $m = 3 + (int)(($l + 40) / 44); $d = $l + 28 - 31 * ((int)($m / 4)); return Date::create($year, $m, $d, 0, 0, 0); } /** * Returns whether a year is a leap year * * @param int year * @return bool TRUE if the given year is a leap year */ public static function isLeapYear($year) { return $year % 400 == 0 || ($year > 1582 && $year % 100 == 0 ? FALSE : $year % 4 == 0); } } ?> * uses('util.ChainedException'); * * throw new ChainedException(...); * * The above will acutally throw a lang.ChainedException! * * @purpose BC * @see xp://lang.ChainedException * @deprecated Use lang.ChainedException instead */ class utilChainedException extends XPException { public $cause = NULL; /** * Constructor * * @param string message * @param lang.Throwable cause */ public function __construct($message, $cause) { parent::__construct($message); $this->cause= $cause; } /** * Set cause * * @param lang.Throwable cause */ public function setCause($cause) { $this->cause= $cause; } /** * Get cause * * @return lang.Throwable */ public function getCause() { return $this->cause; } /** * Return string representation of this exception * * @return string */ public function toString() { $s= $this->compoundMessage()."\n"; $t= sizeof($this->trace); for ($i= 0; $i < $t; $i++) { $s.= $this->trace[$i]->toString(); } if (!$this->cause) return $s; $loop= $this->cause; while ($loop) { // String of cause $s.= 'Caused by '.$loop->compoundMessage()."\n"; // Find common stack trace elements for ($ct= $cc= sizeof($loop->trace)- 1, $t= sizeof($this->trace)- 1; $ct > 0, $t > 0; $cc--, $t--) { if (!$loop->trace[$cc]->equals($this->trace[$t])) break; } // Output uncommon elements only and one line how many common elements exist! for ($i= 0; $i < $cc; $i++) { $s.= xp::stringOf($loop->trace[$i]); } if ($cc != $ct) $s.= ' ... '.($ct - $cc + 1)." more\n"; $loop= $loop instanceof ChainedException ? $loop->cause : NULL; } return $s; } } ?> * uses('util.cmd.Console'); * * Console::writeLine('Hello ', 'a', 'b', 1); // Hello ab1 * Console::writeLinef('Hello %s', 'World'); // Hello World * * Console::$out->write('.'); * * * Example: Writing to standard error * * uses('util.cmd.Console'); * * Console::$err->writeLine('*** An error occured: ', $e->toString()); * * * @test xp://net.xp_framework.unittest.util.cmd.ConsoleTest * @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemConsoleClassTopic.asp * @purpose I/O functions */ class Console extends Object { public static $out= NULL, $err= NULL, $in = NULL; static function __static() { self::$in= new StringReader(new ConsoleInputStream(STDIN)); self::$out= new StringWriter(new ConsoleOutputStream(STDOUT)); self::$err= new StringWriter(new ConsoleOutputStream(STDERR)); } /** * Flush output buffer * */ public static function flush() { self::$out->flush(); } /** * Write a string to standard output * * @param mixed* args */ public static function write() { $a= func_get_args(); call_user_func_array(array(self::$out, 'write'), $a); } /** * Write a string to standard output and append a newline * * @param mixed* args */ public static function writeLine() { $a= func_get_args(); call_user_func_array(array(self::$out, 'writeLine'), $a); } /** * Write a formatted string to standard output * * @param string format * @param mixed* args * @see php://printf */ public static function writef() { $a= func_get_args(); call_user_func_array(array(self::$out, 'writef'), $a); } /** * Write a formatted string to standard output and append a newline * * @param string format * @param mixed* args */ public static function writeLinef() { $a= func_get_args(); call_user_func_array(array(self::$out, 'writeLinef'), $a); } /** * Read a line from standard input. The line ending (\r and/or \n) * is trimmed off the end. * * @param string prompt = NULL * @return string */ public static function readLine($prompt= NULL) { $prompt && self::$out->write($prompt.' '); return self::$in->readLine(); } /** * Read a single character from standard input. * * @param string prompt = NULL * @return string */ public static function read($prompt= NULL) { $prompt && self::$out->write($prompt.' '); return self::$in->read(1); } } ?> * uses('util.cmd.Command', 'peer.http.HttpConnection'); * * class Head extends Command { * protected * $conn = NULL, * $verbose = FALSE; * * #[@arg(position= 0)] * public function setUrl($url) { * $this->conn= new HttpConnection($url); * } * * #[@arg] * public function setVerbose() { * $this->verbose= TRUE; * } * * public function run() { * $this->verbose && $this->out->writeLine('Opening connection to ', $this->conn); * $this->out->writeLine($this->conn->head()->toString()); * } * } * * * This can be run with the "xpcli" utility as follows: *
     *   $ xpcli Head http://de3.php.net/ -v
     * 
    * * @see http://news.xp-framework.net/article/205/2007/07/22/ * @purpose CLI */ package util.cmd { } setParams(NULL === $list ? $_SERVER['argv'] : $list); } /** * Set the parameter string * * @param array params */ public function setParams($params) { $this->list= $params; $this->list[-1]= @$_SERVER['_']; $this->count= sizeof($params); $this->string= implode(' ', $params); } /** * Private helper function that iterates through the parameter array * * @param string long long parameter (w/o --) * @param string short default NULL Short parameter (w/o -), defaults to the first char of the long param * @return mixed position on which the parameter is placed or FALSE if nonexistant */ protected function _find($long, $short= NULL) { if (is_null($short)) $short= $long{0}; foreach (array_keys($this->list) as $i) { // Short notation (e.g. -f value) if ($this->list[$i] == '-'.$short) return $i+ 1; // Long notation (e.g. --help, without a value) if ($this->list[$i] == '--'.$long) return $i; // Long notation (e.g. --file=*.txt) if (substr($this->list[$i], 0, strlen($long)+ 3) == '--'.$long.'=') return $i; } return FALSE; } /** * Checks whether a parameter is set * * @see xp://util.Properties#value * @param string long long parameter (w/o --) * @param string short default NULL Short parameter (w/o -), defaults to the first char of the long param * @return boolean */ public function exists($long, $short= NULL) { if (is_int($long)) return isset($this->list[$long]); return ($this->_find($long, $short) !== FALSE); } /** * Retrieve the value of a given parameter * * Examples: * * $p= new ParamString(); * if ($p->exists('help', '?')) { * printf("Usage: %s %s --force-check [--pattern={pattern}]\n", $p->value(-1), $p->value(0)); * exit(-2); * } * * $force= $p->exists('force-check', 'f'); * $pattern= $p->value('pattern', 'p', '.*'); * * // ... * * * @param string long long parameter (w/o --) * @param string short default NULL Short parameter (w/o -), defaults to the first char of the long param * @param string default default NULL A default value if parameter does not exist * @return string * @throws lang.IllegalArgumentException if parameter does not exist and no default value was supplied. */ public function value($long, $short= NULL, $default= NULL) { if (is_int($long)) { if (NULL === $default && !isset($this->list[$long])) { throw new IllegalArgumentException ('Parameter #'.$long.' does not exist'); } return isset($this->list[$long]) ? $this->list[$long] : $default; } $pos= $this->_find($long, $short); if (FALSE === $pos && NULL === $default) { throw new IllegalArgumentException ('Parameter --'.$long.' does not exist'); } // Default usage (eg.: '--with-foo=bar') $length= strlen($long)+ 2; if ($pos !== FALSE && isset($this->list[$pos]) && strncmp('--'.$long, $this->list[$pos], $length) == 0) { // Usage with value (eg.: '--with-foo=bar') if (strlen($this->list[$pos]) > $length && '=' === $this->list[$pos]{$length}) { return substr($this->list[$pos], $length + 1); // Return string after `--{option}=` } // Usage as switch (eg.: '--enable-foo') return NULL; } // Usage in short (eg.: '-v' or '-f /foo/bar') // If the found element is a new parameter, the searched one is used as // flag, so just return TRUE, otherwise return the value. if ($pos !== FALSE && (!isset($this->list[$pos]) || '-' === $this->list[$pos]{0})) { return $default; } return ($pos !== FALSE ? $this->list[$pos] : $default); } } ?> * $ xpcli [options] fully.qualified.class.Name [classoptions] * * * Options includes one of the following: *
       * -c:
       *   Set the path with which the PropertyManager is configured with. The
       *   PropertyManager is used for dependency injection. If a file called
       *   log.ini exists in this path, the Logger will be configured with. If
       *   a database.ini is present there, the ConnectionManager will be
       *   configured with it.
       * 
       * -cp:
       *   Add the path value to the class path.
       * 
    * * @deprecated This class has been moved to tools:xp.command - RFC #0173 * @test xp://net.xp_framework.unittest.util.cmd.RunnerTest * @see xp://util.cmd.Command * @purpose Runner */ class Runner extends Object { private static $out = NULL, $err = NULL; static function __static() { self::$out= new StringWriter(new ConsoleOutputStream(STDOUT)); self::$err= new StringWriter(new ConsoleOutputStream(STDERR)); } /** * Converts api-doc "markup" to plain text w/ ASCII "art" * * @param string markup * @return string text */ protected static function textOf($markup) { $line= str_repeat('=', 72); return strip_tags(preg_replace(array( '#
    #', '#
    #', '#
  • #', ), array( $line, $line, '* ', ), trim($markup))); } /** * Show usage * * @param lang.XPClass class */ public static function showUsage(XPClass $class) { // Description if (NULL !== ($comment= $class->getComment())) { self::$err->writeLine(self::textOf($comment)); self::$err->writeLine(str_repeat('=', 72)); } $extra= $details= $positional= array(); foreach ($class->getMethods() as $method) { if (!$method->hasAnnotation('arg')) continue; $arg= $method->getAnnotation('arg'); $name= strtolower(preg_replace('/^set/', '', $method->getName()));; $comment= self::textOf($method->getComment()); if (0 == $method->numParameters()) { $optional= TRUE; } else { list($first, )= $method->getParameters(); $optional= $first->isOptional(); } if (isset($arg['position'])) { $details['#'.($arg['position'] + 1)]= $comment; $positional[$arg['position']]= $name; } else if (isset($arg['name'])) { $details['--'.$arg['name'].' | -'.(isset($arg['short']) ? $arg['short'] : $arg['name']{0})]= $comment; $extra[$arg['name']]= $optional; } else { $details['--'.$name.' | -'.(isset($arg['short']) ? $arg['short'] : $name{0})]= $comment; $extra[$name]= $optional; } } // Usage asort($positional); self::$err->write('Usage: $ xpcli ', $class->getName(), ' '); foreach ($positional as $name) { self::$err->write('<', $name, '> '); } foreach ($extra as $name => $optional) { self::$err->write(($optional ? '[' : ''), '--', $name, ($optional ? '] ' : ' ')); } self::$err->writeLine(); // Argument details self::$err->writeLine('Arguments:'); foreach ($details as $which => $comment) { self::$err->writeLine('* ', $which, "\n ", $comment, "\n"); } } /** * Main method * * @param string[] args * @return int */ public static function main(array $args) { return create(new self())->run(new ParamString($args)); } /** * Reassigns standard output stream * * @param io.streams.OutputStream out * @return io.streams.OutputStream the given output stream */ public function setOut(OutputStream $out) { self::$out= new StringWriter($out); return $out; } /** * Reassigns standard error stream * * @param io.streams.OutputStream error * @return io.streams.OutputStream the given output stream */ public function setErr(OutputStream $err) { self::$err= new StringWriter($err); return $err; } /** * Main method * * @param util.cmd.ParamString params * @return int */ public function run(ParamString $params) { $pm= PropertyManager::getInstance(); // No arguments given - show our own usage if ($params->count < 1) { self::$err->writeLine(self::textOf(XPClass::forName(xp::nameOf(__CLASS__))->getComment())); return 1; } // Separate runner options from class options for ($offset= 0, $i= 0; $i < $params->count; $i++) { if ('-c' === $params->list[$i]) { $pm->configure($params->list[$i+ 1]); $offset+= 2; $i++; } else if ('-cp' === $params->list[$i]) { foreach (explode(PATH_SEPARATOR, $params->list[$i+ 1]) as $element) { ClassLoader::registerPath($element, FALSE); } $offset+= 2; $i++; } else { break; } } // Sanity check if (!$params->exists($offset)) { self::$err->writeLine('*** Missing classname'); return 1; } unset($params->list[-1]); $classname= $params->value($offset); $classparams= new ParamString(array_slice($params->list, $offset+ 1)); // Class file or class name if (strstr($classname, xp::CLASS_FILE_EXT)) { $file= new File($classname); if (!$file->exists()) { self::$err->writeLine('*** Cannot load class from non-existant file ', $classname); return 1; } $uri= $file->getURI(); $path= dirname($uri); $paths= array_flip(array_map('realpath', xp::$registry['classpath'])); $class= NULL; while (FALSE !== ($pos= strrpos($path, DIRECTORY_SEPARATOR))) { if (isset($paths[$path])) { $class= XPClass::forName(strtr(substr($uri, strlen($path)+ 1, -10), DIRECTORY_SEPARATOR, '.')); break; } $path= substr($path, 0, $pos); } if (!$class) { self::$err->writeLine('*** Cannot load class from ', $file); return 1; } } else { try { $class= XPClass::forName($classname); } catch (ClassNotFoundException $e) { self::$err->writeLine('*** ', $e->getMessage()); return 1; } } // Check whether class is runnable if (!$class->isSubclassOf('lang.Runnable')) { self::$err->writeLine('*** ', $class->getName(), ' is not runnable'); return 1; } // Usage if ($classparams->exists('help', '?')) { self::showUsage($class); return 0; } // Load, instantiate and initialize $l= Logger::getInstance(); $pm->hasProperties('log') && $l->configure($pm->getProperties('log')); $cm= ConnectionManager::getInstance(); $pm->hasProperties('database') && $cm->configure($pm->getProperties('database')); $instance= $class->newInstance(); $instance->out= self::$out; $instance->err= self::$err; foreach ($class->getMethods() as $method) { if ($method->hasAnnotation('inject')) { // Perform injection $inject= $method->getAnnotation('inject'); switch ($inject['type']) { case 'rdbms.DBConnection': { $args= array($cm->getByHost($inject['name'], 0)); break; } case 'util.Properties': { $args= array($pm->getProperties($inject['name'])); break; } case 'util.log.LogCategory': { $args= array($l->getCategory($inject['name'])); break; } default: { self::$err->writeLine('*** Unknown injection type "'.$inject['type'].'"'); return 2; } } try { $method->invoke($instance, $args); } catch (Throwable $e) { self::$err->writeLine('*** Error injecting '.$inject['name'].': '.$e->getMessage()); return 2; } } else if ($method->hasAnnotation('args')) { // Pass all arguments if (!$method->hasAnnotation('args', 'select')) { $pass= array_slice($classparams->list, 0, $classparams->count); } else { $pass= array(); foreach (preg_split('/, ?/', $method->getAnnotation('args', 'select')) as $def) { if (is_numeric($def) || '-' == $def{0}) { $pass[]= $classparams->value((int)$def); } else { sscanf($def, '[%d..%d]', $begin, $end); isset($begin) || $begin= 0; isset($end) || $end= $classparams->count- 1; while ($begin <= $end) { $pass[]= $classparams->value($begin++); } } } } try { $method->invoke($instance, array($pass)); } catch (Throwable $e) { self::$err->writeLine('*** Error for arguments '.$begin.'..'.$end.': '.$e->getMessage()); return 2; } } else if ($method->hasAnnotation('arg')) { // Pass arguments $arg= $method->getAnnotation('arg'); if (isset($arg['position'])) { $name= '#'.($arg['position']+ 1); $select= intval($arg['position']); $short= NULL; } else if (isset($arg['name'])) { $name= $select= $arg['name']; $short= isset($arg['short']) ? $arg['short'] : NULL; } else { $name= $select= strtolower(preg_replace('/^set/', '', $method->getName())); $short= isset($arg['short']) ? $arg['short'] : NULL; } if (0 == $method->numParameters()) { if (!$classparams->exists($select, $short)) continue; $args= array(); } else if (!$classparams->exists($select, $short)) { list($first, )= $method->getParameters(); if (!$first->isOptional()) { self::$err->writeLine('*** Argument '.$name.' does not exist!'); return 2; } $args= array(); } else { $args= array($classparams->value($select, $short)); } try { $method->invoke($instance, $args); } catch (TargetInvocationException $e) { self::$err->writeLine('*** Error for argument '.$name.': '.$e->getCause()->compoundMessage()); return 2; } } } try { $instance->run(); } catch (Throwable $t) { self::$err->writeLine('*** ', $t->compoundMessage()); return 70; // EX_SOFTWARE according to sysexits.h } return 0; } } ?> * $sp= new SingleProcess(); * if (!$sp->lock()) { * exit(-1); * } * * // [...operation which should only take part once at a time...] * * $sp->unlock(); * * * @purpose Lock process so it can only be run once */ class SingleProcess extends Object { public $lockfile = NULL; /** * Constructor * * @param string lockfileName default NULL the lockfile's name, * defaulting to <>.lck */ public function __construct($lockFileName= NULL) { if (NULL === $lockFileName) $lockFileName= $_SERVER['argv'][0].'.lck'; $this->lockfile= new File($lockFileName); } /** * Lock this application * * @return bool success */ public function lock() { try { $this->lockfile->open(FILE_MODE_WRITE); $this->lockfile->lockExclusive(); } catch (IOException $e) { $this->lockfile->close(); return FALSE; } return TRUE; } /** * Unlock the application * * @return bool Success */ public function unlock() { if ($this->lockfile->unlock()) { $this->lockfile->close(); $this->lockfile->unlink(); return TRUE; } return FALSE; } } ?> addAll($array->values); return $v; } /** * Sorts an array * * @see php://sort * @param lang.types.ArrayList array * @param * method */ public static function sort(ArrayList $array, $method= SORT_REGULAR) { if ($method instanceof Comparator) { usort($array->values, array($method, 'compare')); } else { sort($array->values, $method); } } /** * Returns a sorted array * * @see php://sort * @param lang.types.ArrayList array * @param * method * @return lang.types.ArrayList the sorted array */ public static function sorted(ArrayList $array, $method= SORT_REGULAR) { $copy= clone $array; if ($method instanceof Comparator) { usort($copy->values, array($method, 'compare')); } else { sort($copy->values, $method); } return $copy; } /** * Checks whether a certain value is contained in an array * * @param lang.types.ArrayList array * @param * search * @return bool */ public static function contains(ArrayList $array, $search) { if ($search instanceof Generic) { foreach ($array->values as $value) { if ($search->equals($value)) return TRUE; } } else { foreach ($array->values as $value) { if ($search === $value) return TRUE; } } return FALSE; } } ?> = 8; $len-= 8) { $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); $hash= (($hash << 5) + $hash) + ord($str{$offset++}); } switch ($len) { case 7: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); case 6: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); case 5: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); case 4: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); case 3: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); case 2: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); case 1: $hash= (($hash << 5) + $hash) + ord($str{$offset++}); } return $hash; } } ?> * $hashCode= HashProvider::hashOf($string); * * * Uses MD5 as default hashing implementation. To change the hashing * implementation to be used, use the following: * * HashProvider::getInstance()->setImplementation(new MyHashImplementation()); * * * @see xp://util.collections.DJBX33AHashImplementation * @see xp://util.collections.MD5HashImplementation * @see xp://util.collections.Map * @purpose Hashing */ class HashProvider extends Object { protected static $instance = NULL; public $impl = NULL; static function __static() { self::$instance= new self(); self::$instance->setImplementation(new MD5HashImplementation()); } /** * Constructor * */ protected function __construct() { } /** * Retrieve sole instance of this object * * @return util.collections.HashProvider */ public static function getInstance() { return self::$instance; } /** * Returns hash for a given string * * @param string str * @return int */ public static function hashOf($str) { return self::getInstance()->impl->hashOf($str); } /** * Set hashing implementation * * @param util.collections.HashImplementation impl * @throws lang.IllegalArgumentException when impl is not a HashImplementation */ public function setImplementation(HashImplementation $impl) { $this->impl= $impl; } /** * Get hashing implementation * * @return util.collections.HashImplementation */ public function getImplementation() { return $this->impl; } } ?> v= $v; return $self; } public function current() { return current($this->v); } public function key() { return $this->i; } public function next() { next($this->v); $this->i++; } public function rewind() { reset($this->v); $this->i= 0; } public function valid() { return $this->i < sizeof($this->v); } }'); } /** * Returns an iterator for use in foreach() * * @see php://language.oop5.iterations * @return php.Iterator */ public function getIterator() { return self::$iterate->on($this->_elements); } /** * = list[] overloading * * @param int offset * @return lang.Generic */ public function offsetGet($offset) { throw new IllegalArgumentException('Unsupported operation'); } /** * list[]= overloading * * @param int offset * @param mixed value * @throws lang.IllegalArgumentException if key is neither numeric (set) nor NULL (add) */ public function offsetSet($offset, $value) { if (NULL === $offset) { $this->add($value); } else { throw new IllegalArgumentException('Unsupported operation'); } } /** * isset() overloading * * @param int offset * @return bool */ public function offsetExists($offset) { return $this->contains($offset); } /** * unset() overloading * * @param int offset */ public function offsetUnset($offset) { $this->remove($offset); } /** * Adds an object * * @param lang.Generic object * @return bool TRUE if this set did not already contain the specified element. */ public function add(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } $h= $object->hashCode(); if (isset($this->_elements[$h])) return FALSE; $this->_hash+= HashProvider::hashOf($h); $this->_elements[$h]= $object; return TRUE; } /** * Removes an object from this set * * @param lang.Generic object * @return bool TRUE if this set contained the specified element. */ public function remove(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } $h= $object->hashCode(); if (!isset($this->_elements[$h])) return FALSE; $this->_hash-= HashProvider::hashOf($h); unset($this->_elements[$h]); return TRUE; } /** * Removes an object from this set * * @param lang.Generic object * @return bool TRUE if the set contains the specified element. */ public function contains(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } return isset($this->_elements[$object->hashCode()]); } /** * Returns this set's size * * @return int */ public function size() { return sizeof($this->_elements); } /** * Removes all of the elements from this set * */ public function clear() { $this->_elements= array(); $this->_hash= 0; } /** * Returns whether this set is empty * * @return bool */ public function isEmpty() { return 0 == sizeof($this->_elements); } /** * Adds an array of objects * * @param lang.Generic[] objects * @return bool TRUE if this set changed as a result of the call. */ public function addAll($objects) { $result= FALSE; $hash= $this->_hash; $elements= $this->_elements; for ($i= 0, $s= sizeof($objects); $i < $s; $i++) { if ($this->__generic && !$objects[$i] instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object #'.$i.' '.xp::stringOf($objects[$i]).' must be of '.$this->__generic[0]); } $h= $objects[$i]->hashCode(); if (isset($this->_elements[$h])) continue; $result= TRUE; $hash+= HashProvider::hashOf($h); $elements[$h]= $objects[$i]; } $this->_hash= $hash; $this->_elements= $elements; return $result; } /** * Returns an array containing all of the elements in this set. * * @return lang.Generic[] objects */ public function toArray() { return array_values($this->_elements); } /** * Returns a hashcode for this set * * @return string */ public function hashCode() { return $this->_hash; } /** * Returns true if this set equals another set. * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->hashCode() === $cmp->hashCode(); } /** * Returns a string representation of this set * * @return string */ public function toString() { $s= $this->getClassName().'['.sizeof($this->_elements).'] {'; if (0 == sizeof($this->_elements)) return $s.' }'; $s.= "\n"; foreach (array_keys($this->_elements) as $key) { $s.= ' '.$this->_elements[$key]->toString().",\n"; } return substr($s, 0, -2)."\n}"; } } ?> get($offset); } /** * list[]= overloading * * @param lang.Generic offset * @param lang.Generic value */ public function offsetSet($offset, $value) { $this->put($offset, $value); } /** * isset() overloading * * @param lang.Generic offset * @return bool */ public function offsetExists($offset) { return $this->containsKey($offset); } /** * unset() overloading * * @param lang.Generic offset */ public function offsetUnset($offset) { $this->remove($offset); } /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for this key, the old * value is replaced by the specified value. * Returns previous value associated with specified key, or NULL if * there was no mapping for the specified key. * * @param lang.Generic key * @param lang.Generic value * @return lang.Generic the previous value associated with the key */ public function put($key, Generic $value) { $k= Primitive::boxed($key); if ($this->__generic) { if (!$k instanceof $this->__generic[0]) { throw new IllegalArgumentException('Key '.xp::stringOf($k).' must be of '.$this->__generic[0]); } else if (!$value instanceof $this->__generic[1]) { throw new IllegalArgumentException('Value '.xp::stringOf($value).' must be of '.$this->__generic[1]); } } $h= $k->hashCode(); if (!isset($this->_buckets[$h])) { $previous= NULL; } else { $previous= $this->_buckets[$h][1]; } $this->_buckets[$h]= array($k, $value); $this->_hash+= HashProvider::hashOf($h.$value->hashCode()); return $previous; } /** * Returns the value to which this map maps the specified key. * Returns NULL if the map contains no mapping for this key. * * @param lang.Generic key * @return lang.Generic the value associated with the key */ public function get($key) { $k= Primitive::boxed($key); if ($this->__generic) { if (!$k instanceof $this->__generic[0]) { throw new IllegalArgumentException('Key '.xp::stringOf($k).' must be of '.$this->__generic[0]); } } $h= $k->hashCode(); if (!isset($this->_buckets[$h])) return NULL; return $this->_buckets[$h][1]; } /** * Removes the mapping for this key from this map if it is present. * Returns the value to which the map previously associated the key, * or null if the map contained no mapping for this key. * * @param lang.Generic key * @return lang.Generic the previous value associated with the key */ public function remove($key) { $k= Primitive::boxed($key); if ($this->__generic) { if (!$k instanceof $this->__generic[0]) { throw new IllegalArgumentException('Key '.xp::stringOf($k).' must be of '.$this->__generic[0]); } } $h= $k->hashCode(); if (!isset($this->_buckets[$h])) { $previous= NULL; } else { $previous= $this->_buckets[$h][1]; $this->_hash-= HashProvider::hashOf($h.$previous->hashCode()); unset($this->_buckets[$h]); } return $previous; } /** * Removes all mappings from this map. * */ public function clear() { $this->_buckets= array(); $this->_hash= 0; } /** * Returns the number of key-value mappings in this map * */ public function size() { return sizeof($this->_buckets); } /** * Returns true if this map contains no key-value mappings. * */ public function isEmpty() { return empty($this->_buckets); } /** * Returns true if this map contains a mapping for the specified key. * * @param lang.Generic key * @return bool */ public function containsKey($key) { $k= Primitive::boxed($key); if ($this->__generic) { if (!$k instanceof $this->__generic[0]) { throw new IllegalArgumentException('Key '.xp::stringOf($k).' must be of '.$this->__generic[0]); } } return isset($this->_buckets[$k->hashCode()]); } /** * Returns true if this map maps one or more keys to the specified value. * * @param lang.Generic value * @return bool */ public function containsValue(Generic $value) { if ($this->__generic) { if (!$value instanceof $this->__generic[1]) { throw new IllegalArgumentException('Value '.xp::stringOf($value).' must be of '.$this->__generic[1]); } } foreach (array_keys($this->_buckets) as $key) { if ($this->_buckets[$key][1]->equals($value)) return TRUE; } return FALSE; } /** * Returns a hashcode for this map * * @return string */ public function hashCode() { return $this->_hash; } /** * Returns true if this map equals another map. * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return ( ($cmp instanceof Map) && ($this->hashCode() === $cmp->hashCode()) ); } /** * Returns an array of keys * * @return lang.Generic[] */ public function keys() { $keys= array(); foreach (array_keys($this->_buckets) as $key) { $keys[]= $this->_buckets[$key][0]; } return $keys; } /** * Returns a string representation of this map * * @return string */ public function toString() { $s= $this->getClassName().'['.sizeof($this->_buckets).'] {'; if (0 == sizeof($this->_buckets)) return $s.' }'; $s.= "\n"; foreach (array_keys($this->_buckets) as $key) { $s.= ' '.$this->_buckets[$key][0]->toString().' => '.$this->_buckets[$key][1]->toString().",\n"; } return substr($s, 0, -2)."\n}"; } } ?> setSize($size); } /** * Add an element to the buffer and return the id of the element * which has been deleted in exchange. Returns NULL for the case * that no element has been deleted (which is the case when the * buffer's size has not yet been exceeded). * * * $deleted= $buf->add($key); * * * @param lang.Generic element * @return lang.Generic victim */ public function add(Generic $element) { if ($this->__generic && !$element instanceof $this->__generic[0]) { throw new IllegalArgumentException('Element '.xp::stringOf($element).' must be of '.$this->__generic[0]); } $h= $element->hashCode(); $this->_access[$h]= microtime(TRUE); $this->_elements[$h]= $element; // Check if this buffer's size has been exceeded if (sizeof($this->_access) <= $this->size) return NULL; // Find the position of the smallest value and delete it $p= array_search(min($this->_access), $this->_access, TRUE); $victim= $this->_elements[$p]; unset($this->_access[$p]); unset($this->_elements[$p]); return $victim; } /** * Update an element * * @param lang.Generic element */ public function update(Generic $element) { if ($this->__generic && !$element instanceof $this->__generic[0]) { throw new IllegalArgumentException('Element '.xp::stringOf($element).' must be of '.$this->__generic[0]); } $this->_access[$element->hashCode()]= microtime(TRUE); } /** * Get number of elements currently contained in this buffer * * @return int */ public function numElements() { return sizeof($this->_access); } /** * Set size * * @param int size * @throws lang.IllegalArgumentException is size is not greater than zero */ public function setSize($size) { if ($size <= 0) throw new IllegalArgumentException( 'Size must be greater than zero, '.$size.' given' ); $this->size= $size; } /** * Get size * * @return int */ public function getSize() { return $this->size; } } ?> * $ht= new HashTable(); * $hg= create('new HashTable()'); * * with ($key= new Integer(1); $value= new String('one')); { * $ht->put($key, $value); // OK * $hg->put($key, $value); // *** IllegalArgumentException, key not a string! * } * * * Overloading * =========== * The util.collections classes overload array access where applicable: * * * $h= new HashTable(); * $h['hello']= new Greeting('Hello'); * * $v= create('new Vector()'); * $v[]= new Greeting('Hallo'); * $v[]= new Greeting('Servus'); * $v[]= new Greeting('Grezi'); * * Console::writeLine('Hello in German: ', $v[0]); * * * @see xp://lang.types.ArrayList * @see http://developer.xp-framework.net/xml/rfc/view?0106 * @see http://news.xp-framework.net/article/180/2007/04/29/ * @purpose Colllections */ package util.collections { } * uses('util.collections.Queue', 'text.String'); * * // Fill queue * with ($q= new Queue()); { * $q->put(new String('One')); * $q->put(new String('Two')); * $q->put(new String('Three')); * $q->put(new String('Four')); * } * * // Empty queue * while (!$q->isEmpty()) { * var_dump($q->get()); * } * * * @purpose FIFO * @see xp://util.collections.Stack * @see http://www.faqs.org/docs/javap/c12/ex-12-1-answer.html */ class Queue extends Object { protected $_elements = array(), $_hash = 0; public $__generic = array(); /** * Puts an item into the queue. Returns the element that was added. * * @param lang.Generic object * @return lang.Generic object */ public function put(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } $this->_elements[]= $object; $this->_hash+= HashProvider::hashOf($object->hashCode()); return $object; } /** * Gets an item from the front of the queue. * * @return lang.Generic * @throws util.NoSuchElementException */ public function get() { if (empty($this->_elements)) { throw new NoSuchElementException('Queue is empty'); } $e= $this->_elements[0]; $this->_hash-= HashProvider::hashOf($e->hashCode()); $this->_elements= array_slice($this->_elements, 1); return $e; } /** * Peeks at the front of the queue (retrieves the first element * without removing it). * * Returns NULL in case the queue is empty. * * @return lang.Generic object */ public function peek() { if (empty($this->_elements)) return NULL; else return $this->_elements[0]; } /** * Returns true if the queue is empty. This is effectively the same * as testing size() for 0. * * @return bool */ public function isEmpty() { return empty($this->_elements); } /** * Returns the size of the queue. * * @return int */ public function size() { return sizeof($this->_elements); } /** * Sees if an object is in the queue and returns its position. * Returns -1 if the object is not found. * * @param lang.Generic object * @return int position */ public function search(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } return ($keys= array_keys($this->_elements, $object)) ? $keys[0] : -1; } /** * Remove an object from the queue. Returns TRUE in case the element * was deleted, FALSE otherwise. * * @return lang.Generic * @return bool */ public function remove(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } if (-1 == ($pos= $this->search($object))) return FALSE; $this->_hash-= HashProvider::hashOf($this->_elements[$pos]->hashCode()); unset($this->_elements[$pos]); $this->_elements= array_values($this->_elements); // Re-index return TRUE; } /** * Retrieves an element by its index. * * @param int index * @return lang.Generic * @throws lang.IndexOutOfBoundsException */ public function elementAt($index) { if (!isset($this->_elements[$index])) { throw(new IndexOutOfBoundsException('Index '.$index.' out of bounds')); } return $this->_elements[$index]; } /** * Returns a hashcode for this queue * * @return string */ public function hashCode() { return $this->_hash; } /** * Returns true if this queue equals another queue. * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return ( is('util.collections.Queue', $cmp) && ($this->hashCode() === $cmp->hashCode()) ); } } ?> * uses('util.collections.Stack', 'text.String'); * * // Fill stack * with ($s= new Stack()); { * $s->push(new String('One')); * $s->push(new String('Two')); * $s->push(new String('Three')); * $s->push(new String('Four')); * } * * // Empty stack * while (!$s->isEmpty()) { * var_dump($s->pop()); * } * * * @purpose LIFO * @see xp://util.collections.Queue * @see http://www.faqs.org/docs/javap/c12/ex-12-1-answer.html * @see http://java.sun.com/j2se/1.4.2/docs/api/java/util/Stack.html */ class Stack extends Object { protected $_elements = array(), $_hash = 0; public $__generic = array(); /** * Pushes an item onto the top of the stack. Returns the element that * was added. * * @param lang.Generic object * @return lang.Generic object */ public function push(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } array_unshift($this->_elements, $object); $this->_hash+= HashProvider::hashOf($object->hashCode()); return $object; } /** * Gets an item from the top of the stack * * @return lang.Generic * @throws util.NoSuchElementException */ public function pop() { if (empty($this->_elements)) { throw(new NoSuchElementException('Stack is empty')); } $element= array_shift($this->_elements); $this->_hash+= HashProvider::hashOf($element->hashCode()); return $element; } /** * Peeks at the front of the stack (retrieves the first element * without removing it). * * Returns NULL in case the stack is empty. * * @return lang.Generic object */ public function peek() { if (empty($this->_elements)) return NULL; else return $this->_elements[0]; } /** * Returns true if the stack is empty. This is effectively the same * as testing size() for 0. * * @return bool */ public function isEmpty() { return empty($this->_elements); } /** * Returns the size of the stack. * * @return int */ public function size() { return sizeof($this->_elements); } /** * Sees if an object is in the stack and returns its position. * Returns -1 if the object is not found. * * @param lang.Generic object * @return int position */ public function search(Generic $object) { if ($this->__generic && !$object instanceof $this->__generic[0]) { throw new IllegalArgumentException('Object '.xp::stringOf($object).' must be of '.$this->__generic[0]); } return ($keys= array_keys($this->_elements, $object)) ? $keys[0] : -1; } /** * Retrieves an element by its index. * * @param int index * @return lang.Generic * @throws lang.IndexOutOfBoundsException */ public function elementAt($index) { if (!isset($this->_elements[$index])) { throw(new IndexOutOfBoundsException('Index '.$index.' out of bounds')); } return $this->_elements[$index]; } /** * Returns a hashcode for this queue * * @return string */ public function hashCode() { return $this->_hash; } /** * Returns true if this queue equals another queue. * * @param lang.Generic cmp * @return bool */ public function equals($cmp) { return $cmp instanceof self && $this->hashCode() === $cmp->hashCode(); } } ?> v= $v; return $self; } public function current() { return $this->v[$this->i]; } public function key() { return $this->i; } public function next() { $this->i++; } public function rewind() { $this->i= 0; } public function valid() { return $this->i < sizeof($this->v); } }'); } /** * Constructor * * @param lang.Generic[] elements default array() */ public function __construct(array $elements= array()) { foreach ($elements as $element) { if ($this->__generic) { if (!$element instanceof $this->__generic[0]) { throw new IllegalArgumentException('Element '.xp::stringOf($element).' must be of '.$this->__generic[0]); } } $th